一.目的
通过实现一个简单的扑克牌比大小的游戏,体会面向对象编程的思想。
二.技术
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);
}
}
运行结果: