问题描述:
假设有A和B来两个人玩牌。游戏的规则是这样的:将一副牌均分成两份,每人拿一份。A先拿出手中的第一张扑克牌,放在桌上,然后B也拿出手中的第一张扑克牌,放在A刚打出来的扑克牌的上面,就这样两人交替出牌。出牌时,如果某人打出的牌与桌上的某张牌的牌面相同,即可将两种牌以及其中间的所有牌全部取走,并按照从上到下的顺序依次放到自己手中牌的末尾。当任意一人手中的牌全部取完时,游戏结束,对手获胜。 先假设A手上有牌,按顺序依次为:2 4 1 2 5 6,B手上有牌顺序为:3 1 3 5 6 4。写程序判断谁会赢。
这个问题其实就是考察对栈和队列两种数据结构的应用。代码如下:
1 package com.rampage.algorithm.base; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Stack; 6 7 /** 8 * 9 * @author zyq 10 * 11 */ 12 public class PokerGame1 { 13 14 public static void main(String[] args) { 15 16 int[] arr1 = { 2, 4, 1, 2, 5, 6 }; int[] arr2 = { 3, 1, 3, 5, 6, 4 }; 17 18 19 // 这个是一个永远不会结束的循环 20 /*int[] arr1 = { 1, 1, 1 }; 21 int[] arr2 = { 1, 2, 1 };*/ 22 PokerGame1 game = new PokerGame1(); 23 game.play(arr1, arr2); 24 } 25 26 /** 27 * 28 * @param arr1 29 * @param arr2 30 */ 31 private void play(int[] arr1, int[] arr2) { 32 if (arr1 == null || arr2 == null || arr1.length == 0 || arr2.length == 0 || arr1.length != arr2.length) { 33 System.out.println("Illegal card array for game!"); 34 return; 35 } 36 37 /** 38 * 其实这道题的考查重点就在于栈和列表两种数据结构的考查,我们用栈来表示桌面上的牌(因为桌面上的牌放上去和取走的时候符合栈的特性)。用队列(queue,java中用List即可)来表示 39 * 存储每个人手中的牌。 40 */ 41 List<Integer> list1 = new ArrayList<Integer>(arr1.length); 42 List<Integer> list2 = new ArrayList<Integer>(arr2.length); 43 Stack<Integer> stack = new Stack<Integer>(); // 存储桌面上的牌 44 45 // 首先将数组中的牌入列表 46 for (int i = 0; i < arr1.length; i++) { 47 list1.add(arr1[i]); 48 list2.add(arr2[i]); 49 } 50 51 int turnCount = 0; 52 // 当两个人手上的牌都不为空的时候,模拟出牌过程 53 54 // 还有一种可能就是会无限循环下去,对于这种情况其实发现到后面就是两者之间的牌会又回到最初的状态。 55 // 所以这里给两个列表来存储最开始时的牌的状态,如果后续发现又变成一样,则证明会出现无限循环。 56 List<Integer> originalList1 = new ArrayList<Integer>(list1); 57 List<Integer> originalList2 = new ArrayList<Integer>(list2); 58 59 while (list1.size() > 0 && list2.size() > 0) { 60 // 首先A出牌 61 int element = list1.remove(0); 62 63 // 如果栈中已经有可收回的牌,则收回栈中的牌并且放到A中牌的末尾 64 if (stack.contains(element)) { 65 list1.add(element); 66 int popOne; 67 while ((popOne = stack.pop()) != element) { 68 list1.add(popOne); 69 } 70 list1.add(popOne); 71 } else { 72 stack.push(element); 73 // 如果没有可以收回的牌,则判断当前A中的牌是否为空。 74 if (list1.size() == 0) { 75 break; 76 } 77 } 78 79 // 然后B出牌 80 element = list2.remove(0); 81 82 // 如果栈中已经有可收回的牌,则收回栈中的牌并且放到B中牌的末尾 83 if (stack.contains(element)) { 84 list2.add(element); 85 int popOne; 86 while ((popOne = stack.pop()) != element) { 87 list2.add(popOne); 88 } 89 list2.add(popOne); 90 } else { 91 stack.push(element); 92 // 如果没有可以收回的牌,则判断当前B中的牌是否为空。 93 if (list2.size() == 0) { 94 break; 95 } 96 } 97 98 System.out.println("Turn " + (++turnCount) + " result:"); 99 System.out.print("Player A:"); 100 for (int one : list1) { 101 System.out.print(one + ", "); 102 } 103 System.out.print("\nPlayer B:"); 104 for (int one : list2) { 105 System.out.print(one + ", "); 106 } 107 System.out.print("\nDesk:"); 108 for (int i = stack.size() - 1; i >= 0; i--) { 109 System.out.print(stack.elementAt(i) + ", "); 110 } 111 System.out.println("\n"); 112 113 // 当桌上没牌的时候,判断牌的状态是否又回到最初。 114 if (stack.isEmpty()) { 115 if ((originalList1.size() == list1.size() && originalList1.containsAll(list1) 116 && originalList2.size() == list2.size() && originalList2.containsAll(list2)) 117 || (originalList1.size() == list2.size() && originalList1.containsAll(list2) 118 && originalList2.size() == list1.size() && originalList2.containsAll(list1))) { 119 System.out.println("Player A and Player B tie!"); 120 return; 121 } 122 } 123 } 124 125 // 根据最后谁手上的牌为空,输出结果 126 if (list1.size() == 0) { 127 System.out.println("Player B win.The cards in player B are:"); 128 for (Integer one : list2) { 129 System.out.print(one + ", "); 130 } 131 } else { 132 System.out.println("Player A win.The cards in player A are:"); 133 for (Integer one : list1) { 134 System.out.print(one + ", "); 135 } 136 } 137 138 System.out.println("\nThe cards in the desk are:"); 139 while (stack.size() > 0) { 140 System.out.print(stack.pop() + ", "); 141 } 142 143 } 144 }