Java实战开发(2)——扑克游戏
2020-04-05 本文已影响0人
让时间走12138
本节内容
1.游戏架构和功能
2.游戏功能的具体实现
注:解说以下代码是按照写代码的过程以及思路顺序来讲解的,所以以文字顺序为主,其中文字附带部分代码。所有的源代码在最末尾。
一、游戏架构和功能
(一)游戏过程:
1.设置参与的人数,并给每个人设置名字(ID号)、序号(某一桌)和初始金币
2.设置本局消耗金币(底注),相当于选择不同等级的房间
3.开始玩游戏。每个人下底注(比如5块,10块等),然后给每个人发张牌(或者多张牌,根据游戏规则决定),之后按照顺序下注(①->②->③),当前下注的人可以选择{①下注:自由下注,不能比上个玩家少,也不能多于自己的金币。②跟注:上个玩家下注多少就下注多少。③all-in:自己有多少就下多少。如果他的总金币比上一个玩家下的注要少,那么就按他的注来,并退还前面玩家的下注差(比如1,2号下注20,三号只有all-in15,那么就会退还1,2号5个金币)④比牌(前提是玩法只有一张牌):和另外一位玩家比牌,不管输赢。⑤弃牌:放弃},依次下注,只剩一人时游戏结束
4.一局游戏结束,显示当前所有玩家的金币信息
(二)该游戏里的对象
1.玩家
2.牌
3.游戏中心(在哪里玩,QQ或者微信等)
4.玩家的管理者
5.扑克的管理者
6.规则:先比大小,再比花色(黑♠>红♥梅♣>方♦)ASCII值分别为(6,3,5,4)所以用ASCII不太方便,所以我们可以自己给黑红梅方设值
(三)写代码之前需要以下步骤
找对象抽类——>理清类与类之间的关系——>UML画图/架构
具体架构:游戏中心(Game Center)管理Poker Manager和Play Manager类。
由Poker管理一张牌,在Poker类里面有(设置内部类PokerType包含属性dot、pic Type和tag int(给黑红梅方设值,这样在比较花色的时候直接比较tag值即可),内部类之外有pic 和dot 以及compare方法,开牌比较大小)。
由PokerManager来管理一副牌(有一个数组保存所有的牌,有一些方法来初始化一副牌,以及获取一张牌等)。游戏中心(Game Center)发牌的时候就会从PokerManager里面拿牌
Player类:包含玩家的编号,姓名,筹码,是否弃牌(使用接口),玩家的一张牌,玩家的副牌,还有方法(赢钱,输钱,下注,退还钱如何计算)
PlayManager类:包含初始化所有玩家,获取一个玩家等方法
Game Center类:包含属性当前台面上的总金额,button(每局的赌注),CurrentPlayer(当前玩家),还有其他类的对象。一些方法,初始化数据,开始游戏,游戏结束。
定义一个iGame接口来判断Game Center类里面初始化是否成功,并回调数据给游戏中心
二、扑克游戏具体实现
1.创建AGameCenter的抽象类和单例,直接在构造函数里面设计好执行的顺序,先初始化数据,然后是玩家,最后是扑克,后面补充它们的抽象方法和其他方法
public abstract class AGameCenter implements IGameInitListener{
private int totalSuccess;
protected PlayerManager playerManager;
protected PokerManager pokerManager;
protected int ante;//台面的总金额
protected int totalPlayer;//玩家人数
protected int Button;//底注
protected AGameCenter(){
//初始化游戏本身的数据
initGame();
//初始化玩家
initPlayers();
//初始化扑克
initPokers();
}
protected abstract void initGame();
protected abstract void initPokers();
protected abstract void initPlayers();
protected abstract void start();
@Override
public void onInitSuccess() {
//对成功的计数器+1
setTotalSuccess(getTotalSuccess()+1);
}
@Override
public void onInitFailure() {
}
public void setTotalSuccess(int totalSuccess) {
this.totalSuccess = totalSuccess;
if(totalSuccess==3){//因为要初始化三次,所以通过totalSuccess是不是等于三来判断初始化是否成功
start();
}
}
public int getTotalSuccess() {
return totalSuccess;
}
}
2.创建一个IGameInitListener的接口来判断初始化是否成功
public interface IGameInitListener {
void onInitSuccess();
void onInitFailure();
}
3.创建一个PokerGameCenter类,也就是游戏中心,采用单例设计模式,所以最开始要创建一个静态对象
public class PokerGameCenter extends AGameCenter{
private static PokerGameCenter Instance;//实例化一个对象
private int LiveCount;
private int currentPlayerIndex;
private PokerGameCenter(){//构造方法
}
public static PokerGameCenter GetInstance(){
if(Instance==null){
synchronized (PokerGameCenter.class){
if(Instance==null){
Instance=new PokerGameCenter();
}
}
}
return Instance;
}
@Override
protected void initGame() {
//创建对象
playerManager=playerManager.GetManager();
pokerManager=pokerManager.GetManager();
ante=0;
totalPlayer=3;
Bottom=5;
currentPlayerIndex=1;
LiveCount=totalPlayer;
//设置监听者
playerManager.setListener(this);
pokerManager.setListener(this);
//初始化完毕,成功的计数器+1
setTotalSuccess(getTotalSuccess()+1);
}
@Override
protected void initPokers() {
pokerManager.InitPokers();
}
@Override
protected void initPlayers() {
playerManager.InitPlayers();
}
@Override
protected void start() {
//先扣底注钱
PlayerManager.GetManager().DeductMoney(Bottom);
//实现发牌
dealCards();
//开始下注
startBets();
}
}
4.创建管理类实现接口回调
①创建一个PokerManager类来管理一副牌,因为用的是单例设计模式,所以需要设置一个静态对象,并且私有化构造方法,用接口创建了一个对象Listener来方便将对象创建成功的事件返回给监听者(游戏中心)注:在创建了Poker类之后就可以实现PokerManager类里面的InitPokers方法。
public class PokerManager {
private IGameInitListener Listener;
private static PokerManager manager;
private PokerManager(){
}
public static PokerManager GetManager(){
if(manager==null){
synchronized (PokerManager.class){
if (manager==null){
manager=new PokerManager();
}
}
}
return manager;
}
public void InitPokers(){
//初始化数组对象
pokers=new ArrayList<>();
//创建扑克牌
for(String dot: Constants.IPoker.DOTS){
//这样就取出来了一张牌,之后选择花色
for(Poker.PicType type:Constants.IPoker.PIC_TYPES){
//创建一张牌
Poker poker=new Poker(dot,type);
//添加到数组中保存
pokers.add(poker);
}
}
//当扑克牌初始化成功就回调成功的事件给监听者(游戏中心)
if(Listener!=null){
Listener.onInitSuccess();
}
}
public void setListener(IGameInitListener listener) {
Listener = listener;
}
}
②创建一个PlayerManager类来管理许多玩家,采用的也是单例设计模式,其他原理同上
public class PlayerManager {
private IGameInitListener Listener;
private static PlayerManager manager;
private PlayerManager(){
}
public static PlayerManager GetManager(){
if(manager==null){
synchronized (PlayerManager.class){
if (manager==null){
manager=new PlayerManager();
}
}
}
return manager;
}
public void InitPlayers(){
//当玩家初始化成功就回调成功的事件给监听者(游戏中心)
if(Listener!=null){
Listener.onInitSuccess();
}
}
//获取一个玩家
public Player getPlayer(int index){
return players.get(index);
}
}
public void setListener(IGameInitListener listener) {
Listener = listener;
}
}
5.创建一副牌
先创建一个Constants接口来记录牌的点数和花色
public interface Constants {
interface IPlayer{
int chips=1000;
}
interface IPlayerName{
String [] NAMES_XING={"赵","钱","孙","李","周","吴","郑","王","冯"};
String [] NAMES_MING1={"子","秋","鹤","文","泽","凯","元","建","可"};
String [] NAMES_MING2={"豪","月","雪","晨","岚","峥","瑶","欣","阳"};
}
//扑克使用的常量
interface IPoker{
//点数
String[] DOTS={"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
//四种花色,给每一个花色都匹配一个tag值
Poker.PicType[] PIC_TYPES={Poker.PicType.SPADE,Poker.PicType.HEARTS,
Poker.PicType.CLUBS, Poker.PicType.DIAMONDS};
}
}
创建一个Poker类,再在这个类里面创建一个内部类PicType来管理牌的花色和tag值,tag值是为了方便比较花色大小所以自己给花色赋的值。因为花色是固定不变的,所以可以定义四个静态变量来表示四种不同的花色。另外构造方法是必要的。
public class Poker {
public String dot;//管理牌的点数
public PicType type;//花色对象
public Poker(String dot, PicType type) {
this.dot = dot;
this.type = type;
}
public static class PicType{
public String pic;//管理花色
public int tag;//花色对应的tag值
//
public static final PicType SPADE=new PicType("♠",4);
public static final PicType HEARTS=new PicType("♥",3);
public static final PicType CLUBS=new PicType("♣",2);
public static final PicType DIAMONDS=new PicType("♦",1);
public PicType(String pic, int tag) {
this.pic = pic;
this.tag = tag;
}
}
@Override
public String toString() {
return dot+type.pic;
}
}
6.创建玩家,自动生成名字
现在可以在AGameCenter里面添加一个变量来记录人数,并在PokerGamecenter类里面初始化为3
protected int totalPlayer;//玩家人数
然后创建一个玩家Player类,里面有很多不同的属性(名字,编号等),在记录是否弃牌时,就需要在Constants里面添加一个内部接口记录玩家的状态
interface IPlayerState{
int HAND=0;//还在玩
int DISCARD=1;//弃牌
}
创建一个Player类,里面包含玩家的一些属性,其中编号,名字和筹码可以直接知道就可以写在一个构造方法里面,代码如下
public class Player {
public int id;//编号
public String name;//名字
public int chips;//筹码
public Poker poker;//手上的一张牌
public ArrayList<Poker> pokers;//手上有很多张牌
public int playState;//玩家的状态
public Player(int id, String name, int chips) {
this.id = id;
this.name = name;
this.chips = chips;
playState=Constants.IPlayerState.HAND;//初始化状态
}
}
创建一个Util类来随机生成名字,因为数组下标必为整数,所以用MAth.abs()函数取随机数的绝对值
public class Util {
public static String AutoGeneName(){
Random random=new Random();
//姓名的随机数
int x_index=Math.abs(random.nextInt()%Constants.IPlayerName.NAMES_XING.length);
int m_index=Math.abs( random.nextInt()%Constants.IPlayerName.NAMES_MING1.length);
int l_index=Math.abs( random.nextInt()%Constants.IPlayerName.NAMES_MING2.length);
String f= Constants.IPlayerName.NAMES_XING[x_index]+
Constants.IPlayerName.NAMES_MING1[m_index]+
Constants.IPlayerName.NAMES_MING2[l_index];
return f;
}
/**
*输出语句
*/
public static void show (boolean nextLine,boolean needNumber,String...args) {
StringBuilder builder=new StringBuilder();
if (needNumber) {
for (int i = 0; i < args.length; i++) {
String content = (i + 1) + "." + args[i]+" ";//1.下注2.跟注等
builder.append(content);//把数组里面的都追加过来
}
}else{
for(String content:args){
builder.append(content+" ");
}
}
if(nextLine){
System.out.println(builder.toString());
}else{
System.out.print(builder.toString());
}
}
//输出一行不换行,不需要编号的数据
public static void show(String content){
Util.show(false,false,new String[]{content});
}
}
7.发牌
需要先设置一个底注Bottom,在AGameCenter类里面定义,在PokerGameCenter类里面初始化
protected int Button;//底注
在发牌之前需要先扣钱,先在Player类里面定义一个扣钱的方法Lost Money,在PlayerManager类里面写一个DeductMoney方法扣钱,遍历每个数组并调用LostMoney方法
//扣钱
public void LostMoney(int count){
chips-=count;
}
//所有玩家扣钱
public void DeductMoney(int count){
for(Player player:players){
player.LostMoney(count);
}
}
开始发牌,需要在PokerManager类里面添加一个getOnePoker方法来获取一张牌,因为牌的顺序已经是乱的,所以每次选择牌的第一张即可,并且删除这张牌(以免后面的玩家抽到一样的牌)。
然后在PokerGameCenter类实现start方法实现发牌,每次发一张牌,调用getOnePoker方法,并将这张牌发给对应的人。创建一副牌之后还得打乱顺序
public Poker getOnePoker(){
//因为牌已经被打乱了,所以获取第一张,再将其删除即可
if(pokers.size()>0){
Poker poker=pokers.get(0);
//将这张牌从数组里面删除
pokers.remove(0);
return poker;
}
return null;
}
//打乱顺序-洗牌
Collections.shuffle(pokers);
8.包装输出语句
在下注之前我们要显示玩家的选择,先在PokerGameCenter类里面的start方法里面添加一个下注的函数,然后在start方法外实现这个函数。在Util类里面写一个输出方法,显示用户的选择。(其具体代码见上)
public static void show (boolean nextLine,boolean needNumber,String...args) {
StringBuilder builder=new StringBuilder();
if (needNumber) {
for (int i = 0; i < args.length; i++) {
String content = (i + 1) + "." + args[i]+" ";//1.下注2.跟注等
builder.append(content);//把数组里面的都追加过来
}
}else{
for(String content:args){
builder.append(content+" ");
}
}
if(nextLine){
System.out.println(builder.toString());
}else{
System.out.print(builder.toString());
}
}
9.显示提示内容接收选择
在PokerGameCenter类我们要实现startBets方法,显示内容,那我们就在Util类里添加了一个show函数,然后在startBets方法里调用这个函数.
//输出一行不换行,不需要编号的数据
public static void show(String content){
Util.show(false,false,new String[]{content});
}
在用户选择后我们需要写一个方法来接收用户的输入,将这个input方法直接写在PoerkGameCenter类里面,还需要一个一个方法来发牌,同样写在PoerkGameCenter类里面
private int input(int max,int min) {
while (1 > 0) {
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
if (num >= min || num <= min) {
return num;
}
Util.show("输入数据不正确,请重新输入");
}
private void dealCards () {
int count = playerManager.getPlayerCount();
for (int i = 0; i < count; i++) {
//从扑克中心获取一张牌
Poker poker = PokerManager.GetManager().getOnePoker();
//将这张牌发给对应的人
Player player = PlayerManager.GetManager().getPlayer(i);
player.poker = poker;
}
System.out.println(playerManager.players);
}
}
10.实现弃牌和下注
某个玩家弃牌后,当前在玩人数减一,同时玩家的索引值加一,并判断索引值是否超过在玩人数,如果超过,索引值就初始化为1
case 5:
//弃牌
player.playState= Constants.IPlayerState.DISCARD;
//弃牌之后,在玩的玩家数减一
LiveCount--;
之后索引值会加一,写在switch语句后面
currentPlayerIndex++;
if(currentPlayerIndex>totalPlayer){
currentPlayerIndex=1;
}
在Player类里面添加一个扣钱的方法
//加钱
public void WinMoney(int count){
chips+=count;
}
在PlayerManager类添加一个AwardMoney方法,把钱加给玩家
public void awardPlayer(int money){
for(Player player:players){
if(player.playState==Constants.IPlayerState.HAND){
player.WinMoney(money);
}
}
}
下注:在PokerGameCenter方法里面添加一个下注方法,然后在caes1里调用这个函数,因为每次下注都要比上一个玩家多,所以定义一个变量来记录上一个玩家下的注。
//下注
private void Bet(Player player){
Util.show("请输入下注金额:");
int total= input(player.chips,LastPlayerBet);
//总金额增加
ante+=total;
//扣除这个人的筹码
player.LostMoney(total);
//记录这次下注金额
LastPlayerBet=total;
}
11.实现不同状态的提示和跟注
如果一个人的所有的金币都少于前一个人的赌注,那么这个时候他只有两种选择,一种是all-in,另一种就是弃牌,所以在做选择前,我们要先比较每一个玩家的所有钱和前一个人的赌注,所以就要分两种不同的情况,每种情况的显示与选择都不同。所以我们在constants接口里另外写一个接口来作为显示
interface IBet{
String [] NORMAL =new String[]{"下注 2.跟注 3.pall-in 4.比牌 5.弃牌"};
String [] LESS= new String[]{"all-in,弃牌"};
}
在startbet里面重新写过startBet方法
//下注
private void startBets(){
while(LiveCount>1) {
//判断当前这个人的提示信息
Player player = playerManager.getPlayer(currentPlayerIndex - 1);
if (player.chips <= LastPlayerBet) {
Util.show(true, true, Constants.IBet.LESS);
//获取当前玩家信息
Util.show("请" + player.id + "号玩家选择操作(" + player.name + " $" + player.chips + "):");
//接收用户输入
int choice = input(2, 1);
System.out.println(choice);
switch (choice) {
case 1:
//all-in
break;
case 2:
//弃牌
player.playState = Constants.IPlayerState.DISCARD;
//弃牌之后,在玩的玩家数减一
LiveCount--;
//当前玩家索引指向下一个
break;
}
} else {
Util.show(true, true, Constants.IBet.NORMAL);
//获取当前玩家信息
Util.show("请" + player.id + "号玩家选择操作(" + player.name + " $" + player.chips + "):");
//接收用户输入
int choice = input(2, 1);
System.out.println(choice);
switch (choice) {
case 1:
Bet(player);
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
//弃牌
player.playState = Constants.IPlayerState.DISCARD;
//弃牌之后,在玩的玩家数减一
LiveCount--;
//当前玩家索引指向下一个
}
break;
}
currentPlayerIndex++;
if(currentPlayerIndex>totalPlayer){
currentPlayerIndex=1;
}
}
//游戏结束
playerManager.awardPlayer(ante);
System.out.println(playerManager.players);
}
因为不论玩家的金币不论是多于还是低于前一个人的赌注,都有弃牌这个功能,所以我们另外写一个函数来表示弃牌。前面直接调用这个函数即可,写在PokerGameCenter类里面
//弃牌
private void giveup(Player player){
player.playState = Constants.IPlayerState.DISCARD;
//弃牌之后,在玩的玩家数减一
LiveCount--;
}
跟注我们也可以写一个函数,然后直接调用即可,写在PokerGameCenter类里面
//跟注
private void follow(Player player){
//总金额增加
ante+=LastPlayerBet;
//扣除这个人的筹码
player.LostMoney(LastPlayerBet);
}
12.实现all-in
这个我们也是在PokerGameCenter类里面写一个allin函数即可
原理:当一个人选择all-in,只需要比较一次,最大的赢。如果有任何一个人选择了all-in,就要提示后面的人要all-in还是弃牌,只有这两种选择。所以我们定义一个变量记录玩家是否选择了all-in,并且初始化为false(在InitGame函数里初始化),再定义一个变量来记录AllinPosition来记录all-in的位置,先让它=currentPlayerIndex(在All-in函数里赋值)。
private boolean Allin;
private int AllinPosition;
在satrtbets函数里的循环开始的时候,我们要先判断currentPlayerIndex与AllinPosition是否相等,然后比较大小,比较大小这个方法写在Poker类里面
//比较两张牌的大小
public int Compare(Poker another){
if( this.type.tag>another.type.tag){
return 1;
}else{
return -1;
}
}
在PlayerManager类里面添加一个奖励赢家的方法
public void awardPlayer(int money,int smallestAllinBet) {
Player max = null;
for (Player player : players) {
if (player.playState == Constants.IPlayerState.HAND) {
if (max == null) {
//找到第一个没有弃牌的人
max=player;
}
else
{
int result= max.poker.Compare(player.poker);
if(result==-1){
//max记录最大的那个玩家
max=player;
}
}
}
}
//让最大的人赢钱
max.WinMoney(money);
}
如果有多个人选择all-in,定义一个变量记录最小的下注金额(在PokerGameCenter类里面)
private int smallestAllinBet;
如果有多人all-in,其中有玩家的总金币多于smallestBet,那么多于的钱就需要返回给玩家,在Player类里面添加一个还钱方法
//还钱
public void returnMoney(int couut){
chips+=couut;
}
同时在awardPlayer方法里面添加退钱的代码,首先判断all-in的人数,再进行比较
//没人all-in
if(smallestAllinBet==0){
return;
}
//将max之外所有多于all-in的人的钱返还
int totalReturn=0;
for(Player player:players){
//找到没有弃牌并且不是当前最大的那个人
if(!player.equals(max)&&player.playState==Constants.IPlayerState.HAND){
player.returnMoney(player.currentBet-smallestAllinBet);
totalReturn+=(player.currentBet-smallestAllinBet);
}
}
//从max中退回多余的钱
max.LostMoney(totalReturn);
因为索引值+1这个需要多次使用,所以我们将它写成一个方法在PokerGameCenter类里面
private void changeCurrentIndex(){
//当前玩家索引值指向下一个
currentPlayerIndex++;
if(currentPlayerIndex>totalPlayer){
currentPlayerIndex=1;
}
}
同时在satrtBet方法也需要修改一下,在获取一个玩家的信息之后要先判断其是否弃牌,如果弃牌那么之后所有的case操作都没必要进行
//判断当前这个人是否已经弃牌
if(player.playState==Constants.IPlayerState.DISCARD){
//这个人已经弃牌,下面的不用做
changeCurrentIndex();
continue;
}
那么all-in函数的完整代码如下
private void allin(Player player){
if(Allin){
//比较两个All-in从值
if(player.chips<smallestAllinBet){
smallestAllinBet=player.chips;
}
}else {
//第一个人第一次all-in,记录当前最小值
Allin=true;
smallestAllinBet=player.chips;
//记录当前all-in起始点
AllinPosition=currentPlayerIndex;
}
//当前这个人all-in
player.currentBet=player.chips;
//总金额
ante+=player.chips;
//下注所有
player.LostMoney(player.chips);
}
那么我们所有的功能都已经实现了,只需要在主函数里面创建按一个对象即可
public class MyClass {
public static void main(String[] args) {
PokerGameCenter center = PokerGameCenter.GetInstance();
}
}
C5H}Q97{FOHM6(C_0IR1WN8.png之后我们运行这段代码,就会显示一下内容
IY9AL1%2WN3AT_Z{3H5FPLK.png
然后选择你想要的操作即可,这就是我们今天的全部内容了,我会将所有的源代码放在最后
public abstract class AGameCenter implements IGameInitListener {
private int totalSuccess;
protected PlayerManager playerManager;
protected PokerManager pokerManager;
protected int ante;//台面的总金额
protected int totalPlayer;
protected int Bottom;//底注
protected AGameCenter(){
//初始化游戏本身的数据
initGame();
//初始化玩家
initPlayers();
//初始化扑克
initPokers();
}
protected abstract void initGame();
protected abstract void initPokers();
protected abstract void initPlayers();
protected abstract void start();
@Override
public void onInitSuccess() {
//对成功的计数器+1
setTotalSuccess(getTotalSuccess()+1);
}
@Override
public void onInitFailure() {
}
public void setTotalSuccess(int totalSuccess) {
this.totalSuccess = totalSuccess;
if(totalSuccess==3){
start();
}
}
public int getTotalSuccess() {
return totalSuccess;
}
}
public interface IGameInitListener {
void onInitSuccess();
void onInitFailure();
}
public class PokerGameCenter extends AGameCenter {
private int LiveCount;
private static PokerGameCenter Instance;//实例化一个对象
private int currentPlayerIndex;
private int LastPlayerBet;
private boolean Allin;
private int AllinPosition;
private int smallestAllinBet;
private PokerGameCenter(){
}
public static PokerGameCenter GetInstance(){
if(Instance==null){
synchronized (PokerGameCenter.class){
if(Instance==null){
Instance=new PokerGameCenter();
}
}
}
return Instance;
}
@Override
protected void initGame() {
//创建对象
playerManager=playerManager.GetManager();
pokerManager=pokerManager.GetManager();
ante=0;
totalPlayer=3;
Bottom=5;
Allin=false;
currentPlayerIndex=1;
LiveCount=totalPlayer;
//设置监听者
playerManager.setListener(this);
pokerManager.setListener(this);
//初始化完毕,成功的计数器+1
setTotalSuccess(getTotalSuccess()+1);
}
@Override
protected void initPokers() {
pokerManager.InitPokers();
}
@Override
protected void initPlayers() {
playerManager.InitPlayers(totalPlayer);
}
@Override
protected void start() {
//先扣底注钱
PlayerManager.GetManager().DeductMoney(Bottom);
ante=totalPlayer*Bottom;
//实现发牌
dealCards();
//开始下注
startBets();
}
//下注
private void startBets(){
while(LiveCount>1) {
if(currentPlayerIndex==AllinPosition){
//直接比大小
break;
}
//判断当前这个人的提示信息
Player player = playerManager.getPlayer(currentPlayerIndex - 1);
//判断当前这个人是否已经弃牌
if(player.playState==Constants.IPlayerState.DISCARD){
//这个人已经弃牌,下面的不用做
changeCurrentIndex();
continue;
}
if (player.chips <= LastPlayerBet) {
Util.show(true, true, Constants.IBet.LESS);
//获取当前玩家信息
Util.show("请" + player.id + "号玩家选择操作(" + player.name + " $" + player.chips + "):");
//接收用户输入
int choice = input(2, 1);
System.out.println(choice);
switch (choice) {
case 1:
//all-in
allin(player);
break;
case 2:
//弃牌
giveup(player);
break;
}
} else {
Util.show(true, true, Constants.IBet.NORMAL);
//获取当前玩家信息
Util.show("请" + player.id + "号玩家选择操作(" + player.name + " $" + player.chips + "):");
//接收用户输入
int choice = input(2, 1);
System.out.println(choice);
switch (choice) {
case 1:
//下注
Bet(player);
break;
case 2:
//跟注
follow(player);
break;
case 3:
//all-in
allin(player);
break;
case 4:
//比牌
break;
case 5:
//弃牌
giveup(player);
break;
}
changeCurrentIndex();
}
}
//游戏结束
playerManager.awardPlayer(ante,smallestAllinBet);
System.out.println(playerManager.players);
}
//跟注
private void follow(Player player){
//总金额增加
ante+=LastPlayerBet;
//扣除这个人的筹码
player.LostMoney(LastPlayerBet);
}
//all-in
private void allin(Player player){
if(Allin){
//比较两个All-in从值
if(player.chips<smallestAllinBet){
smallestAllinBet=player.chips;
}
}else {
//第一个人第一次all-in,记录当前最小值
Allin=true;
smallestAllinBet=player.chips;
//记录当前all-in起始点
AllinPosition=currentPlayerIndex;
}
//当前这个人all-in
player.currentBet=player.chips;
//总金额
ante+=player.chips;
//下注所有
player.LostMoney(player.chips);
}
//下注
private void Bet(Player player){
Util.show("请输入下注金额:");
int total= input(player.chips,LastPlayerBet);
//总金额增加
ante+=total;
//扣除这个人的筹码
player.LostMoney(total);
//记录这次下注金额
LastPlayerBet=total;
}
private int input(int max,int min) {
while (1 > 0) {
Scanner scanner=new Scanner(System.in);
int num = scanner.nextInt();
if (num >= min || num <= min) {
return num;
}
Util.show("输入数据不正确,请重新输入");
}
}
private void dealCards () {
int count = playerManager.getPlayerCount();
for (int i = 0; i < count; i++) {
//从扑克中心获取一张牌
Poker poker = PokerManager.GetManager().getOnePoker();
//将这张牌发给对应的人
Player player = PlayerManager.GetManager().getPlayer(i);
player.poker = poker;
}
System.out.println(playerManager.players);
}
//弃牌
private void giveup(Player player){
player.playState = Constants.IPlayerState.DISCARD;
//弃牌之后,在玩的玩家数减一
LiveCount--;
}
private void changeCurrentIndex(){
//当前玩家索引值指向下一个
currentPlayerIndex++;
if(currentPlayerIndex>totalPlayer){
currentPlayerIndex=1;
}
}
}
public class Player {
public int id;//编号
public String name;//名字
public int chips;//筹码
public Poker poker;//手上的一张牌
public ArrayList<Poker> pokers;//手上有很多张牌
public int playState;//玩家的状态
public int currentBet;//记录当前下注金额
public Player(int id, String name, int chips) {
this.id = id;
this.name = name;
this.chips = chips;
playState=Constants.IPlayerState.HAND;//初始化状态
}
//扣钱
public void LostMoney(int count){
chips-=count;
}
//加钱
public void WinMoney(int count){
chips+=count;
}
//还钱
public void returnMoney(int couut){
chips+=couut;
}
@Override
public String toString() {
return "id:"+id+" name "+name+" "+poker.dot+poker.type.pic+"("+chips+")";
}
}
public class PlayerManager {
private IGameInitListener Listener;
private static PlayerManager manager;
public ArrayList<Player> players;
private PlayerManager(){
}
public static PlayerManager GetManager(){
if(manager==null){
synchronized (PlayerManager.class){
if (manager==null){
manager=new PlayerManager();
}
}
}
return manager;
}
//初始化玩家
public void InitPlayers(int totalPlayer){
//创建输出
players=new ArrayList<>();
for(int i=0;i<totalPlayer;i++){
//获取玩家名字
String name=Util.AutoGeneName();
//创建玩家对象
Player player=new Player(i+1,name, Constants.IPlayer.chips);
//保存玩家
players.add(player);
}
//当玩家初始化成功就回调成功的事件给监听者(游戏中心)
if(Listener!=null){
Listener.onInitSuccess();
}
}
//所有玩家扣钱
public void DeductMoney(int count){
for(Player player:players){
player.LostMoney(count);
}
}
public int getPlayerCount(){
return players.size();
}
//获取一个玩家
public Player getPlayer(int index){
return players.get(index);
}
public void awardPlayer(int money,int smallestAllinBet) {
Player max = null;
for (Player player : players) {
if (player.playState == Constants.IPlayerState.HAND) {
if (max == null) {
//找到第一个没有弃牌的人
max=player;
}
else
{
int result= max.poker.Compare(player.poker);
if(result==-1){
//max记录最大的那个玩家
max=player;
}
}
}
}
//让最大的人赢钱
max.WinMoney(money);
//没人all-in
if(smallestAllinBet==0){
return;
}
//将max之外所有多于all-in的人的钱返还
int totalReturn=0;
for(Player player:players){
//找到没有弃牌并且不是当前最大的那个人
if(!player.equals(max)&&player.playState==Constants.IPlayerState.HAND){
player.returnMoney(player.currentBet-smallestAllinBet);
totalReturn+=(player.currentBet-smallestAllinBet);
}
}
//从max中退回多余的钱
max.LostMoney(totalReturn);
}
public void setListener(IGameInitListener listener) {
Listener = listener;
}
}
public class Poker {
public String dot;//管理牌的点数
public PicType type;//花色对象
public Poker(String dot, PicType type) {
this.dot = dot;
this.type = type;
}
public static class PicType{
public String pic;//管理花色
public int tag;//花色对应的tag值
//
public static final PicType SPADE=new PicType("♠",4);
public static final PicType HEARTS=new PicType("♥",3);
public static final PicType CLUBS=new PicType("♣",2);
public static final PicType DIAMONDS=new PicType("♦",1);
public PicType(String pic, int tag) {
this.pic = pic;
this.tag = tag;
}
}
//比较两张牌的大小
public int Compare(Poker another){
if( this.type.tag>another.type.tag){
return 1;
}else{
return -1;
}
}
@Override
public String toString() {
return dot+type.pic;
}
}
public class PokerManager {
private IGameInitListener Listener;
private ArrayList<Poker> pokers;
private static PokerManager manager;
private PokerManager(){
}
public static PokerManager GetManager(){
if(manager==null){
synchronized (PokerManager.class){
if (manager==null){
manager=new PokerManager();
}
}
}
return manager;
}
public void InitPokers(){
//初始化数组对象
pokers=new ArrayList<>();
//创建扑克牌
for(String dot: Constants.IPoker.DOTS){
//这样就取出来了一张牌,之后选择花色
for(Poker.PicType type:Constants.IPoker.PIC_TYPES){
//创建一张牌
Poker poker=new Poker(dot,type);
//添加到数组中保存
pokers.add(poker);
}
}
//打乱顺序-洗牌
Collections.shuffle(pokers);
//当扑克牌初始化成功就回调成功的事件给监听者(游戏中心)
if(Listener!=null){
Listener.onInitSuccess();
}
}
public Poker getOnePoker(){
//因为牌已经被打乱了,所以获取第一张,再将其删除即可
if(pokers.size()>0){
Poker poker=pokers.get(0);
//将这张牌从数组里面删除
pokers.remove(0);
return poker;
}
return null;
}
public void setListener(IGameInitListener listener) {
Listener = listener;
}
}
public interface Constants {
interface IBet{
String [] NORMAL =new String[]{"下注 2.跟注 3.pall-in 4.比牌 5.弃牌"};
String [] LESS= new String[]{"all-in,弃牌"};
}
interface IPlayer{
int chips=1000;
}
interface IPlayerName{
String [] NAMES_XING={"赵","钱","孙","李","周","吴","郑","王","冯"};
String [] NAMES_MING1={"子","秋","鹤","文","泽","凯","元","建","可"};
String [] NAMES_MING2={"豪","月","雪","晨","岚","峥","瑶","欣","阳"};
}
interface IPlayerState{
int HAND=0;//还在玩
int DISCARD=1;//弃牌
}
//扑克使用的常量
interface IPoker{
//点数
String[] DOTS={"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
//四种花色,给每一个花色都匹配一个tag值
Poker.PicType[] PIC_TYPES={Poker.PicType.SPADE,Poker.PicType.HEARTS,
Poker.PicType.CLUBS, Poker.PicType.DIAMONDS};
}
}
public class Util {
/**
* 自动生成名字
*/
public static String AutoGeneName(){
Random random=new Random();
//姓名的随机数
int x_index=Math.abs(random.nextInt()%Constants.IPlayerName.NAMES_XING.length);
int m_index=Math.abs( random.nextInt()%Constants.IPlayerName.NAMES_MING1.length);
int l_index=Math.abs( random.nextInt()%Constants.IPlayerName.NAMES_MING2.length);
String f= Constants.IPlayerName.NAMES_XING[x_index]+
Constants.IPlayerName.NAMES_MING1[m_index]+
Constants.IPlayerName.NAMES_MING2[l_index];
return f;
}
/**
*输出语句
*/
public static void show (boolean nextLine,boolean needNumber,String...args) {
StringBuilder builder=new StringBuilder();
if (needNumber) {
for (int i = 0; i < args.length; i++) {
String content = (i + 1) + "." + args[i]+" ";//1.下注2.跟注等
builder.append(content);//把数组里面的都追加过来
}
}else{
for(String content:args){
builder.append(content+" ");
}
}
if(nextLine){
System.out.println(builder.toString());
}else{
System.out.print(builder.toString());
}
}
//输出一行不换行,不需要编号的数据
public static void show(String content){
Util.show(false,false,new String[]{content});
}
}
public class MyClass {
public static void main(String[] args) {
PokerGameCenter center = PokerGameCenter.GetInstance();
}
}