java:Map集合模拟斗地主,多线程模拟抢地主 实例

 源码如下:

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的双列集合特点,可以完成任何像扑克牌这种无法用自然排序集合的自定义排序;

猜你喜欢

转载自blog.csdn.net/weixin_42711325/article/details/81942133