约瑟夫环随机洗牌

//今天做作业时,想着可不可以用一个随机数(整数)对一副扑克牌进行随机洗牌,发现当数据排成一个环时,使用可以实现,于是想到了约瑟夫环
//注:java,代码完全由kimi生成
package task004;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

public class RealRandNum {
// 修复:去掉 URL 末尾的空格
private static final String API_URL =
"https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new";

public static void main(String[] args) throws Exception {
    // 1. 获取真随机数作为约瑟夫环的步长
    int step = fetchRandomNumber();
    System.out.println("随机步长: " + step);

    // 2. 初始化54张扑克牌 (0-53,可映射到 红桃A-K,方块A-K,黑桃A-K,梅花A-K,大小王)
    List<Integer> deck = new ArrayList<>();
    for (int i = 0; i < 54; i++) {
        deck.add(i);
    }
    System.out.println("原始牌序: " + deck);

    // 3. 使用约瑟夫环算法打乱
    List<Integer> shuffled = josephusShuffle(deck, step);
    System.out.println("约瑟夫环打乱后: " + shuffled);

    // 4. 映射为扑克牌名称(可选)
    printPokerNames(shuffled);
}

// 获取随机数(修复异步赋值问题)
private static int fetchRandomNumber() throws Exception {
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(API_URL))
            .header("User-Agent", "Java TrueRandom Client")
            .GET()
            .build();

    CompletableFuture<HttpResponse<String>> future =
            client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

    // 修复:使用 AtomicReference 包装,解决 Lambda 中赋值问题
    AtomicReference<String> resultRef = new AtomicReference<>();
    future.thenAccept(response -> {
        resultRef.set(response.body().trim());
    }).join();

    return Integer.parseInt(resultRef.get());
}

/**
 * 约瑟夫环洗牌算法
 * @param deck 初始牌组
 * @param step 步长(每次数 step 张牌,第 step 张出列)
 * @return 打乱后的牌序(出列顺序)
 */
private static List<Integer> josephusShuffle(List<Integer> deck, int step) {
    List<Integer> result = new ArrayList<>();
    List<Integer> temp = new ArrayList<>(deck); // 工作副本
    int index = 0;

    while (!temp.isEmpty()) {
        // 计算下一个要移除的位置:(当前索引 + 步长 - 1) % 剩余数量
        index = (index + step - 1) % temp.size();

        // 移除该位置的牌,加入结果
        result.add(temp.remove(index));

        // 注意:remove 后,index 位置自动被后续元素填补
        // 下一轮从当前 index 开始计数(如果从0开始需要调整,但这里 index 已经指向下一个元素)
        // 如果 index == temp.size(),说明刚好在末尾,下一轮回到0
    }

    return result;
}

// 将数字映射为扑克牌名称(0-51为52张牌,52小王,53大王)
private static void printPokerNames(List<Integer> shuffled) {
    String[] suits = {"♥", "♦", "♠", "♣"};
    String[] ranks = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};

    System.out.println("扑克牌映射:");
    for (int i = 0; i < shuffled.size(); i++) {
        int card = shuffled.get(i);
        String name;
        if (card == 52) name = "小王";
        else if (card == 53) name = "大王";
        else {
            name = suits[card / 13] + ranks[card % 13];
        }
        System.out.printf("第%2d张: %s%n", i + 1, name);
    }
}

}

posted @ 2026-04-14 23:14  ainey  阅读(3)  评论(0)    收藏  举报