最少次数结束游戏
测试下来, 一副牌两个人玩小猫钓鱼, 目前最少出牌次数是 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即可.
- 想通过随机发牌的方式获取最少轮数, 不太现实, 基数太大了.