卡牌游戏小猫钓鱼

最少次数结束游戏

测试下来, 一副牌两个人玩小猫钓鱼, 目前最少出牌次数是 55 次

==================开始==================
玩家A: [6, A, 7, 2, x, q, 8,  5, 6, 4, 8, x, q,     2, 7, 4, 8, x, q,     3, 8, x, q,   2, 4, 5] <-
玩家B: [3, 5, 4, 9, j, k, 6,  3, 7, A, 9, j, k, 3,  A, 5, 6, 9, j, k, 2,  7, 9, j, k, A]

永远结束不了的出牌

==================开始==================
玩家A: [1, 1, 2, 2] <-
玩家B: [1, 1, 2, 2]
桌面 : []

代码

@Test
    public void test0211() {
        for (int i=0; i<10000000; i++) {
            testCatFishing(59);
        }
    }

    //@Test
    public void testCatFishing(int limit) {
        String[] poker = new String[]{"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
                "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
                "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
                "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};

        /*String[] poker = new String[]{"A", "2", "3", "4", "5",
                "A", "2", "3", "4", "5"};*/

        // 桌子上的扑克
        Stack<String> desk = new Stack<>();
        // 桌子上的扑克对应的下标
        Map<String, Integer> deskMap = new HashMap<>();

        // 复制一份扑克
        String[] poker2 = new String[poker.length];
        for (int i=0; i<poker.length; i++) {
            poker2[i] = poker[i];
        }

        // 玩家A手中的扑克
        Queue<String> playerA = new LinkedList<>();
        // 玩家B手中的扑克
        Queue<String> playerB = new LinkedList<>();

        // 随机分发扑克, 每人26张
        Random random = new Random();
        while (playerA.size() < poker.length / 2) {

            int index = random.nextInt(poker.length);
            while (StringUtils.isBlank(poker2[index])) {
                index = random.nextInt(poker.length);
            }

            playerA.add(poker2[index]);
            poker2[index] = "";
        }

        for (int i=0; i<poker.length; i++) {
            if (StringUtils.isNotBlank(poker2[i])) {
                playerB.add(poker2[i]);
            }
        }

        // 复制一份分发扑克的结果, 用于结尾打印
        Queue<String> playerA2 = new LinkedList<>(playerA);
        Queue<String> playerB2 = new LinkedList<>(playerB);

        // 桌子上的扑克的下标
        int index = 0;
        // 轮到谁出牌
        boolean pollA = true;
        boolean pollB = false;

        // 统计出牌总次数
        int count = 1;

        while (playerA.size() > 0 && playerB.size() > 0) {
            if (pollA) {
                String card = playerA.poll();

                // 如果桌子上含有当前牌, 则收牌
                if (deskMap.containsKey(card)) {
                    int cardIndex = deskMap.get(card);

                    // 需要收的牌
                    Stack<String> winCards = new Stack<>();
                    for (int i=cardIndex; i<index; i++) {
                        String card2 = desk.pop();
                        winCards.add(card2);
                        deskMap.remove(card2);
                    }

                    // 将收来的牌放到玩家A手牌的最后
                    for (int i=cardIndex; i<index; i++) {
                        playerA.add(winCards.pop());
                    }
                    playerA.add(card);

                    // 更新桌子上卡牌的下标
                    index = cardIndex;
                } else {
                    // 没有牌可收
                    desk.add(card);
                    deskMap.put(card, index++);
                    pollA = false;
                    pollB = true;
                }


                /*System.out.println("==================第" + count + "轮==================");
                System.out.print("玩家A: " + playerA.toString());
                if (pollA) {
                    System.out.println(" <-");
                } else {
                    System.out.println();
                }

                System.out.print("玩家B: " + playerB.toString());
                if (pollB) {
                    System.out.println(" <-");
                } else {
                    System.out.println();
                }

                System.out.println("桌面 : " + desk.toString());
                System.out.println();*/
                count++;
            }

            if (pollB) {
                String card = playerB.poll();

                if (deskMap.containsKey(card)) {
                    int cardIndex = deskMap.get(card);

                    Stack<String> winCards = new Stack<>();
                    for (int i=cardIndex; i<index; i++) {
                        String card2 = desk.pop();
                        winCards.add(card2);
                        deskMap.remove(card2);
                    }

                    for (int i=cardIndex; i<index; i++) {
                        playerB.add(winCards.pop());
                    }
                    playerB.add(card);
                    index = cardIndex;
                } else {
                    desk.add(card);
                    deskMap.put(card, index++);
                    pollB = false;
                    pollA = true;
                }


                /*System.out.println("==================第" + count + "轮==================");
                System.out.print("玩家A: " + playerA.toString());
                if (pollA) {
                    System.out.println(" <-");
                } else {
                    System.out.println();
                }

                System.out.print("玩家B: " + playerB.toString());
                if (pollB) {
                    System.out.println(" <-");
                } else {
                    System.out.println();
                }

                System.out.println("桌面 : " + desk.toString());
                System.out.println();*/
                count++;
            }

        }

        if (count < limit) {
            System.out.println("==================开始==================");
            System.out.println("玩家A: " + playerA2.toString() + " <-");
            System.out.println("玩家B: " + playerB2.toString());
            System.out.println("桌面 : " + desk.toString());

            System.out.println("==================结束==================");
            System.out.println("玩家A: " + playerA.toString());
            System.out.println("玩家B: " + playerB.toString());
            System.out.println("桌面 : " + desk.toString());
            System.out.println("轮次 : " + count);

            System.out.println();
        }
    }

统计结果

4*(n张不同卡牌)  小猫钓鱼最少次数
4*13 55
玩家A: [6, A, 7, 2, x, q, 8,  5, 6, 4, 8, x, q,     2, 7, 4, 8, x, q,     3, 8, x, q,   2, 4, 5] <-
玩家B: [3, 5, 4, 9, j, k, 6,  3, 7, A, 9, j, k, 3,  A, 5, 6, 9, j, k, 2,  7, 9, j, k, A]


4*11 47
玩家A: [6, A, 7, 2, x, 8,  5, 6, 4, 8, x,     2, 7, 4, 8, x,     3, 8, x,   2, 4, 5] <-
玩家B: [3, 5, 4, 9, j, 6,  3, 7, A, 9, j, 3,  A, 5, 6, 9, j, 2,  7, 9, j, A]


4*10 42
玩家A: [1, 3, 5, 7, 9,  1, 3, 5, 7, 9,     1, 4, 6, 8, x,     x, 3, 4, 8, 9] <-
玩家B: [2, 4, 6, 8, 1,  x, 2, 4, 6, 8, x,  2, 3, 5, 7, 9, 2,  5, 6, 7]


4*9 39
玩家A: [6, A, 7, 2, 8,  5, 6, 4, 8,     2, 7, 4, 8,     3, 8,  2, 4, 5] <-
玩家B: [3, 5, 4, 9, 6,  3, 7, A, 9, 3,  A, 5, 6, 9, 2,  7, 9, A]


4*8 34
玩家A: [7, 6, 4, 2,  6, 5, 7, 4,     7, 3, 6, 8,     8, 5, 2, 6] <-
玩家B: [A, 5, 3, 7,  8, 3, A, 2, 8,  A, 4, 2, 5, A,  3, 4]


4*7 31
玩家A: [6, A, 7, 2,  5, 6, 4,     2, 7, 4,     3,   2, 4, 5] <-
玩家B: [3, 5, 4, 6,  3, 7, A, 3,  A, 5, 6, 2,  7, A]


4*6 26
玩家A: [A, 3, 4,  4, 2, A,     6, 4, 5,     2, 3, 4] <-
玩家B: [5, 6, A,  5, 3, 6, 5,  2, A, 3, 2,  6]


4*5 23
玩家A: [2, 5, 3,  2, A,     5, 2,     4, 5,  A] <-
玩家B: [A, 4, 2,  4, 3, 4,  A, 3, 5,  3]


4*4 18
A2A24242
3A4343A3


4*3 15
A22333
3AAA22


4*2 10


2*7 14
2*6 13
2*5 10
2*4 9
2*3 6
2*2 5

总结

  • 对于 4*(n张不同卡牌), n 如果为偶数, 那么最少次数是 4*n+2, 卡牌分布规律为玩家A和玩家B手中卡牌分为4个部分(n, n+1, n+1, n-2), 前三部分都被玩家B全部收取, 最后一部分没人收取, 玩家A没有卡牌, 游戏结束;
  • 如果 n 为奇数, 那么最少次数是 4*n+3, 卡牌的分布规律为玩家A和玩家B手中卡牌分为5个部分(n+1, n, n, n-4, 3), 前两部分都被玩家B全部收取, 第三部分留一张牌, 第四部分被玩家B全部收取, 第五部分没人收取, 玩家A没有卡牌, 游戏结束.
  • 如果想知道 4* 15 张不同卡牌最少轮数的分牌方式, 只要在前四部分的最后都插入13, 14即可.
  • 想通过随机发牌的方式获取最少轮数, 不太现实, 基数太大了.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值