文档章节

请设计用于通用扑克牌的数据结构。并说明你会如何创建该数据结构的子类。实现“二十一点”游戏

一贱书生
 一贱书生
发布于 2016/11/21 09:58
字数 5546
阅读 75
收藏 1
点赞 0
评论 0

 

Java 扑克发牌算法实现

利用Random类的对象的链表-随机的顺序存储一副52张的纸牌。用含有两个字符的字符串代表纸牌,例如“1C”表示梅花A,”JD”表示方片J等。从栈中输出4手牌,每手牌有13张纸牌。

 

 

 

  1. 首先给扑克牌中每张牌设定一个编号,下面算法实现的编号规则如下:  
  2.  /*   红桃按照从小到大依次为:1-13  
  3.   u    方块按照从小到大依次为:14-26  
  4.   u    黑桃按照从小到大依次为:27-39  
  5.   u    梅花按照从小到大依次为:40-52  
  6.   u    小王为53,大王为54 
  7.   算法实现如下:  
  8.   u    首先按照以上编号规则初始化一个包含108个数字的数组  
  9.   u    每次随机从该数组中抽取一个数字,分配给保存玩家数据的数组  */
  10.   实现该功能的代码如下所示:  
  11.     package com.zuidaima;  
  12.   import Java.util.*;  
  13.   /** 
  14.   * 发牌算法的实现 
  15.   * 要求:把2副牌,也就是108张,发给4个人,留6张底牌 
  16. *     @author www.zuidaima.com 
  17. */  
  18. public class Exec{  
  19.     public static void main(String[] args){  
  20.        //存储108张牌的数组  
  21.        int[] total = new int[108];  
  22.        //存储四个玩家的牌  
  23.        int[][] player = new int[4][25];  
  24.        //存储当前剩余牌的数量  
  25.        int leftNum = 108;  
  26.        //随机数字  
  27.        int ranNumber;  
  28.        //随机对象  
  29.        Random random = new Random();  
  30.        //初始化数组  
  31.        for(int i = 0;i < total.length;i++){  
  32.            total[i] = (i + 1) % 54;  
  33.            //处理大小王编号  
  34.            if(total[i] == 0){  
  35.               total[i] = 54;   
  36.            }  
  37.        }  
  38.        //循环发牌  
  39.        for(int i = 0;i < 25;i++){  
  40.            //为每个人发牌  
  41.            for(int j = 0;j < player.length;j++){  
  42.               //生成随机下标  
  43.               ranNumber = random.nextInt(leftNum);  
  44.               //发牌  
  45.               player[j][i] = total[ranNumber];  
  46.               //移动已经发过的牌  
  47.               total[ranNumber] = total[leftNum - 1];  
  48.               //可发牌的数量减少1  
  49.               leftNum--;     
  50.            }    
  51.        }  
  52.        //循环输出玩家手中的牌  
  53.        for(int i = 0;i < player.length;i++){  
  54.            for(int j = 0;j < player[i].length;j++){  
  55.               System.out.print(" " + player[i][j]);    
  56.            }  
  57.            System.out.println();  
  58.        }  
  59.        //底牌  
  60.        for(int i = 0;i < 8;i++){  
  61.            System.out.print(" " + total[i]);   
  62.        }  
  63.        System.out.println();  
  64.     }  
  65. }  
  66.  

 

 完成一个变形版的纸牌21点游戏。该游戏来源于21点游戏,实现人机对战。

游戏说明如下:

(1)该游戏需要两副牌,没有Joker,共104张。每张“纸牌”应具有花色数字两个属性。

(2)游戏在机器与人类玩家之间进行。游戏一开始应先洗牌(将104张牌打乱)。

(3)机器永远是庄家,所以永远先给机器发牌,机器的牌不可见,只能看到机器要了几张牌。机器停止要牌后,再给人类玩家发牌。

(4)游戏胜利与失败的条件与普通21相同;除此以外,一方在当前牌没有爆掉的前提下,如果下一张牌使得手中有两张完全一样的牌(同数字、同花色)则立刻胜利。

(5)游戏结束时机器的牌要全部显示,并提示谁胜利了。

程序设计要求如下:

(1)程序中应至少有Card类和CardGame类。

(2)Card类需要重写Object类的equals(Object o)函数,用于比较两张牌是否完全一样;重写toString函数,用于输出牌时直接显示牌的花色与数字。

(3)CardGame类应具有shuffle(洗牌)、deal(发牌)、win(胜利判别)等函数。

(4)选择适当的java集合类来实现“发牌牌堆”和“手牌”(不允许都使用数组)。

 

  1. /* 
  2.  * To change this template, choose Tools | Templates 
  3.  * and open the template in the editor. 
  4.  */  
  5. package 21pointgame;  
  6. import java.util.ArrayList;  
  7. import java.util.Scanner;  
  8.   
  9. /** 
  10.  * 
  11.  * @author Soledad 
  12.  */  
  13. public class Main {  
  14.   
  15.     /** 
  16.      * @param args the command line arguments 
  17.      */  
  18.     public static void main(String[] args) {  
  19.         CardGame cg = new CardGame();  
  20.         cg.startGame();  
  21. // TODO code application logic here  
  22.     }  
  23. }  
  24. enum Color{  
  25.     HEARTS, DIAMOND, SPADE, CLUB  //红桃,方块,黑桃,梅花  
  26. }//***************学习点之一***************  
  27. class Card {  
  28.     private Color cardColor;  //牌的花色  
  29.     private int number;         //牌的面值  
  30.   
  31.     public Card(){  
  32.     }  
  33.   
  34.     public Card(Color c, int num) {  
  35.         cardColor = c;  
  36.         number = num;  
  37.     } //相当于C++中的赋值构造函数  
  38.       
  39.     @Override  
  40.     public boolean equals(Object obj) {  
  41.         if (obj == null)  
  42.             return false;  
  43.         else{  
  44.             if (obj instanceof Card){  
  45.                 return ((Card)obj).cardColor == this.cardColor &&((Card)obj).number == this.number ;  
  46.             }  
  47.             else   
  48.                 return false;     
  49.         }        
  50.      }//***************学习点之二***************  
  51.   
  52.     @Override  
  53.     public int hashCode() {  
  54.         int hash = 7;  
  55.         hash = 59 * hash + (this.cardColor != null ? this.cardColor.hashCode() : 0);  
  56.         hash = 59 * hash + this.number;  
  57.         return hash;  
  58.     }//****************学习点之三***************  
  59.     @Override  
  60.     public String toString() {  
  61.         String symbol;  
  62.         String numberString = "";  
  63.   
  64.         if (cardColor == Color.HEARTS)  
  65.             symbol = "红心";  
  66.         else if (cardColor == Color.DIAMOND)  
  67.             symbol = "方块";  
  68.         else if (cardColor == Color.SPADE)  
  69.             symbol = "黑桃";  
  70.         else  
  71.             symbol = "梅花";  
  72.   
  73.         if (number == 11) {  
  74.             numberString += "J";  
  75.         } else if (number == 12) {  
  76.             numberString += "Q";  
  77.         } else if (number == 13) {  
  78.             numberString += "K";  
  79.         } else if (number == 1){  
  80.             numberString += "A";  
  81.         } else{  
  82.             numberString += number;  
  83.         }  
  84.           
  85.         return symbol + "  " + numberString + "  ";  
  86.     }//****************学习点之四****************  
  87.   
  88.     public Color getCardColor() {  
  89.         return cardColor;  
  90.     }  
  91.   
  92.     public void setCardColor(Color cardColor) {  
  93.         this.cardColor = cardColor;  
  94.     }  
  95.   
  96.     public int getNumber() {  
  97.         return number;  
  98.     }  
  99.   
  100.     public void setNumber(int number) {  
  101.         this.number = number;  
  102.     }  
  103. }  
  104.   
  105. class CardGame{  
  106.     private Card[] cardHeap;      //排堆  
  107.     private int cardHeapPos;      //发到第几张牌了  
  108.     private ArrayList<Card>  playerCards ;     //玩家手牌  
  109.     private ArrayList<Card>  computerCards;    //电脑手牌  
  110.     //***************学习点之五***************  
  111.   
  112.     public CardGame() {  
  113.         cardHeap = new Card[104];  
  114.         playerCards = new ArrayList<Card>();  
  115.         computerCards = new ArrayList<Card>();  
  116.   
  117.         for(int i = 0; i < 104; i += 4 ) {  
  118.             for(int j = 0; j < 4; j ++) {  
  119.                 switch(j){  
  120.                     case 0:  
  121.                         cardHeap[i + j] = new Card(Color.HEARTS, i % 13 + 1);  
  122.                         break;  
  123.                     case 1:  
  124.                         cardHeap[i + j] = new Card(Color.DIAMOND, i % 13 + 1);  
  125.                         break;  
  126.                     case 2:  
  127.                         cardHeap[i + j] = new Card(Color.CLUB, i % 13 + 1);  
  128.                         break;  
  129.                     default:  
  130.                         cardHeap[i + j] = new Card(Color.SPADE, i % 13 + 1);  
  131.                         break;  
  132.                 }  
  133.             }  
  134.         }//通过两个循环分配给牌组两副牌(去除Jokers)  
  135.     }  
  136.   
  137.     void showCards(ArrayList<Card> cards) {  
  138.         for(Card element:cards) {  
  139.             System.out.print(element);  
  140.         }//****************学习点之六***************  
  141.         System.out.println();  
  142.     }  
  143.       
  144.     void shuffle(){  
  145.         cardHeapPos = 0; //归零  
  146.         Card[] tempHeap = new Card[104];  
  147.         int pos;  
  148.   
  149.         for(int i = 0 ; i < 104; i ++) {  
  150.             pos = (int)(Math.random() * 104);//**************学习点之七****************  
  151.             for(int j = 0; j < 104; j ++){  
  152.                 if(null == tempHeap[pos]) { //表示该空位没有分配值  
  153.                     tempHeap[pos] = new Card( cardHeap[i].getCardColor(), cardHeap[i].getNumber());  
  154.                     break;  
  155.                 } else {  
  156.                     pos = (pos + 1) % 104;  
  157.                 }  
  158.             }  
  159.         }//随机发牌堆到tempHeap中  
  160.   
  161.           
  162.         for(int i = 0; i < 104; i ++) {  
  163.             cardHeap[i].setCardColor(tempHeap[i].getCardColor());  
  164.             cardHeap[i].setNumber(tempHeap[i].getNumber());  
  165.         }//复制回原数组  
  166.     }  
  167.   
  168.     void deal(ArrayList<Card> cards) {  
  169.         cards.add(cardHeap[++cardHeapPos]);  
  170.     }  
  171.   
  172.     void gameOver(){  
  173.         System.out.println("庄家的牌");  
  174.         showCards(computerCards);  
  175.         System.out.println("庄家的总点数为 :" + getValue(computerCards));  
  176.         System.out.println("你的牌");  
  177.         showCards(playerCards);  
  178.         System.out.println("你的总点数为 :" + getValue(playerCards));  
  179.     }  
  180.   
  181.     int getValue(ArrayList<Card> cards) {  
  182.         int value = 0;  
  183.   
  184.         for(Card e:cards) {  
  185.             if (e.getNumber() >= 10)  
  186.                 value += 10;  
  187.             else if (e.getNumber() == 1)  
  188.                 value += 11;         //抽到“A”的时候是加1或加11, 这里先把加11  
  189.             else  
  190.                 value += e.getNumber();  
  191.         }  
  192.   
  193.         if(value > 21) {  
  194.             for(Card e:cards) {  
  195.                 if (e.getNumber() == 1){  
  196.                     value -= 10;  
  197.                     if (value < 21) break;  //如果小于21就跳出了  
  198.                 }  
  199.             }  
  200.         }  
  201.   
  202.         if(value > 21)  return -1;  
  203.         return value;  
  204.   
  205.     }  
  206.   
  207.    
  208.     boolean haveSame(ArrayList<Card> cards) {  
  209.         for(int i = 0; i < cards.size(); i ++) {  
  210.             for(int j = i + 1; j < cards.size(); j ++) {  
  211.                 if (cards.get(i).equals(cards.get(j))) {  
  212.                     return true;  
  213.                 }  
  214.             }  
  215.         }  
  216.         return false;  
  217.     }//return true表示cards中出现完全重复的牌  
  218.   
  219.     void startGame() {  
  220.         boolean finish = false;  
  221.         Scanner in = new Scanner(System.in);//****************学习点之八****************  
  222.         String playerInput = "";         
  223.   
  224.         while(!finish) {  
  225.             playerCards.clear();  
  226.             computerCards.clear();  
  227.             shuffle();  
  228.             //庄家摸牌  
  229.             System.out.println("庄家摸牌...");  
  230.             int computerValue = 0;  
  231.             boolean getWinner = false;  
  232.             try {  
  233.                     Thread.sleep(3000);  
  234.             }  
  235.             catch(InterruptedException e) {  
  236.                     e.printStackTrace();  
  237.             }  
  238.             //如果庄家的总点数等于或少于16点,则必须拿牌,否则停牌  
  239.             while(computerValue <= 16) {  
  240.                 deal(computerCards);  
  241.                 getWinner = haveSame(computerCards);  
  242.                 if (getWinner) {  
  243.                     System.out.println("庄家摸到了完全相同的牌,赢得了胜利!!!");  
  244.                     gameOver();  
  245.                     break;  
  246.                 }  
  247.                 computerValue = getValue(computerCards);  
  248.                 if (computerValue == -1) {  
  249.                     System.out.println("你赢了, 庄家牌摸爆了!!!");  
  250.                     gameOver();  
  251.                     getWinner = true;  
  252.                     break;  
  253.                 }  
  254.             }  
  255.   
  256.             if(!getWinner) {  
  257.                 System.out.println("庄家共有 " + computerCards.size() + " 张牌");  
  258.   
  259.                 while(!playerInput.equals("n")) {  
  260.                     deal(playerCards);  
  261.   
  262.                     getWinner = haveSame(playerCards);  
  263.                     if (getWinner) {  
  264.                         System.out.println("你摸到了完全相同的牌,赢得了胜利!!!");  
  265.                         gameOver();  
  266.                         break;  
  267.                     }  
  268.                     System.out.println("你的牌:");  
  269.                     showCards(playerCards);  
  270.                     int playerValue = getValue(playerCards);  
  271.                      if (playerValue == -1) {  
  272.                         System.out.println("庄家赢了, 你牌摸爆了!!!");  
  273.                         gameOver();  
  274.                         getWinner = true;  
  275.                         break;  
  276.                     }  
  277.                     System.out.println("总点数为 " + getValue(playerCards));  
  278.                     System.out.println("是否继续要牌(y/n)?");  
  279.                     playerInput = in.nextLine();  
  280.                 }  
  281.             }  
  282.   
  283.             if(!getWinner) {  
  284.                 switch(win()) {  
  285.                     case 1: //玩家胜利  
  286.                         System.out.println("你胜利了!!!");  
  287.                         gameOver();  
  288.                         break;  
  289.                     case 2:  
  290.                         System.out.println("平局!!!");  
  291.                         gameOver();  
  292.                         break;  
  293.                     case 3:  
  294.                         System.out.println("庄家获胜!!!");  
  295.                         gameOver();  
  296.                         break;  
  297.                 }  
  298.             }  
  299.   
  300.             System.out.println("是否继续游戏(y/n)?");  
  301.             playerInput = in.nextLine();  
  302.               
  303.             if(playerInput.equals("n"))  
  304.                 finish = true;  
  305.         }  
  306.     }  
  307.     //如果是用户不再摸牌而调用win, 则finish 设置为ture  
  308.     //返回1,说明玩家胜利  
  309.     //返回2,说明平局  
  310.     //返回3,说明电脑胜利  
  311.     int win() {  
  312.         //havaSame和双方是否爆牌已经在之前判断了(一旦有相同牌则获胜,一旦爆牌则失败,可见这两种情形优先级较高)  
  313.   
  314.         int playerValue = getValue(playerCards);  
  315.         int computerValue = getValue(computerCards);//获取玩家和电脑的总点数  
  316.   
  317.         if (playerValue > computerValue)  
  318.             return 1;  
  319.         else if (playerValue == computerValue)  
  320.             return 2;  
  321.         else  
  322.             return 3;  
  323.     }  
  324. }  

 

· 学习点之一:用enum枚举

enum一般用来枚举一组相同类型的常量。如性别、日期、月份、颜色等。对这些属性用常量的好处是显而易见的,不仅可以保证单例,且要作比较的时候可以用”== ”来替换”equals”,是一种好的习惯(如本例中第45行)。

用法:如:

性别:

 

[java] view plain copy

print?

  1. publicenum SexEnum {  
  2.   male, female;  
  3. }  

 

本例中的花色:

[java] view plain copy

print?

  1. enum Color{  
  2.     HEARTS, DIAMOND, SPADE, CLUB  //红桃,方块,黑桃,梅花  
  3. }  

需要注意的是,枚举对象里面的值都必须是唯一的,特别的,我们可以还通过enum类型名直接引用该常量,比如本例中的121,124,127等行通过类型名直接引用。

除此之外,我们还可以往enum中添加新方法,这里就不加介绍了。

 

 

· 学习点之二:重写equals函数进行比较

      equals(Object o)函数原本是Object类下面的函数,我查了一下JAVA的API,截图如下:

 

简而言之,如果JAVA中默认的equals方法跟实际不符的话,就需要重写equals方法。我们这里要对牌是否相同作比较,因此需要重写该方法(第40~50行):

[java] view plain copy

print?

  1. public boolean equals(Object obj) {  
  2.         if (obj == null)  
  3.             return false;//如果参数为空直接返回false  
  4.         else{  
  5.             if (obj instanceof Card){  
  6.                 return ((Card)obj).cardColor == this.cardColor &&((Card)obj).number == this.number ;//如果花色数字均相同则返回true否则false  
  7.             }  
  8.             else   
  9.                 return false;  //类型不一致返回false   
  10.         }        
  11.      }  

 

另外我们注意到API里面写着:

“注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。”这也就是我们下面要学习的第三点。

· 学习点之三:重写hashcode()

问:也许上面的话有些晦涩难懂啊,我们为什么要重写hashcode()方法呢?

答: object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true;

 

注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。如下:

(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true

(2)当obj1.hashCode() ==obj2.hashCode()为false时,obj1.equals(obj2)必须为false

如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等。特别指出利用equals比较八大包装对象(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它自定义对象时都是比较的引用地址。

hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。

 

总而言之,这样如果我们对一个对象重写了equals,意 思是只要对象的成员变量值都相等那么equals就等于true,但不重写hashcode,那么我们再new一个新的对象,当原对象.equals(新 对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致,如在存储散列集合时(如Set类),将会存储了两个值一样的对 象,导致混淆,因此,就也需要重写hashcode()。

更通俗的说:

Object中的hashcode()方法在我们创建对象的时候为每个对象计算一个散列码,这个散列码是唯一的,所以如果2个对象的散列码相同,那他们一定是同一个对象。

自己定义的类也可以重写hashCode()方法,按照自己定义的算法计算散列码的生成。

Object中的equals()方法,比较的是2个对象的引用地址,包括他们各自的散列码,如果不同,就认为是不同的对象。

String类中重写了equals方法,比较的是他们字符串的内容。

在我们这里自己定义的算法是(第53~58行):

[java] view plain copy

print?

  1. public int hashCode() {  
  2.         int hash = 7;  
  3.         hash = 59 * hash + (this.cardColor != null ? this.cardColor.hashCode() : 0);  
  4.         hash = 59 * hash + this.number;  
  5.         return hash;  
  6.     }  

 

· 学习点之四:重写toString()函数

因为它是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”。

它通常只是为了方便输出,比如System.out.println(xx),括号里面的“xx”如果不是String类型的话,就自动调用xx的toString()方法。然而对于默认的toString()方法往往不能满足需求,需要重写覆盖这个方法。

比较易懂,就不具体说明了,见代码60~86行。

 

·学习点之五:动态数组ArrayList

      动态数组,即可以将 ArrayList想象成一种“会自动扩增容量的Array”。它的优点是可以动态地插入和删除元素,但牺牲效率。

有关使用ArrayList的例子,参考ArrayList用法,里面介绍的很详细。在我们这题中,由于电脑和玩家的手牌都会因为抽牌而增加,因此将二者均设为ArrarList(第114,115行),方便动态插入。

 

· 学习点之六:增强for循环

      见代码138~140行,很多人没看懂for(Card element:cards) 这段,其实这是JDK5.0的新特性,作用是遍历数组元素。其语法如下:

 

  1. for(type element: array){  
  2. System.out.println(element);  
  3.   }   

 

 

· 学习点之七:善于使用随机数

      直接调用Math.random()可以产生一个[0,1)之间的随机数,注意区间是前闭后开的。本题当中因为共有104张牌,那么我们直接用(int)Math.random()*104即可以产生[0,104)之间的随机数,对应一下数组的下标前闭后开刚好满足。

 

· 学习点之八:利用Scanner进行输入

      我们都知 道,JAVA里输入输出函数十分的麻烦,尤其是输入。可喜的是,从SDK1.5开始,新增了Scanner类,简化了输入函数。如本题的221 行:Scanner in=new Scanner(System.in) 首先创建了一个in对象,然后in对象可以调用下列方法,读取用户在命令行输入的各种数据类型: nextDouble(), nextFloat, nextInt(),nextLine(),nextLong()等,上述方法执行时都会造成堵塞,等待用户在命令行输入数据回车确认,例如本题中的第 279行,在系统问询是否继续要牌(y/n)后,用in.nextLine()来接受玩家输入的值。

 

 

说了这么多,我们来运行下程序:

e….我什么都没干 输了- -;

再来一次。。。

平局。。。行,就这样了,不要欺负电脑了。

我们再回到题目和代码:

 

· 完成一个变形版的纸牌21点游戏。该游戏来源于21点游戏,实现人机对战。

游戏说明如下:

(1)该游戏需要两副牌,没有Joker,共104张。每张“纸牌”应具有花色数字两个属性。--直接对应代码24~37,60~102,117~134行

(2)游戏在机器与人类玩家之间进行。游戏一开始应先洗牌(将104张牌打乱)。--直接对应代码144~166行

(3)机器永远是庄家,所以永远先给机器发牌,机器的牌不可见,只能看到机器要了几张牌。机器停止要牌后,再给人类玩家发牌。--直接对应代码224~280行

(4)游戏胜利与失败的条件与普通21相同;除此以外,一方在当前牌没有爆掉的前提下,如果下一张牌使得手中有两张完全一样的牌(同数字、同花色)则立刻胜利。--直接对应代码181~205,208~217,311~323行

(5)游戏结束时机器的牌要全部显示,并提示谁胜利了。--直接对应代码172~179,283~297行

程序设计要求如下:

(1)程序中应至少有Card类和CardGame类。

(2)Card类需要重写Object类的equals(Object o)函数,用于比较两张牌是否完全一样;重写toString函数,用于输出牌时直接显示牌的花色与数字。

(3)CardGame类应具有shuffle(洗牌)、deal(发牌)、win(胜利判别)等函数。

(4)选择适当的java集合类来实现“发牌牌堆”和“手牌”(不允许都使用数组)。

21点游戏是一个古老的扑克游戏,游戏的规则是:各个参与者设法使自己的牌达到总分21而不超过这个数值。扑克牌的分值取它们的面值,A充当1或者11分,J,Q和K人头牌都是10分。庄家VS1~7个玩家。在开局时,包括庄家在内的所有参与者都有两张牌。玩家可以看到他们的所有牌以及总分,而庄家有一张牌暂时是隐藏的。接下来,只要愿意,各个玩家都有机会依次再拿一张牌。如果是玩家的总分超过了21(称为引爆),那么这个玩家就输了。在所有玩家都拿了额外的牌后,庄家将显示隐藏的牌。只要庄家的总分等于或小于16,那么他就必须再拿牌。如果庄家引爆了,那么还没有引爆的所有玩家都将获胜,引爆的玩家打成平局。否则,将余下的各玩家的总分与庄家的总分做比较,如果玩家的总分大于庄家的总分,则玩家获胜。如果二者的总分相同,则玩家与庄家打成平局中。

 

 

游戏功能描述

  1. 创建一副扑克牌:
    包括四种花色:黑桃,红桃,梅花,方片
    包括十三种点数:2-10,J,Q,K,A
  2. 创建两名玩家(or多名)
    玩家至少要有ID,姓名,手牌等属性,手牌为扑克牌的集合
  3. 将创建好的扑克牌进行随机洗牌
  4. 从洗牌后的扑克牌的第一张开始,发给每个玩家,按照一人一张的方式,每人发两张(or多张)
  5. 比较两名玩家手中的扑克牌,比较规则为:取两人各自手中点数最大的牌进行比较,点数大的赢;若两人各自的点数最大的牌相等,则再按照花色比较。

代码

//Card.Java

package card;

public class Card{
    private String color;
    private String number;

    public Card(String color, String number) {
        this.color = color;
        this.number = number;
    }

    public String getColor() {
        return color;
    }

    public String getNumber() {
        return number;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof Card))
            return false;
        Card other = (Card) obj;
        if (color == null) {
            if (other.color != null)
                return false;
        } else if (!color.equals(other.color))
            return false;
        if (number == null) {
            if (other.number != null)
                return false;
        } else if (!number.equals(other.number))
            return false;
        return true;
    }

}

 

//Cards.java

package card;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Cards {
    private List<Card> list = new ArrayList<Card>();

    //创建一副扑克牌
    public Cards(){
        System.out.println("-----------------创建扑克牌------------------");
        String[] color = {"黑桃", "红桃", "梅花", "方片"};
        String[] number = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J","Q","K", "A"};
        for(int i=0;i<color.length;i++)
            for(int j=0;j<number.length;j++){
                list.add(new Card(color[i], number[j]));
            }   
        System.out.println("----------------扑克牌创建成功!---------------");
    }

    //获取一副扑克牌
    public List<Card> getList() {
        return list;
    }

    //洗牌(打乱)
    public void shufCards(){
        System.out.println("----------------开始洗牌------------------------");
        Collections.shuffle(list);
        System.out.println("----------------洗牌结束------------------------");
    }

    //展示一副扑克牌
    public void showCards(){
        System.out.print("当前的扑克牌为:");
        System.out.print("[ ");
        for(int i=0;i<list.size();i++){
            System.out.print(list.get(i).getColor() + list.get(i).getNumber()+ " ");
        }
        System.out.println(" ]");
    }

}

 

//Player.java

package card;

import java.util.ArrayList;
import java.util.List;

public class Player {
    private int id;
    private String name;
    private List<Card> handCards = new ArrayList<Card>();

    public Player(int id, String name){
        this.id = id;
        this.name = name;
    }

    public List<Card> getHandCards() {
        return handCards;
    }

    public void setHandCards(Card card) {
        handCards.add(card);
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

 

//CardComparator.java(自定义排序规则)

package card;

import java.util.Comparator;

public class CardComparator implements Comparator<Card> {

    @Override
    public int compare(Card c1, Card c2) {
        // 构建花色和牌值数组,通过比对,计算得到某张牌的价值(大小)
        String[] color = {"方片", "梅花", "红桃", "黑桃"};
        String[] number = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J","Q","K", "A"};

        //由于比较规则是先比较牌值,如果相等再比较花色(黑红梅方),所以将牌值赋予较高的权值
        int valueOfC1 = 0;
        int valueOfC2 = 0;
        for(int i=0;i<number.length;i++){
            if(c1.getNumber().equals(number[i])) valueOfC1 += i*10;
            if(c2.getNumber().equals(number[i])) valueOfC2 += i*10;
        }
        for(int i=0;i<color.length;i++){
            if(c1.getColor().equals(color[i])) valueOfC1 += i;
            if(c2.getColor().equals(color[i])) valueOfC2 += i;
        }

        if( valueOfC1 > valueOfC2 ) return -1;
        if( valueOfC1 < valueOfC2 ) return 1;

        return 0;
    }

}

 

//PlayDemo.java

package card;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

public class PlayDemo {

    //创建玩家
    //要对玩家ID的异常处理,要求用户只能输入整数ID,否则需要重新输入
    public Player setPlayer(){
        int id=0;
        String name="";
        Scanner console = new Scanner(System.in);
        boolean ready = true;
        do{
            try{
                System.out.println("输入ID:");
                id = console.nextInt();
                ready = true;
            }catch(Exception e){
                System.out.println("请输入整数类型的ID!");
                ready = false;
                console.nextLine();
            }
        }while(ready==false);

        System.out.println("输入姓名:");
        name = console.next();      
        return new Player(id, name);
    }

    public static void main(String[] args) {
        //测试简易扑克牌程序
        PlayDemo game = new PlayDemo();
        //(1)创建一副牌
        Cards cards = new Cards();
        //(2)展示新的扑克牌
        cards.showCards();
        //(3)洗牌
        cards.shufCards();
        //(4)创建玩家
        System.out.println("--------------创建两个(or多个)玩家就可以开始游戏啦!-------------");
        List<Player> p = new ArrayList<Player>();
        for(int i=0;i<2;i++)
        {
            System.out.println("请输入第"+(i+1)+"位玩家的ID和姓名:");
            p.add(game.setPlayer());
        }
        for(int i=0;i<p.size();i++)
        {
            System.out.println("欢迎玩家:"+p.get(i).getName());
        }
        //(5)扑克牌比大小游戏开始啦~
        int count = 0;
        System.out.println("------------------开始发牌---------------------");
        //设定每人分别拿两张(or多张)
        for(int i=0; i<2;i++){
            //玩家轮流拿牌
            for(int j=0; j< p.size(); j++){
                System.out.println(">玩家"+p.get(j).getName()+"拿牌");
                p.get(j).setHandCards(cards.getList().get(count));
                count++;
            }
        }
        System.out.println("------------------发牌结束!--------------------");
        System.out.println("------------------开始游戏 ---------------------");
        for(int i=0;i<p.size();i++){
            System.out.print("玩家"+p.get(i).getName()+"的手牌为:[ ");
            for(int j=0;j<p.get(i).getHandCards().size();j++){
                Card cur = p.get(i).getHandCards().get(j);
                System.out.print(cur.getColor()+cur.getNumber()+" ");
            }
            System.out.println(" ]");
        }

        //排序得到每个玩家最大的手牌(排序规则自定义)
        for(int i=0;i<p.size();i++){
            Collections.sort(p.get(i).getHandCards(), new CardComparator());
        }
        List<Card> maxCard = new ArrayList<Card>();
        for(int i=0;i<p.size();i++){
            Card maxCur = p.get(i).getHandCards().get(0);
            System.out.println("玩家"+p.get(i).getName()+"最大的手牌为:"+ maxCur.getColor()+maxCur.getNumber());
            maxCard.add(maxCur);
        }

        //得到最后的胜者
        List<Card> temp = new ArrayList<Card>();
        temp.addAll(maxCard);
        Collections.sort(temp, new CardComparator());
        for(int i=0;i<p.size();i++){
            if(maxCard.get(i).equals(temp.get(0))) System.out.println("恭喜玩家:"+p.get(i).getName()+"获胜!"); 
        }

    }

}

 

游戏运行截图

这里写图片描述
这里写图片描述
还有一个地方需要优化,即不能输入重复的ID和姓名,可以重写Player的equals方法,将用户的输入与已有的输入相比较,不满足要求则需要重新输入,

 

© 著作权归作者所有

共有 人打赏支持
一贱书生
粉丝 19
博文 722
码字总数 600072
作品 0
类型嵌套 -- Nested Types

枚举类型常被用于实现特定类或结构体的功能。同样地,也能够在有多种变量类型的环境中方便地定义通用类或结构体。为了实现这种功能,Swift允许你定义类型嵌套,可以在枚举类型、类和结构体中...

626224816 ⋅ 2014/08/03 ⋅ 0

快速上手Gobject

What is G-object? —很多人被灌输了这样一种概念:要写面向对象程序,那么就需要学习一种面向对象编程语言,例如C++、Java、C#等等,而C语言是用来编写结构化程序的。 —事实上,面向对象只...

shezjl ⋅ 2016/01/17 ⋅ 0

【白话设计模式五】工厂方法模式(Factory Method)

白话设计模式 工厂模式 单例模式 【白话设计模式一】简单工厂模式(Simple Factory) 【白话设计模式二】外观模式(Facade) 【白话设计模式三】适配器模式(Adapter) 【白话设计模式四】单例模式...

陶邦仁 ⋅ 2016/02/19 ⋅ 0

翟志军/BlackjackGame

21点游戏 v0.1.0 这是一个纸牌的赌博游戏。 这个游戏的规则:每个玩家分别与庄家比点数,但是又不能超过21点。这是最原始,最简单的规则。但是发展到现代。游戏的规则已经变得复杂了很多。比...

翟志军 ⋅ 2014/02/28 ⋅ 0

Java程序员应当知道的10个面向对象设计原则

面向对象设计原则是OOPS编程的核心, 但我见过的大多数Java程序员热心于像Singleton (单例) 、 Decorator(装饰器)、Observer(观察者) 等设计模式,而没有把足够多的注意力放在学习面向对象的...

银月光海 ⋅ 2015/03/16 ⋅ 0

工厂方法模式(Factory Method)

1 场景问题 1.1 导出数据的应用框架 考虑这样一个实际应用:实现一个导出数据的应用框架,来让客户选择数据的导出方式,并真正执行数据导出。 在一些实际的企业应用中,一个公司的系统往往分...

无寄语 ⋅ 2016/09/26 ⋅ 0

扑克游戏的洗牌算法及简单测试

我在学习《写给大家看的C语言书》这本书时,对书后面附录的一个扑克游戏程序非常感兴趣。源代码在帖子最后。 PS:这本C语言教学书真的很好呀,非常适合我的水平。 在我弄明白作者的程序后,感...

逍遥书生 ⋅ 2012/11/22 ⋅ 0

从设计原则到设计模式

说明:这些资料仅仅是对设计模式的一些总结,没有设计模式的相关知识,很难看懂。即使看懂了这些,也仅说明理解了模式的基本思想。想要学好设计模式,还是建议好好看文后所列的参考书籍和推荐...

五大三粗 ⋅ 2014/12/09 ⋅ 0

菜鸟成长系列-多态、接口和抽象类

多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用) 动态绑定 静态绑定和动态绑定 这里所谓的绑定,...

glmapper ⋅ 2017/11/17 ⋅ 0

疯狂ios讲义之游戏的状态数据模型

对游戏玩家而言,在游戏界面上看到的“元素”千差万别、变化多端,但对游戏开发者而言,游戏界面上的元素在底层都是一些数据,不同的数据所绘制的图片有所不同。因此,建立游戏的状态数据模型...

博文视点 ⋅ 2014/02/13 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Mahout推荐算法API详解

前言 用Mahout来构建推荐系统,是一件既简单又困难的事情。简单是因为Mahout完整地封装了“协同过滤”算法,并实现了并行化,提供非常简单的API接口;困难是因为我们不了解算法细节,很难去根...

xiaomin0322 ⋅ 24分钟前 ⋅ 0

WampServer默认web服务器根目录位置

安装WampServer之后的web服务器根目录默认位置在WampServer安装目录下的www:

临江仙卜算子 ⋅ 25分钟前 ⋅ 0

Redux的一些手法记录

Redux Redux的基本概念见另一篇文。 这里记录一下Redux在项目中的实际操作的手法。 actions 首先定义action.js,actions的type,可以另起一个action-type.js文件。 action-type.js用来存...

LinearLaw ⋅ 27分钟前 ⋅ 0

android 手势检测(左右滑动、上下滑动)

GestureDetector类可以让我们快速的处理手势事件,如点击,滑动等。 使用GestureDetector分三步: 1. 定义GestureDetector类 2. 初始化手势类,同时设置手势监听 3. 将touch事件交给gesture...

王先森oO ⋅ 41分钟前 ⋅ 0

java 方法的执行时间监控 设置超时(Future 接口)

java 方法的执行时间监控 设置超时(Future 接口) import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor......

青峰Jun19er ⋅ 45分钟前 ⋅ 0

一名开源小白的Apache成长自述

今天收到了来自Apache Vote我成为Serviceomb项目Committer的邮件,代表自己的贡献得到了充分的肯定;除了感谢团队的给力支持,我更希望将自己的成长经历——如何践行Apache Way的心得介绍给大...

微服务框架 ⋅ 47分钟前 ⋅ 0

vim介绍、颜色显示和移动光标、一般模式下复制、剪切和粘贴

1.vim 是 vi 的升级版 vim 是带有颜色显示的 mini安装的系统,一般都不带有vim [root@aminglinux-128 ~]# yum install -y vim-enhanced已加载插件:fastestmirror, langpacksLoading mir...

oschina130111 ⋅ 48分钟前 ⋅ 0

Deepin 操作系统四面楚歌

作为国内做的最好的 Linux 发行版,源自 Debian sid 的 Deepin 目前正面临重重困境,新版本不断延期,开发人员离职,bug 长期得不到修复,和 Debian/Ubuntu 的兼容性问题也面临越来越严重的挑...

六库科技 ⋅ 48分钟前 ⋅ 0

MyBatis之动态sql

我们需要知道的是,使用mybatis重点是对sql的灵活解析和处理。在原先的UserMappser.xml中,我们这样查询表中满足条件的记录 : 123 <select id="findUserList" parameterType="userQuery...

瑟青豆 ⋅ 49分钟前 ⋅ 0

这届俄罗斯世界杯的冷门那么多怎么办?

最纯粹的世界杯,最神奇的大冷门。 德国0比1被墨西哥摩擦了。 日本历史性的赢了哥伦比亚。 C罗也挑平了西班牙。 梅西被冰岛狮吼吼愣神了。 就连11次进世界杯4强的巴西也被瑞士逼平了。 天台已...

开源中国众包平台 ⋅ 49分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部