实战:Java 扑克牌比较游戏

一.目的

通过实现一个简单的扑克牌比大小的游戏,体会面向对象编程的思想。

二.技术

1.常量类

2.类的创建,封装

3.单例模式

4.自定义异常类

三.如何使用

1.常量类

对于程序运行过程中,一直不变的数据,我们将它们统一保存在一个类中,这个类的名字通常是Constants,常量数据要用public static final修饰。

例如:

public class Constants {

    //所有点数
    public static final String[] DOTS = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};

    //所有的花色
    public static final String[] COLORS = {"♠","♥","♣","♦"};

    //默认的玩家姓名数组
    public static final String[] DEFAULT_NAMES ={"周润发","渣渣辉","陈小春","甄子丹"};

    //玩家默认的持有金币
    public static final int DEFAULT_MONEY = 1000;

    //玩家金币不足
    public static final int NOT_ENOUGH = -1;

    //玩家金币足够
    public static final int ENOUGH = 1;

    //底注金额
    public static final int BASE_WAGER = 100;
}

很明扑克牌的花色和点数是一直不变的,类似这样的数据我们就要写入常量类中,注意常量变量的名字一般大写。

2.类的创建,封装

明确这个任务中需要哪些类,这些类有什么功能

对于一个扑克牌游戏,我们需要玩家类Player来抽象玩家,需要扑克牌类Poker来抽象扑克牌,一系列玩家的行为需要一个类来管理所以诞生了我们的玩家管理类PlayerManager,同理管理我们的扑克牌也需要一个管理类PokerManager。一局游戏需要一个类来管理赌注,到那个玩家选择,所以诞生了我们的中心类Center

Poker类:有自己的点数和花色,重写String toString()是为了方便打印

public class Poker {

    public String dot;
    public String color;

    public Poker(){}
    public Poker(String dot,String color){
        this.dot = dot;
        this.color = color;
    }

    @Override
    public String toString() {
        return "Poker[" +
                "'" + dot + '\'' +
                "'" + color + '\'' +
                ']';
    }
}

PokerManager类,首先需要一个变量保存一副牌,接着要产生一副洗好的牌,展示牌,给每个人发牌。

/**
 * 管理牌的相关操作
 */
public class PokerManager {

    //单例模式
    private PokerManager() {}
    public static final PokerManager PokerDefault = new PokerManager();

    //成员变量:保存一副牌
    public static ArrayList<Poker> pokers = new ArrayList<>();

    /**
     * 展示一副牌
     */
    public void showPokers(){
        for (Poker poker : pokers) {
            System.out.print(poker+" ");
        }
        System.out.println("");
    }

    /**
     * 洗牌
     */
    public void shufflePokers(){
        //生成一副牌
        for (int i = 0; i < Constants.DOTS.length; i++) {
            for (int j = 0; j < Constants.COLORS.length; j++) {
                Poker poker = new Poker(Constants.DOTS[i],Constants.COLORS[j]);
                pokers.add(poker);
            }
        }
        //洗牌
        Collections.shuffle(pokers);
    }

    /**
     * 发牌
     */
    public void dealPokerToPlayers(){
        for (int i = 0; i < PlayerManager.PlayerDefault.players.size(); i++) {
            PlayerManager.PlayerDefault.players.get(i).poker = pokers.get(i);
        }
    }

}

3.单例模式

恶汉式创建:私有化构造方法,利用构造方法创建一个不可变的静态常量。

使用单利模式的目的是为了共享数据

在这里PokerManager类就需要使用单例模式,我们需要用它来创建一副牌,一副牌在一局游戏中肯定只有一个。难道现实中玩牌是先这副牌发牌后另一副牌发牌?

/**
 * 管理牌的相关操作
 */
public class PokerManager {

    //单例模式
    private PokerManager() {}
    public static final PokerManager PokerDefault = new PokerManager();

}

4.自定义异常类

两步走:自定义一个类继承Throwable类;创建构造方法,我建议创建有参的构造方法,便于传递异常信息。

比如我们这里初始化玩家数量最多只能初始化4个;如果超过四个,那么我们就在对应位置抛出一个异常。

public class XLWrongInputEXception extends Throwable {

    public XLWrongInputEXception(String desc){
        super(desc);
    }

}

四.具体使用

工程结构图

PlayerManager类

package swu.xl.day4.MyPractise.Manager;

import java.util.ArrayList;
import java.util.Arrays;

import swu.xl.day4.MyPractise.Constants;
import swu.xl.day4.MyPractise.Model.Player;
import swu.xl.day4.MyPractise.Status;

/**
 * 管理人的相关操作
 */
public class PlayerManager {

    //单例模式
    private PlayerManager(){}
    public static final PlayerManager PlayerDefault = new PlayerManager();

    //成员变量:保存玩家
    public ArrayList<Player> players = new ArrayList<>();

    /**
     * 展示所有玩家信息
     */
    public void showPlayers(){
        for (Player player : players) {
            System.out.print(player+" ");
        }
        System.out.println("");
    }

    /**
     * 初始化游戏玩家
     * @param count 玩家的人数
     */
    public void initPlayers(int count){
        for (int i = 0; i < count; i++) {
            Player player = new Player(Constants.DEFAULT_NAMES[i],Constants.DEFAULT_MONEY);
            player.id = i+1;
            player.status = Status.StatusIn;
            players.add(player);
        }
    }

    /**
     * 所有游戏玩家下底注
     * @return 下的底注金额
     */
    public int betWagerOfPlayers(){
        for (Player player : players) {
            player.bet(Constants.BASE_WAGER);
        }
        return players.size()*Constants.BASE_WAGER;
    }

    /**
     * 当前玩家
     * @param index 当前玩家的索引值
     * @return
     */
    public Player getPlayerOfIndex(int index){
        return players.get(index);
    }

    /**
     * 比较两个玩家的扑克牌
     * @param p1 玩家1
     * @param p2 玩家2
     * @return 扑克牌牌面大的玩家
     */
    public Player compareTwoPlayer(Player p1,Player p2){
        //比较点数大小
        int index1 = Arrays.binarySearch(Constants.DOTS,p1.poker.dot);
        int index2 = Arrays.binarySearch(Constants.DOTS,p2.poker.dot);
        if (index1 != index2){
            //点数不同
            if (index1 > index2){
                return p1;
            }else {
                return p2;
            }
        }else {
            //点数相同
            index1 = Arrays.binarySearch(Constants.COLORS,p1.poker.color);
            index2 = Arrays.binarySearch(Constants.COLORS,p2.poker.color);
            if (index1 > index2){
                return p1;
            }else {
                return p2;
            }
        }
    }

}

PokerManager类

package swu.xl.day4.MyPractise.Manager;

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

import swu.xl.day4.MyPractise.Constants;
import swu.xl.day4.MyPractise.Model.Poker;

/**
 * 管理牌的相关操作
 */
public class PokerManager {

    //单例模式
    private PokerManager() {}
    public static final PokerManager PokerDefault = new PokerManager();

    //成员变量:保存一副牌
    public static ArrayList<Poker> pokers = new ArrayList<>();

    /**
     * 展示一副牌
     */
    public void showPokers(){
        for (Poker poker : pokers) {
            System.out.print(poker+" ");
        }
        System.out.println("");
    }

    /**
     * 洗牌
     */
    public void shufflePokers(){
        //生成一副牌
        for (int i = 0; i < Constants.DOTS.length; i++) {
            for (int j = 0; j < Constants.COLORS.length; j++) {
                Poker poker = new Poker(Constants.DOTS[i],Constants.COLORS[j]);
                pokers.add(poker);
            }
        }
        //洗牌
        Collections.shuffle(pokers);
    }

    /**
     * 发牌
     */
    public void dealPokerToPlayers(){
        for (int i = 0; i < PlayerManager.PlayerDefault.players.size(); i++) {
            PlayerManager.PlayerDefault.players.get(i).poker = pokers.get(i);
        }
    }

}

Playerr类

package swu.xl.day4.MyPractise.Model;

import swu.xl.day4.MyPractise.Constants;
import swu.xl.day4.MyPractise.Status;

public class Player {

    public String name;
    public int money;
    public int id;
    public Poker poker;
    public Status status;

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

    @Override
    public String toString() {
        return id+"号:'" + name + '\'' +
                ":" + money + " " + poker;
    }

    /**
     * 玩家下注
     * @param betMoney 下注金额
     * @return ENOUGH 金额足够 NOT_ENOUGH金额不足
     */
    public int bet(int betMoney){
        if (money >= betMoney){
            money -= betMoney;
            return Constants.ENOUGH;
        }

        return Constants.NOT_ENOUGH;
    }
}

Poker类

package swu.xl.day4.MyPractise.Model;

public class Poker {

    public String dot;
    public String color;

    public Poker(){}
    public Poker(String dot,String color){
        this.dot = dot;
        this.color = color;
    }

    @Override
    public String toString() {
        return "Poker[" +
                "'" + dot + '\'' +
                "'" + color + '\'' +
                ']';
    }
}

Center类

package swu.xl.day4.MyPractise;

import swu.xl.day4.MyPractise.Manager.PlayerManager;
import swu.xl.day4.MyPractise.Manager.PokerManager;
import swu.xl.day4.MyPractise.Model.Player;

/**
 * 管理游戏
 */
public class Center {

    //成员变量:记录下注的总金额
    public int wager;

    //成员变量:记录当前玩家
    int currentPlayerIndex;

    //开始游戏
    public void start(){
        //玩家下底注
        Utils.log(false,true,new String[]{"游戏中心---玩家开始下底注"+Constants.BASE_WAGER+":"});
        int temp = PlayerManager.PlayerDefault.betWagerOfPlayers();
        wager += temp;
        PlayerManager.PlayerDefault.showPlayers();

        //开始发牌
        Utils.log(false,true,new String[]{"游戏中心---开始发牌:"});
        PokerManager.PokerDefault.dealPokerToPlayers();
        PlayerManager.PlayerDefault.showPlayers();

        //第一个玩家
        currentPlayerIndex = 0;

        //是否有人下注
        boolean hasPlayerBet = false;

        //只有两个人,还允许各下注一次
        int betTime = 0;

        //临时的下注金额
        int tempWager = 0;

        //各个玩家做出选择
        while (true) {
                System.out.println("");
                //获得当前玩家
                Player tempPlayer = PlayerManager.PlayerDefault.getPlayerOfIndex(currentPlayerIndex);

                //判断是否需要切换到下一个
                boolean needChangeNext = true;

                //提示信息
                Utils.log(false,true,new String[]{"游戏中心---请"+tempPlayer+"玩家选择操作"});
                //提示哪一位玩家做出选择
                Utils.log(true,false,new String[]{"看牌","弃牌",hasPlayerBet?"跟注":"下注"});

                int count = Utils.getInput();
                try {
                    if (count > 3){
                        throw new XLWrongInputEXception("异常:超出选择范围");
                    }
                }catch (XLWrongInputEXception e){
                    System.out.println(e.getMessage());
                    System.exit(1);
                }
                //具体的选择操作
                switch (count) {
                    case 1:
                        //看牌
                        Utils.log(false,true,new String[]{"你的扑克牌是:"+tempPlayer.poker});
                        //不需要比较人数
                        needChangeNext = false;
                        break;
                    case 2:
                        //弃牌
                        Utils.log(false,true,new String[]{"游戏中心---"+tempPlayer+"选择弃牌"});
                        tempPlayer.status = Status.StatusOut;
                        break;
                    case 3:
                        //下注
                        Utils.log(false,false,new String[]{"游戏中心---请输入"+(hasPlayerBet?"跟注":"下注")+"的金额:"});
                        //判断下注是否成功
                        while (true) {
                            //下注金额
                            tempWager = Utils.getInput();
                            //判断是否下注成功
                            if (tempPlayer.bet(tempWager) == Constants.NOT_ENOUGH){
                                //不成功
                                Utils.log(false,false,new String[]{"游戏中心---赌注不足,请重新输入"+(hasPlayerBet?"跟注":"下注")+"的金额:"});
                            }else {
                                //成功
                                //增加赌盘上的赌注
                                wager += tempWager;
                                //输出信息
                                Utils.log(false,true,new String[]{tempPlayer.id+"号玩家"+(hasPlayerBet?"跟注":"下注")+tempWager+"成功"});
                                //切换为已经有人下注
                                hasPlayerBet = true;
                                break;
                            }
                        }
                        break;
                    default:
                        break;
                }

                //根据玩家数量做出决定
                if (needChangeNext) {
                //临时变量保存当前的玩家数量
                int remainingCount = getCountOfRemainingPlayers();

                //如果只有一个人
                if (remainingCount == 1){
                    //取得结果
                    //这种情况必定是两个人了,其中一个人做出了弃牌的选择
                    //此时指引玩家的索引还停留在该弃牌玩家上

                    //切换到下一个人
                    changePlayerToNext();

                    //得到胜利者
                    Player winner = PlayerManager.PlayerDefault.getPlayerOfIndex(currentPlayerIndex);
                    winner.money += wager;

                    //输出胜利者
                    Utils.log(false,true,new String[]{"游戏中心---"+winner.id+"号玩家赢得胜利,赢得金额"+wager});

                    break;
                }

                //如果只有两个人
                if (remainingCount == 2){
                    betTime++;
                    if (betTime > 2){
                        //0 有人做出弃牌决定
                        //1 2
                        //只有两个人的时候,只可以再互相下注一次
                        //之后比较结果

                        //提示信息
                        System.out.println("");
                        Utils.log(false,true,new String[]{"游戏中心---下注次数用尽 进行比较"});

                        //进行比较
                        Player winner = getWinner();
                        winner.money += wager;

                        //输出胜利者
                        Utils.log(false,true,new String[]{"游戏中心---"+winner.id+"号玩家赢得胜利,赢得金额"+wager});

                        break;
                    }
                }

                //切换到下一个
                changePlayerToNext();
            }
        }

        //跳出循环后结束游戏
        //PlayerManager.PlayerDefault.showPlayers();
    }

    /**
     * 获得目前还在游戏的玩家数量
     * @return 玩家数量
     */
    public int getCountOfRemainingPlayers(){
        int sum = 0;
        for (Player player : PlayerManager.PlayerDefault.players) {
            if (player.status == Status.StatusIn) {
                sum++;
            }
        }
        return sum;
    }

    /**
     *找到下一个玩家
     */
    public void changePlayerToNext(){
        //获得玩家数量
        int size = PlayerManager.PlayerDefault.players.size();
        //找到下一个玩家
        //从下一个玩家开始currentPlayerIndex+1
        for (int i = (currentPlayerIndex+1) % size; ; i++) {
            Player player = PlayerManager.PlayerDefault.getPlayerOfIndex(i);
            if (player.status == Status.StatusIn){
                currentPlayerIndex = i % size;
                return;
            }
        }
    }

    /**
     * 比较最后剩余的两个玩家的扑克牌大小
     * @return 最后胜利的玩家
     */
    public Player getWinner(){
        //得到两个玩家
        Player p1 = null;
        Player p2 = null;
        for (Player player : PlayerManager.PlayerDefault.players) {
            if (player.status == Status.StatusIn){
                if (p1 ==null){
                    p1 = player;
                }else {
                    p2 = player;
                }
            }
        }
        return PlayerManager.PlayerDefault.compareTwoPlayer(p1,p2);
    }
}

Constants类

package swu.xl.day4.MyPractise;

public class Constants {

    //所有点数
    public static final String[] DOTS = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};

    //所有的花色
    public static final String[] COLORS = {"♠","♥","♣","♦"};

    //默认的玩家姓名数组
    public static final String[] DEFAULT_NAMES ={"周润发","渣渣辉","陈小春","甄子丹"};

    //玩家默认的持有金币
    public static final int DEFAULT_MONEY = 1000;

    //玩家金币不足
    public static final int NOT_ENOUGH = -1;

    //玩家金币足够
    public static final int ENOUGH = 1;

    //底注金额
    public static final int BASE_WAGER = 100;
}

Main类

package swu.xl.day4.MyPractise;

import swu.xl.day4.MyPractise.Manager.PlayerManager;
import swu.xl.day4.MyPractise.Manager.PokerManager;

public class Main {

    public static void main(String[] args){

        //欢迎
        Utils.log(false,true,new String[]{"游戏中心---欢迎来到扑克游戏"});

        //洗牌
        Utils.log(false,true,new String[]{"游戏中心---扑克牌已经洗好:"});
        PokerManager.PokerDefault.shufflePokers();
        PokerManager.PokerDefault.showPokers();

        //提示输入玩家
        Utils.log(false,false,new String[]{"游戏中心---请输入玩家人数:"});

        //生成玩家
        int count = Utils.getInput();
        try {
            if (count > Constants.DEFAULT_NAMES.length){
                throw new XLWrongInputEXception("异常:系统最多加载4个玩家");
            }
        } catch (XLWrongInputEXception e) {
            System.out.println(e.getMessage());
            System.exit(1);
        }
        PlayerManager.PlayerDefault.initPlayers(count);
        PlayerManager.PlayerDefault.showPlayers();

        //开始游戏
        Center center = new Center();
        center.start();
    }
}

Status类

package swu.xl.day4.MyPractise;

public enum Status {
    StatusIn, //玩家未弃牌
    StatusOut //玩家弃牌
}

Utils类

package swu.xl.day4.MyPractise;

import java.util.Scanner;

public class Utils {

    /**
     * 打印内容
     * @param separator 要不要***
     * @param lineBreak 要不要换行
     * @param content   输出的文本内容
     */
    public static void log(boolean separator,boolean lineBreak,String...content){

        //判断是否需要分割线
        System.out.print(separator?"**************\n":"");

        //判断输出的内容是单行还是多行
        if (content.length == 1) {
            System.out.print(content[0]+(separator?"\n":""));
        }else {
            //输出带编号的多行数据
            for (int i = 0; i < content.length; i++) {
                System.out.println((i+1)+". "+content[i]);
            }
        }

        //判断是否需要分割线
        System.out.print(separator?"**************\n":"");

        //判断是或需要换行
        System.out.print(lineBreak?"\n":"");
    }

    /**
     * 接受用户输入
     * @return 用户输入
     */
    public static int getInput(){

        Scanner scanner = new Scanner(System.in);

        return scanner.nextInt();
    }
}

XLWrongInputEXception类

package swu.xl.day4.MyPractise;

public class XLWrongInputEXception extends Throwable {

    public XLWrongInputEXception(String desc){
        super(desc);
    }
}

运行结果:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容