JAVA-梭哈游戏

该游戏为书中贯穿前八章,一个非常全面的游戏实现,

其中涉及到,数组,集合,集合工具集,泛型,异常等

还是比较全面,其中的逻辑也比较复杂,主要是因为不知道游戏规则,导致业务逻辑无法继续,

该代码实现了几乎梭哈游戏的所有内容,只有牌型比较没有实现,如果实现,则代码性质将变质,我的学习之路到此为止,

以下

package java相关小实验;

import org.apache.commons.lang3.ArrayUtils;

import java.util.*;

/**
 * 一些声明信息
 *
 * @author 86150
 * @date: 2022/7/2 10:12
 * @description: 梭哈游戏
 * @since JDK 1.17
 * <p>
 * 关于梭哈游戏的规则
 * 我自己也没玩过,网上解释并不能解释我的疑惑,好在本程序只是一个实验性质的学习项目,也不用太过较真,
 * 为了使程序运行,我将在规则中加入自己的理解,我会打上标识
 * <p>
 * 游戏开始后,先发给各家2张牌,从第二张牌开始自动亮出,
 * <my>游戏开始时,每位玩家2000欢乐豆,入场费200欢乐豆,在具体的游戏规则有两套规则,选择方案二</my>
 * -----------------------------------------------------------------------------
 * 方案一:
 * 每发一张牌,从牌面较大者逆时针下注。优先下注者可选择
 * <my>每次下注100欢乐豆起步,每次最高下注金额为5*入场费</my>
 * <p>
 * 1.下注(选择欢乐豆数量,范围100<选择<5*入场费)
 * 2.不加(再次对自己下注,下注欢乐豆数量>你要加注的人欢乐豆数量)
 * 3.放弃
 * <p>
 * 在别人下注之后,可考虑
 * 1.跟(选择欢乐豆数量,范围100<选择<5*入场费)
 * 2.加(再次对自己下注,下注欢乐豆数量>你要加注的人欢乐豆数量)
 * <my>并且只要选择“跟”或“加”,则跳过本轮下注阶段</my>
 * 如果使用此方案,考虑在每次下注阶段使用Map,value值存储是否已经下注,每次判断value值,为0下注,为1跳过
 * -----------------------------------------------------------------------------
 * 方案二:
 * <p>
 * 每发一张牌,从牌面较大者逆时针下注。优先下注者可选择
 * <my>每次下注100欢乐豆起步,每次最高下注金额为5*入场费</my>
 * <p>
 * 1.下注(选择欢乐豆数量,范围100<选择<5*入场费)
 * 2.不加(再次对自己下注,下注欢乐豆数量>你要加注的人欢乐豆数量)
 * 3.放弃
 * 之后每个人可选择:
 * 1.跟(下注和上家一样筹码)
 * 2.加(下注筹码<上家筹码<5*入场费)
 * 3.放弃
 * -------------------------------------------------------------------------------
 * <p>
 * 当发到第四张牌时,可以选择“梭”,即增加下注到允许的最大筹码值
 * <my>最大筹码值=5*入场费</my>
 * <p>
 * 最后的胜利者获得本局桌面上的全部筹码,
 * <p>
 * 如果输家剩余的筹码数少于规定坐下的最小数额将被请出桌子。
 * <my>最小数额:欢乐豆<100</my>
 * ------------------------------------------------------------------------------------
 * 【牌型比较】
 * 牌型:同花顺>铁支>葫芦>同花>顺子>三条>两对>对子>散牌
 * 点数:A>K>Q>J>10>9>8
 * 花色:黑桃>红桃>草花>方片
 * ------------------------------------------------------------------------------------
 * 【牌型说明】
 * 同花顺:拥有五张连续数字同花色的顺子,以黑桃A为首的同花顺最大;
 * 铁支:四张相同数字的牌,外加一单张。比数字大小,「A」铁支最大;
 * 葫芦:由「三条」加一个「对子」所组成的牌。若别家也有此牌型,则比三条数字大小;
 * 同花:不构成顺子的五张同花色的牌。比花色后比大小;
 * 顺子:五张连续数字不花色的牌组成。 以A为首的顺子最大,如果大家都是顺子,比最大的一张牌,如果大小还一样就比这张牌的花色,黑桃A顺子最大;
 * 三条:牌型由三张相同的牌组成,以A为首的三条最大;
 * 二对:牌型中五张牌由两组两张同数字的牌所组成。若遇相同则先比这副牌中最大的一对,如又相同再比第二对,如果还是一样,比大对子中的最大花色;
 * 对子:牌型由两张相同的牌加上三张单张所组成。如果大家都是对子,比对子的大小,如果对子也一样,比这个对子中的最大花色
 * 散牌:由单一型态,不构成上面的牌型的五张散牌组成,先比最大一张牌的大小,如果大小一样,比这张牌的花色
 */
public class ShowHand {
    //定义该游戏最多支持多少个玩家
    private final int PLAY_NUM = 5;

    //    定义入场费
    private final int NUM = 200;

    //定义扑克牌的所有花色和数值
    private String[] types = {"方块-", "梅花-", "红心-", "黑桃-"};

    private String[] values = {"2", "3", "4", "5"
            , "6", "7", "8", "9", "10"
            , "J", "Q", "K", "A"};

    // 游戏开始金额
    private Integer[] money = new Integer[PLAY_NUM];
    // 每次的下注值
    private Integer[] moneyHand = new Integer[PLAY_NUM];

    // cards是一局游戏中剩下的扑克牌
    private List<String> cards = new LinkedList<String>();

    // 定义所有的玩家
    private String[] players = new String[PLAY_NUM];

    // 所有玩家手上的扑克牌
    private List<String>[] playersCards = new List[PLAY_NUM];

    /**
     * 初始化扑克牌,放入52张扑克牌
     * 并且使用shuffle方法将它们按随机顺序排列
     */
    public void initCards() {
        for (int i = 0; i < types.length; i++) {
            for (int j = 0; j < values.length; j++) {
                cards.add(types[i] + values[j]);
            }
        }

        //随机排列
        Collections.shuffle(cards);
    }

    /**
     * 初始化玩家,为每个玩家分派用户名
     */
    public void initPlayer(String... names) {

        System.out.println("玩家数量:" + names.length);

        try {

            if (names.length > PLAY_NUM || names.length < 2) {
                //初始化玩家用户名
                for (int i = 0; i < names.length; i++) {
                    players[i] = names[i];
//                    初始化金额
                    money[i] = 2000;
                }
            }
        } catch (Exception e) {

            //校验玩家数量,
            System.out.println("玩家数量不对");
//            直接结束程序
            System.exit(0);
        }


        //初始化玩家用户名
        for (int i = 0; i < names.length; i++) {
            players[i] = names[i];
        }


    }

    /**
     * 初始化玩家手上的扑克牌,开始游戏时每个玩家手上的扑克牌为空
     * 程序使用一个长度为0的LinkedList来表示
     */
    public void initPlayerCards() {
        for (int i = 0; i < players.length; i++) {
            if (players[i] != null && !"".equals(players[i])) {

//                给每个玩家一个linkedList数组,用于存储手中的牌

// 这个逻辑比较绕,    声明一个list的泛型(字符串)变量              创建一个list数组,长度为5
//                这里的泛型<String>让我看的有点迷糊,如果去掉,会出错
//                private List<String>[] playersCards = new List[PLAY_NUM];

//              给这个list数组的每个位置,给一个链表,限制加入元素类型为string
                playersCards[i] = new LinkedList<String>();

//                  下面代码报错     java不允许创建泛型类型的数组实例
//                 List<String>[] playersCards = new LinkedList<String>();

//                将金额初始化位2000,加减的值为入场费
                money[i] = 2000 - NUM;
                moneyHand[i] = 0 + NUM;
            }
        }
    }

    /**
     * 输出全部扑克牌,该方法没有实际作用,仅用作测试
     */
    public void showAllCards() {
        for (String card : cards) {
            System.out.println(card);
        }
    }


    /**
     * 派扑克牌
     *
     * @paramfirst 最先派给谁
     */
    public void deliverCard(String first) {

        //查询出指定元素在数组中的索引
        int firstPos = ArrayUtils.indexOf(players, first);

        //依次给位于该指定玩家之后的每个玩家派扑克牌
        for (int i = firstPos; i < PLAY_NUM; i++) {

            if (players[i] != null) {

//                从牌堆(cards)中拿牌
                playersCards[i].add(cards.get(0));

//                去掉已经发的牌
                cards.remove(0);

            }
        }

        //依次给位于该指定玩家之前的每个玩家派扑克牌
        for (int i = 0; i < firstPos; i++) {
            if (players[i] != null) {

                playersCards[i].add(cards.get(0));
                cards.remove(0);

            }
        }
    }

    /**
     * 输出玩家手上的扑克牌
     * 实现该方法时,应该控制每个玩家看不到别人的第一张牌,用count计数器实现
     */
    public void showPlayerCards() {

        for (int i = 0; i < PLAY_NUM; i++) {

            //当该玩家不为空时
            if (players[i] != null) {

                //输出玩家
                System.out.print(players[i] + " : \t");

//                计数器
                int count = 1;

                //遍历输出玩家手上的扑克牌
                for (String card : playersCards[i]) {

//                    跳过第一张手牌的输出查看
                    if (count == 1) {

                        System.out.print("*  ");
                        count++;

                        continue;
                    }

                    System.out.print(card + "\t");
                }
            }
            System.out.print("\n");
        }
    }


    /**
     * 展示每个人的第一张手牌
     */
    public void showOnewCards() {

        for (int i = 0; i < PLAY_NUM; i++) {

            //当该玩家不为空时
            if (players[i] != null) {

                //输出玩家
                System.out.print(players[i] + " ,你的第一张手牌是:\t ");

                System.out.print(playersCards[i].get(0) + "\t");

            }
            System.out.print("\n");
        }
    }


    /**
     * @param
     * @description: 比较牌面大小,下注方法
     * @return: void
     * @author: 谢柯
     * @time: 2022/7/23 17:25
     */
    public void bet() {
        int t = playersCards[0].size();

        System.out.println("每个玩家手中的牌数:" + t);

//        牌面比较
        String a = "";
//        花色比较
        String a1 = "无,牌面比较有结果";
//        记录下标
        int index01 = 0;


//        获取每个玩家手上,刚发的牌
        for (int i = 0; i < PLAY_NUM; i++) {

            if (players[i] != null) {

//                按”-“切割,存在card中
//               这是个比较奇怪的数组,在一个list中取第i个,这个里面存的是一个linkedlist的链表,再用get(索引)取
                String[] card = playersCards[i].get(t - 1).split("-");

//               牌面比较,记录大者
                if ("".equals(a) || contrast(a, card[1]) == 1) {

                    a = card[1];           //        则记录   1.牌面
                    a1 = card[0];          //                2.花色
                    index01 = i;           //                3.下标

                } else


//               牌面相同 花色判断
                    if (contrast(a, card[1]) == 0) {

                        int b = contrastColour(a1, card[0]);

                        if (b == 1) {
                            //a的花色大,不变

                        } else if (b == -1) {

//                        现有的花色大
                            a = card[1];
                            a1 = card[0];
                            index01 = i;

                        } else if (b == 0) {

                            //这里不改变值,就记录最开始的值
                            System.out.println("相同牌面,相同花色,按发牌人逆时针,顺位说话");
                            System.out.println("现实中不存在这种情况,出错");
                            System.exit(0);
                        }

                        System.out.println("上轮发牌中,花色最大值为:" + a1 );
                    }
            }
        }

        System.out.println("上轮发牌中,最大值为:" + a);
        System.out.println("上轮发牌中,最大值拥有者是:" + index01 + "\n");

        //下注
        xiazhu(index01);
    }


    /**
     * @param a
     * @param b
     * @description: 比较牌面大小    返回值含义  1(a<b)   -1(a>b)   0(a==b)
     * @return: int
     * @author: 谢柯
     * @time: 2022/7/25 8:52
     */
    public int contrast(String a, String b) {

        Map<String, Integer> s = new HashMap<String, Integer>();
        s.put("A", 1);
        s.put("2", 2);
        s.put("3", 3);
        s.put("4", 4);
        s.put("5", 5);
        s.put("6", 6);
        s.put("7", 7);
        s.put("8", 8);
        s.put("9", 9);
        s.put("10", 10);
        s.put("J", 11);
        s.put("Q", 12);
        s.put("K", 13);

//        a,b必须都在map中,下面的比较才有意义
        if (s.containsKey(a) && s.containsKey(b)) {

            int p = s.get(a).intValue();
            int q = s.get(b).intValue();

//        用键对应的值做判断,直接返回大值

            if (p > q) {
                return -1;

            } else if (p < q) {
                return 1;

            } else if (p == q) {
                return 0;
            }
        }


        System.out.println("有内鬼!停止交易");
        System.exit(0);
        return 0;
    }


    /**
     * @param a b
     * @description: 比较花色大小 返回值意义  1(a>b)    -1(a<b)     0(a==b)
     * 比较规则     黑桃>红心>梅花>方块
     * @return: int
     * @author: 谢柯
     * @time: 2022/7/25 8:50
     */
    public int contrastColour(String a, String b) {

        Map<String, Integer> s = new HashMap<String, Integer>();
        s.put("方块", 1);
        s.put("梅花", 2);
        s.put("红心", 3);
        s.put("黑桃", 4);

//        a,b必须都在map中,下面的比较才有意义
        if (s.containsKey(a) && s.containsKey(b)) {

            int p = s.get(a).intValue();
            int q = s.get(b).intValue();


//        用键对应的值做判断,直接返回大值
//        黑桃>红心>梅花>方块
            if (p > q) {
                return 1;
            } else if (p < q) {
                return -1;
            } else if (p == q) {
                return 0;
            }
        }

        System.out.println("有内鬼!停止交易");
        System.exit(0);
        return 0;
    }

    /**
     * @param firstPos
     * @description: 跟据传来的下标, 开始下注
     * @return: void
     * @author: 谢柯
     * @time: 2022/7/25 12:10
     */
    public void xiazhu(int firstPos) {

        Scanner in = new Scanner(System.in);
        int i1 = 0;
        //逆时针下注
        for (int i = firstPos; i >= 0; i--) {
            if (players[i] != null) {

//                对于两种人物,有两种不同的提示状态
                if (i == firstPos) {

//                    第一个需要选择,下注或者不加
                    System.out.println(players[i] + "-开始下注\n下注-1  不加-2  放弃-3");
                } else {

//                    之后的选择,跟或加
                    System.out.println(players[i] + "-开始下注\n跟-1  加-2  放弃-3");
                }

//                菜单选择
                int p = in.nextInt();

                switch (p) {
                    case 1:
//                        如果是首位,输入下注筹码
                        if (i == firstPos) {
                            System.out.println("输入值:");
                            i1 = in.nextInt();

                            while (i1 > moneyHand[i] || i1 > 5 * NUM || i1<0) {
                                System.out.println("错误,重新输入");
                                i1 = in.nextInt();
                            }

//                           如果值符合规范
//                            值不小0,值小于账户余额,值小于最大值(5*入场费)
                            money[i] = money[i] - i1;
                            moneyHand[i] = moneyHand[i] + i1;

                        } else {
//                          如果不是首位,赋上一位的值
                            money[i] = money[i] - i1;
                            moneyHand[i] = moneyHand[i] + i1;
                        }

                        break;
                    case 2:
                        if (i == firstPos) {
//                            首位选择不加,给一个初始值
                            i1 = 200;

                        } else {
//                            除过第一位,其余玩家加情况,
                            int i2 = in.nextInt();

                            while (i2 < i1 || i2 > moneyHand[i] || i2 > 5 * NUM) {
                                System.out.println("错误,重新输入");
                                i2 = in.nextInt();
                            }

//                                将输入的金额同步到数组
                            money[i] = money[i] - i2;
                            moneyHand[i] = moneyHand[i] + i2;
                        }
                        break;
                    case 3:
                        // 如果玩家需要放弃,则需要将玩家列表中删除,但筹码不能删除,考虑如何处理
//                        如果玩家放弃,则清除该玩家在”玩家“数组中的位置
                        players[i] = null;

                        break;

                    default:
                        System.out.println("错误");
                        i++;
                }
            }
        }


        //逆时针下注
        for (int i = players.length - 1; i > firstPos; i--) {
            if (players[i] != null) {

//                对于两种人物,有两种不同的提示状态
                if (i == firstPos) {

//                    第一个需要选择,下注或者不加
                    System.out.println(players[i] + "-开始下注\n下注-1  不加-2  放弃-3");
                } else {

//                    之后的选择,跟或加
                    System.out.println(players[i] + "-开始下注\n跟-1  加-2  放弃-3");
                }

//                菜单选择
                int p = in.nextInt();

                switch (p) {
                    case 1:
//                        如果是首位,输入下注筹码
                        if (i == firstPos) {
                            System.out.println("输入值:");
                            i1 = in.nextInt();

                            while (i1 > moneyHand[i] || i1 > 5 * NUM || i1<0) {
                                System.out.println("错误,重新输入");
                                i1 = in.nextInt();
                            }

//                           如果值符合规范
//                            值不小0,值小于账户余额,值小于最大值(5*入场费)
                            money[i] = money[i] - i1;
                            moneyHand[i] = moneyHand[i] + i1;

                        } else {
//                          如果不是首位,赋上一位的值
                            money[i] = money[i] - i1;
                            moneyHand[i] = moneyHand[i] + i1;
                        }
                        break;
                    case 2:
                        if (i == firstPos) {
//                            首位选择不加,给一个初始值
                            i1 = 200;

                        } else {
//                            除过第一位,其余玩家加情况,
                            int i2 = in.nextInt();
                            while (i2 < i1 || i2 > moneyHand[i] || i2 > 5 * NUM) {
                                System.out.println("错误,重新输入");
                                i2 = in.nextInt();

//                                将输入的金额同步到数组
                                money[i] = money[i] - i2;
                                moneyHand[i] = moneyHand[i] + i2;
                            }
                        }
                        break;
                    case 3:
                        // 如果玩家需要放弃,则需要将玩家列表中删除,但筹码不能删除,考虑如何处理
//                        如果玩家放弃,则清除该玩家在”玩家“数组中的位置
                        players[i] = null;

                        break;

                    default:
                        System.out.println("错误,重新输入");
                        i++;
                }


            }
        }


    }

    //    查看筹码值,无实际意义
    public void fori() {

        System.out.println("剩余金额:");
        for (int i = 0; i < money.length; i++) {
            if (money[i] != null) {
                System.out.print(players[i] + ":" + money[i] + "  ");
            }
        }
        System.out.println("\n");

        System.out.println("抛出金额:");
        for (int i = 0; i < moneyHand.length; i++) {
            if (money[i] != null) {
                System.out.print(players[i] + ":" + moneyHand[i] + "  ");
            }
        }
        System.out.println("\n");
    }


    public static void main(String[] args) {

//            实例化本类对象
        ShowHand sh = new ShowHand();

//        添加玩家
        sh.initPlayer("电脑玩家", "孙悟空", "孙悟空1", "孙悟空2");

//        洗牌
        sh.initCards();

//        初始化玩家手牌(为空)
        sh.initPlayerCards();

        //下面测试所有扑克牌,没有实际作用
        sh.showAllCards();
        System.out.println("---------------");

        //从孙悟空开始发牌,每人一张
        sh.deliverCard("孙悟空");

//        查看第一张手牌
        sh.showOnewCards();

        //看所有玩家手上的牌
        sh.showPlayerCards();

                /*
                这个地方需要增加处理:
                1.游戏是否只剩一个玩家?如果是,则此玩家胜利了
                2.如果已经是最后一张扑克牌,则需要比较剩下玩家的牌面大小
                */


        //再次从"电脑玩家"开始派牌
//        请注意,如果在上一轮该玩家放弃,则这里将抛出索引越界,可能的一种解决方案是,依次向数组后遍历,不为空开始 发牌
        sh.deliverCard("电脑玩家");

//        查看玩家手牌
        sh.showPlayerCards();

//        查看牌面,最大者下注
        sh.bet();

//        查看筹码流动
        sh.fori();




        //再次从"电脑玩家"开始派牌
        sh.deliverCard("电脑玩家");

//        查看玩家手牌
        sh.showPlayerCards();

//        查看牌面,最大者下注
        sh.bet();

//        查看筹码流动
        sh.fori();


//        第三次发牌
//        sh.deliverCard("电脑玩家");
//
//        sh.showPlayerCards();


    }
}


后言:

当我们试图想用文明道德这样的一个利刃,去指向她人的生活的时候,请不妨停下来想一想,我们在用谁的道德标准,绑架的又是谁的生活。

在复杂的现实与社会的分层之中,请更为公允的去思考道德秩序这样的问题,而在不同的生活境遇与生计可能性之下,也要正视不同人的活法,也更为善意地去对待我们与她人的关系

——黄盈盈

黄盈盈:我是黄盈盈,我今天讲的是「小姐研究二十年」|一席_哔哩哔哩_bilibili

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值