java:Map集合模擬鬥地主,多執行緒模擬搶地主 例項
阿新 • • 發佈:2018-11-26
原始碼如下:
package selfpractice.day4; import java.util.*; //多執行緒模擬搶地,重點程式碼位於loot()方法內 public class Practice_Poker { public static void main(String[] args) {//入口 //獲得一幅撲克牌存放於HashMap中 HashMap<Integer, String> myPoker = newPoker(); //洗牌後將撲克牌鍵值存放於連結串列中 LinkedList<Integer> myPokerPoint = shuffle(); //存放玩家撲克牌鍵值的連結串列,每個連結串列代表一個玩家 LinkedList<Integer> player1 = new LinkedList<>(); LinkedList<Integer> player2 = new LinkedList<>(); LinkedList<Integer> player3 = new LinkedList<>(); //起牌按現實世界獲得17張撲克牌,剩餘3張即底牌 getPoker(myPokerPoint,player1,player2,player3); LinkedList<Integer> diPai = new LinkedList<>(myPokerPoint);//lambda不讓傳入可變引數myPoker 展示底牌放到方法執行後 loot(myPokerPoint,player1,player2,player3);//搶地主 //展示地底牌 for (Integer integer : diPai) { System.out.print(myPoker.get(integer)+" "); } System.out.println();//換個行 對齊 try {//等待控制檯輸出完畢前面的內容,否則結果可能格式混亂 Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } //三位玩家理牌 System.out.println("三位玩家理牌..."); sort(player1); sort(player2); sort(player3); //展示牌面,最後揭曉底牌 System.out.print("玩家一:"); showPoker(player1,myPoker); System.out.print("玩家二:"); showPoker(player2,myPoker); System.out.print("玩家三:"); showPoker(player3,myPoker); } //獲得撲克牌方法:來一幅撲克牌,返回一個包含54張牌的HashMap陣列,鍵值升序0~53,對應鬥地主規則牌面值大小 private static HashMap<Integer,String> newPoker(){ HashMap<Integer,String> hashMap=new HashMap<>();//存放撲克牌的HashMap String[] colors={"♥","♠","♦","♣"};//花色陣列 String[] nums={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};//牌面陣列 int term=0;//鍵值 //遍歷加入前52張牌 for (String num:nums) { for (String color:colors) { hashMap.put(term++,color+num); } } //新增大小王 hashMap.put(term++,"小王"); hashMap.put(term,"大王"); System.out.println("得到一副牌"); return hashMap; } //洗牌方法,實際洗的是LinkedList陣列 private static LinkedList<Integer> shuffle(){ //獲得所有牌的鍵值存入連結串列 LinkedList<Integer> linkedList=new LinkedList<>(); for (int i = 0; i < 54; i++) { linkedList.add(i); } Collections.shuffle(linkedList);//洗牌 System.out.println("洗牌..."); return linkedList;//返回洗牌結果 } //發牌方法:每起牌一次,撲克牌少一張,真實模擬,剩餘三張為底牌(引數一次為洗好的底牌和三個連結串列玩家) private static void getPoker( LinkedList<Integer> myPokerPoint,LinkedList<Integer> player1, LinkedList<Integer> player2,LinkedList<Integer> player3){ LinkedList<LinkedList<Integer>> playerList=new LinkedList<>(); //玩家放入迴圈起牌佇列 playerList.add(player1); playerList.add(player2); playerList.add(player3); //迴圈依次起牌,各17張 for (int i = 0; i < 51; i++) { playerList.getFirst().add(myPokerPoint.removeFirst()); playerList.addLast(playerList.removeFirst());//迴圈起牌佇列滾動一次,即第一個元素放到最後 } System.out.println("發牌..."); } //理牌方法:用Collections工具的快速排序sort方法 private static void sort(LinkedList<Integer> linkedList){ Collections.sort(linkedList); } //搶地主:利用多執行緒模擬搶地主,傳入 private static void loot(LinkedList<Integer> myPokerPoint,LinkedList<Integer> player1, LinkedList<Integer> player2,LinkedList<Integer> player3) { Object lock1=new Object();//物件鎖1 //先吹口哨,等待0.5秒,三位玩家執行緒依次就緒 synchronized (lock1){System.out.println("多執行緒模擬搶地主...\n裁判吹口哨:"); //等待0.5秒 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("口哨聲..."); lock1.notifyAll();//釋放物件鎖1開始搶地主 } new Thread(()->{//載入執行緒後等待物件鎖1倍裁判程式釋放,搶到物件鎖開始執行同步程式碼 synchronized (lock1){ //若底牌數大於0則拿過來加入自己的牌,並表示搶到地主並展示一下 //若沒有底牌就算了 if(myPokerPoint.size()>0) { player1.addAll(myPokerPoint); System.out.println("玩家一搶到地主"); System.out.print("展示底牌:"); myPokerPoint.clear(); } } },"玩家一執行緒").start(); new Thread(()->{//載入執行緒後等待物件鎖1倍裁判程式釋放 synchronized (lock1){ //若底牌數大於0則拿過來加入自己的牌,並表示搶到地主並展示一下 //若沒有底牌就算了 if(myPokerPoint.size()>0) { player2.addAll(myPokerPoint); System.out.println("玩家二搶到地主"); System.out.print("展示底牌:"); myPokerPoint.clear(); } } },"玩家二執行緒").start(); new Thread(()->{//載入執行緒後等待物件鎖1倍裁判程式釋放 synchronized (lock1){ //若底牌數大於0則拿過來加入自己的牌,並表示搶到地主並展示一下 //若沒有底牌就算了 if(myPokerPoint.size()>0) { player3.addAll(myPokerPoint); System.out.println("玩家三搶到地主"); System.out.print("展示底牌:"); myPokerPoint.clear(); } } },"玩家三執行緒").start( ); } //亮牌方法:自動判斷傳入的是玩家還是底牌 private static void showPoker(LinkedList<Integer> linkedList, HashMap<Integer, String> hashMap){ if(linkedList.size()==20) System.out.print("(地主)"); for (int i = 0; i <20; i++) { if(linkedList.size()==20){//若是地主 String str=hashMap.get(linkedList.get(i)); System.out.print(str+" "); }else{//否則是農民 String str=hashMap.get(linkedList.get(i)); System.out.print(str+" "); if(i==16) break; } } System.out.println();//換行 } }
連續執行三次結果如下:
第一次:
得到一副牌 洗牌... 發牌... 多執行緒模擬搶地主... 裁判吹口哨: 口哨聲... 玩家三搶到地主 展示底牌:♦10 ♠9 ♠6 三位玩家理牌... 玩家一:♥5 ♠5 ♣5 ♦6 ♠7 ♦7 ♠8 ♥9 ♦9 ♣9 ♥10 ♠10 ♦J ♣Q ♣K ♥2 小王 玩家二:♣3 ♥4 ♣4 ♦5 ♥6 ♣6 ♥7 ♣7 ♣8 ♣10 ♥J ♣J ♠K ♦K ♣A ♦2 大王 玩家三:(地主)♥3 ♠3 ♦3 ♠4 ♦4 ♠6 ♥8 ♦8 ♠9 ♦10 ♠J ♥Q ♠Q ♦Q ♥K ♥A ♠A ♦A ♠2 ♣2
第二次:
得到一副牌
洗牌...
發牌...
多執行緒模擬搶地主...
裁判吹口哨:
口哨聲...
玩家一搶到地主
展示底牌:大王 ♦4 ♦6
三位玩家理牌...
玩家一:(地主)♥3 ♦4 ♣4 ♠6 ♦6 ♠7 ♦7 ♦8 ♣8 ♥9 ♦9 ♣10 ♦J ♣J ♠A ♣A ♥2 ♠2 小王 大王
玩家二:♣3 ♥5 ♠5 ♦5 ♣5 ♥7 ♣7 ♥8 ♣9 ♦10 ♥Q ♦Q ♠K ♦K ♣K ♥A ♣2
玩家三:♠3 ♦3 ♥4 ♠4 ♥6 ♣6 ♠8 ♠9 ♥10 ♠10 ♥J ♠J ♠Q ♣Q ♥K ♦A ♦2
第三次:
得到一副牌
洗牌...
發牌...
多執行緒模擬搶地主...
裁判吹口哨:
口哨聲...
玩家二搶到地主
展示底牌:♥9 ♠8 ♦4
三位玩家理牌...
玩家一:♥3 ♣4 ♥5 ♠5 ♥6 ♣6 ♦8 ♣8 ♣9 ♥10 ♦10 ♣10 ♦J ♣Q ♥K ♥A ♠A
玩家二:(地主)♠3 ♥4 ♦4 ♦5 ♣5 ♦6 ♥7 ♠7 ♠8 ♥9 ♠9 ♥J ♠J ♣J ♠Q ♦Q ♠2 ♦2 ♣2 大王
玩家三:♦3 ♣3 ♠4 ♠6 ♦7 ♣7 ♥8 ♦9 ♠10 ♥Q ♠K ♦K ♣K ♦A ♣A ♥2 小王
機緣巧合,各搶到一次地主!!!!大家可以自己複製程式碼執行.
思維過程已經用在程式碼中註釋出,可以複製程式碼後利用除錯模式跟隨我的思路一步步執行程式碼!
程式設計思想:
1/ 利用多執行緒模擬搶地主,加入"裁判程式",率先獲得同步物件鎖. 以保障三個玩家執行緒全部建立完畢後,再同時爭奪物件鎖,執行鎖內程式碼,可以保證競爭絕對公平;
2/因為java控制檯字元輸出有延遲,故中間搶完地主後置了一段等待後臺輸出的時間;
3/根據本程式碼思維,利用HashMap的雙列集合特點,可以完成任何像撲克牌這種無法用自然排序集合的自定義排序;