請設計用於通用撲克牌的數據結構。並說明你會如何建立該數據結構的子類。實現「二十一點」遊戲

 

Java 撲克發牌算法實現

利用Random類的對象的鏈表-隨機的順序存儲一副52張的紙牌。用含有兩個字符的字符串表明紙牌,例如「1C」表示梅花A,」JD」表示方片J等。從棧中輸出4手牌,每手牌有13張紙牌。java

 

 

 

  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張。每張「紙牌」應具備花色數字兩個屬性。app

(2)遊戲在機器與人類玩家之間進行。遊戲一開始應先洗牌(將104張牌打亂)。dom

(3)機器永遠是莊家,因此永遠先給機器發牌,機器的牌不可見,只能看到機器要了幾張牌。機器中止要牌後,再給人類玩家發牌。ide

(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方法,將用戶的輸入與已有的輸入相比較,不知足要求則須要從新輸入,

相關文章
相關標籤/搜索