本節(jié)內(nèi)容
1.游戲架構(gòu)和功能
2.游戲功能的具體實(shí)現(xiàn)
注:解說以下代碼是按照寫代碼的過程以及思路順序來講解的,所以以文字順序?yàn)橹鳎渲形淖指綆Р糠执a。所有的源代碼在最末尾。
一、游戲架構(gòu)和功能
(一)游戲過程:
1.設(shè)置參與的人數(shù),并給每個人設(shè)置名字(ID號)、序號(某一桌)和初始金幣
2.設(shè)置本局消耗金幣(底注),相當(dāng)于選擇不同等級的房間
3.開始玩游戲。每個人下底注(比如5塊,10塊等),然后給每個人發(fā)張牌(或者多張牌,根據(jù)游戲規(guī)則決定),之后按照順序下注(①->②->③),當(dāng)前下注的人可以選擇{①下注:自由下注,不能比上個玩家少,也不能多于自己的金幣。②跟注:上個玩家下注多少就下注多少。③all-in:自己有多少就下多少。如果他的總金幣比上一個玩家下的注要少,那么就按他的注來,并退還前面玩家的下注差(比如1,2號下注20,三號只有all-in15,那么就會退還1,2號5個金幣)④比牌(前提是玩法只有一張牌):和另外一位玩家比牌,不管輸贏。⑤棄牌:放棄},依次下注,只剩一人時游戲結(jié)束
4.一局游戲結(jié)束,顯示當(dāng)前所有玩家的金幣信息
(二)該游戲里的對象
1.玩家
2.牌
3.游戲中心(在哪里玩,QQ或者微信等)
4.玩家的管理者
5.撲克的管理者
6.規(guī)則:先比大小,再比花色(黑?>紅?梅?>方?)ASCII值分別為(6,3,5,4)所以用ASCII不太方便,所以我們可以自己給黑紅梅方設(shè)值
(三)寫代碼之前需要以下步驟
找對象抽類——>理清類與類之間的關(guān)系——>UML畫圖/架構(gòu)
具體架構(gòu):游戲中心(Game Center)管理Poker Manager和Play Manager類。
由Poker管理一張牌,在Poker類里面有(設(shè)置內(nèi)部類PokerType包含屬性dot、pic Type和tag int(給黑紅梅方設(shè)值,這樣在比較花色的時候直接比較tag值即可),內(nèi)部類之外有pic 和dot 以及compare方法,開牌比較大小)。
由PokerManager來管理一副牌(有一個數(shù)組保存所有的牌,有一些方法來初始化一副牌,以及獲取一張牌等)。游戲中心(Game Center)發(fā)牌的時候就會從PokerManager里面拿牌
Player類:包含玩家的編號,姓名,籌碼,是否棄牌(使用接口),玩家的一張牌,玩家的副牌,還有方法(贏錢,輸錢,下注,退還錢如何計(jì)算)
PlayManager類:包含初始化所有玩家,獲取一個玩家等方法
Game Center類:包含屬性當(dāng)前臺面上的總金額,button(每局的賭注),CurrentPlayer(當(dāng)前玩家),還有其他類的對象。一些方法,初始化數(shù)據(jù),開始游戲,游戲結(jié)束。
定義一個iGame接口來判斷Game Center類里面初始化是否成功,并回調(diào)數(shù)據(jù)給游戲中心
二、撲克游戲具體實(shí)現(xiàn)
1.創(chuàng)建AGameCenter的抽象類和單例,直接在構(gòu)造函數(shù)里面設(shè)計(jì)好執(zhí)行的順序,先初始化數(shù)據(jù),然后是玩家,最后是撲克,后面補(bǔ)充它們的抽象方法和其他方法
public abstract class AGameCenter implements IGameInitListener{
private int totalSuccess;
protected PlayerManager playerManager;
protected PokerManager pokerManager;
protected int ante;//臺面的總金額
protected int totalPlayer;//玩家人數(shù)
protected int Button;//底注
protected AGameCenter(){
//初始化游戲本身的數(shù)據(jù)
initGame();
//初始化玩家
initPlayers();
//初始化撲克
initPokers();
}
protected abstract void initGame();
protected abstract void initPokers();
protected abstract void initPlayers();
protected abstract void start();
@Override
public void onInitSuccess() {
//對成功的計(jì)數(shù)器+1
setTotalSuccess(getTotalSuccess()+1);
}
@Override
public void onInitFailure() {
}
public void setTotalSuccess(int totalSuccess) {
this.totalSuccess = totalSuccess;
if(totalSuccess==3){//因?yàn)橐跏蓟危酝ㄟ^totalSuccess是不是等于三來判斷初始化是否成功
start();
}
}
public int getTotalSuccess() {
return totalSuccess;
}
}
2.創(chuàng)建一個IGameInitListener的接口來判斷初始化是否成功
public interface IGameInitListener {
void onInitSuccess();
void onInitFailure();
}
3.創(chuàng)建一個PokerGameCenter類,也就是游戲中心,采用單例設(shè)計(jì)模式,所以最開始要創(chuàng)建一個靜態(tài)對象
public class PokerGameCenter extends AGameCenter{
private static PokerGameCenter Instance;//實(shí)例化一個對象
private int LiveCount;
private int currentPlayerIndex;
private PokerGameCenter(){//構(gòu)造方法
}
public static PokerGameCenter GetInstance(){
if(Instance==null){
synchronized (PokerGameCenter.class){
if(Instance==null){
Instance=new PokerGameCenter();
}
}
}
return Instance;
}
@Override
protected void initGame() {
//創(chuàng)建對象
playerManager=playerManager.GetManager();
pokerManager=pokerManager.GetManager();
ante=0;
totalPlayer=3;
Bottom=5;
currentPlayerIndex=1;
LiveCount=totalPlayer;
//設(shè)置監(jiān)聽者
playerManager.setListener(this);
pokerManager.setListener(this);
//初始化完畢,成功的計(jì)數(shù)器+1
setTotalSuccess(getTotalSuccess()+1);
}
@Override
protected void initPokers() {
pokerManager.InitPokers();
}
@Override
protected void initPlayers() {
playerManager.InitPlayers();
}
@Override
protected void start() {
//先扣底注錢
PlayerManager.GetManager().DeductMoney(Bottom);
//實(shí)現(xiàn)發(fā)牌
dealCards();
//開始下注
startBets();
}
}
4.創(chuàng)建管理類實(shí)現(xiàn)接口回調(diào)
①創(chuàng)建一個PokerManager類來管理一副牌,因?yàn)橛玫氖菃卫O(shè)計(jì)模式,所以需要設(shè)置一個靜態(tài)對象,并且私有化構(gòu)造方法,用接口創(chuàng)建了一個對象Listener來方便將對象創(chuàng)建成功的事件返回給監(jiān)聽者(游戲中心)注:在創(chuàng)建了Poker類之后就可以實(shí)現(xiàn)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(){
//初始化數(shù)組對象
pokers=new ArrayList<>();
//創(chuàng)建撲克牌
for(String dot: Constants.IPoker.DOTS){
//這樣就取出來了一張牌,之后選擇花色
for(Poker.PicType type:Constants.IPoker.PIC_TYPES){
//創(chuàng)建一張牌
Poker poker=new Poker(dot,type);
//添加到數(shù)組中保存
pokers.add(poker);
}
}
//當(dāng)撲克牌初始化成功就回調(diào)成功的事件給監(jiān)聽者(游戲中心)
if(Listener!=null){
Listener.onInitSuccess();
}
}
public void setListener(IGameInitListener listener) {
Listener = listener;
}
}
②創(chuàng)建一個PlayerManager類來管理許多玩家,采用的也是單例設(shè)計(jì)模式,其他原理同上
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(){
//當(dāng)玩家初始化成功就回調(diào)成功的事件給監(jiān)聽者(游戲中心)
if(Listener!=null){
Listener.onInitSuccess();
}
}
//獲取一個玩家
public Player getPlayer(int index){
return players.get(index);
}
}
public void setListener(IGameInitListener listener) {
Listener = listener;
}
}
5.創(chuàng)建一副牌
先創(chuàng)建一個Constants接口來記錄牌的點(diǎn)數(shù)和花色
public interface Constants {
interface IPlayer{
int chips=1000;
}
interface IPlayerName{
String [] NAMES_XING={"趙","錢","孫","李","周","吳","鄭","王","馮"};
String [] NAMES_MING1={"子","秋","鶴","文","澤","凱","元","建","可"};
String [] NAMES_MING2={"豪","月","雪","晨","嵐","崢","瑤","欣","陽"};
}
//撲克使用的常量
interface IPoker{
//點(diǎn)數(shù)
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};
}
}
創(chuàng)建一個Poker類,再在這個類里面創(chuàng)建一個內(nèi)部類PicType來管理牌的花色和tag值,tag值是為了方便比較花色大小所以自己給花色賦的值。因?yàn)榛ㄉ枪潭ú蛔兊模钥梢远x四個靜態(tài)變量來表示四種不同的花色。另外構(gòu)造方法是必要的。
public class Poker {
public String dot;//管理牌的點(diǎn)數(shù)
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;//花色對應(yīng)的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.創(chuàng)建玩家,自動生成名字
現(xiàn)在可以在AGameCenter里面添加一個變量來記錄人數(shù),并在PokerGamecenter類里面初始化為3
protected int totalPlayer;//玩家人數(shù)
然后創(chuàng)建一個玩家Player類,里面有很多不同的屬性(名字,編號等),在記錄是否棄牌時,就需要在Constants里面添加一個內(nèi)部接口記錄玩家的狀態(tài)
interface IPlayerState{
int HAND=0;//還在玩
int DISCARD=1;//棄牌
}
創(chuàng)建一個Player類,里面包含玩家的一些屬性,其中編號,名字和籌碼可以直接知道就可以寫在一個構(gòu)造方法里面,代碼如下
public class Player {
public int id;//編號
public String name;//名字
public int chips;//籌碼
public Poker poker;//手上的一張牌
public ArrayList<Poker> pokers;//手上有很多張牌
public int playState;//玩家的狀態(tài)
public Player(int id, String name, int chips) {
this.id = id;
this.name = name;
this.chips = chips;
playState=Constants.IPlayerState.HAND;//初始化狀態(tài)
}
}
創(chuàng)建一個Util類來隨機(jī)生成名字,因?yàn)閿?shù)組下標(biāo)必為整數(shù),所以用MAth.abs()函數(shù)取隨機(jī)數(shù)的絕對值
public class Util {
public static String AutoGeneName(){
Random random=new Random();
//姓名的隨機(jī)數(shù)
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);//把數(shù)組里面的都追加過來
}
}else{
for(String content:args){
builder.append(content+" ");
}
}
if(nextLine){
System.out.println(builder.toString());
}else{
System.out.print(builder.toString());
}
}
//輸出一行不換行,不需要編號的數(shù)據(jù)
public static void show(String content){
Util.show(false,false,new String[]{content});
}
}
7.發(fā)牌
需要先設(shè)置一個底注Bottom,在AGameCenter類里面定義,在PokerGameCenter類里面初始化
protected int Button;//底注
在發(fā)牌之前需要先扣錢,先在Player類里面定義一個扣錢的方法Lost Money,在PlayerManager類里面寫一個DeductMoney方法扣錢,遍歷每個數(shù)組并調(diào)用LostMoney方法
//扣錢
public void LostMoney(int count){
chips-=count;
}
//所有玩家扣錢
public void DeductMoney(int count){
for(Player player:players){
player.LostMoney(count);
}
}
開始發(fā)牌,需要在PokerManager類里面添加一個getOnePoker方法來獲取一張牌,因?yàn)榕频捻樞蛞呀?jīng)是亂的,所以每次選擇牌的第一張即可,并且刪除這張牌(以免后面的玩家抽到一樣的牌)。
然后在PokerGameCenter類實(shí)現(xiàn)start方法實(shí)現(xiàn)發(fā)牌,每次發(fā)一張牌,調(diào)用getOnePoker方法,并將這張牌發(fā)給對應(yīng)的人。創(chuàng)建一副牌之后還得打亂順序
public Poker getOnePoker(){
//因?yàn)榕埔呀?jīng)被打亂了,所以獲取第一張,再將其刪除即可
if(pokers.size()>0){
Poker poker=pokers.get(0);
//將這張牌從數(shù)組里面刪除
pokers.remove(0);
return poker;
}
return null;
}
//打亂順序-洗牌
Collections.shuffle(pokers);
8.包裝輸出語句
在下注之前我們要顯示玩家的選擇,先在PokerGameCenter類里面的start方法里面添加一個下注的函數(shù),然后在start方法外實(shí)現(xiàn)這個函數(shù)。在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);//把數(shù)組里面的都追加過來
}
}else{
for(String content:args){
builder.append(content+" ");
}
}
if(nextLine){
System.out.println(builder.toString());
}else{
System.out.print(builder.toString());
}
}
9.顯示提示內(nèi)容接收選擇
在PokerGameCenter類我們要實(shí)現(xiàn)startBets方法,顯示內(nèi)容,那我們就在Util類里添加了一個show函數(shù),然后在startBets方法里調(diào)用這個函數(shù).
//輸出一行不換行,不需要編號的數(shù)據(jù)
public static void show(String content){
Util.show(false,false,new String[]{content});
}
在用戶選擇后我們需要寫一個方法來接收用戶的輸入,將這個input方法直接寫在PoerkGameCenter類里面,還需要一個一個方法來發(fā)牌,同樣寫在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("輸入數(shù)據(jù)不正確,請重新輸入");
}
private void dealCards () {
int count = playerManager.getPlayerCount();
for (int i = 0; i < count; i++) {
//從撲克中心獲取一張牌
Poker poker = PokerManager.GetManager().getOnePoker();
//將這張牌發(fā)給對應(yīng)的人
Player player = PlayerManager.GetManager().getPlayer(i);
player.poker = poker;
}
System.out.println(playerManager.players);
}
}
10.實(shí)現(xiàn)棄牌和下注
某個玩家棄牌后,當(dāng)前在玩人數(shù)減一,同時玩家的索引值加一,并判斷索引值是否超過在玩人數(shù),如果超過,索引值就初始化為1
case 5:
//棄牌
player.playState= Constants.IPlayerState.DISCARD;
//棄牌之后,在玩的玩家數(shù)減一
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里調(diào)用這個函數(shù),因?yàn)槊看蜗伦⒍家壬弦粋€玩家多,所以定義一個變量來記錄上一個玩家下的注。
//下注
private void Bet(Player player){
Util.show("請輸入下注金額:");
int total= input(player.chips,LastPlayerBet);
//總金額增加
ante+=total;
//扣除這個人的籌碼
player.LostMoney(total);
//記錄這次下注金額
LastPlayerBet=total;
}
11.實(shí)現(xiàn)不同狀態(tài)的提示和跟注
如果一個人的所有的金幣都少于前一個人的賭注,那么這個時候他只有兩種選擇,一種是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) {
//判斷當(dāng)前這個人的提示信息
Player player = playerManager.getPlayer(currentPlayerIndex - 1);
if (player.chips <= LastPlayerBet) {
Util.show(true, true, Constants.IBet.LESS);
//獲取當(dāng)前玩家信息
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;
//棄牌之后,在玩的玩家數(shù)減一
LiveCount--;
//當(dāng)前玩家索引指向下一個
break;
}
} else {
Util.show(true, true, Constants.IBet.NORMAL);
//獲取當(dāng)前玩家信息
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;
//棄牌之后,在玩的玩家數(shù)減一
LiveCount--;
//當(dāng)前玩家索引指向下一個
}
break;
}
currentPlayerIndex++;
if(currentPlayerIndex>totalPlayer){
currentPlayerIndex=1;
}
}
//游戲結(jié)束
playerManager.awardPlayer(ante);
System.out.println(playerManager.players);
}
因?yàn)椴徽撏婕业慕饚挪徽撌嵌嘤谶€是低于前一個人的賭注,都有棄牌這個功能,所以我們另外寫一個函數(shù)來表示棄牌。前面直接調(diào)用這個函數(shù)即可,寫在PokerGameCenter類里面
//棄牌
private void giveup(Player player){
player.playState = Constants.IPlayerState.DISCARD;
//棄牌之后,在玩的玩家數(shù)減一
LiveCount--;
}
跟注我們也可以寫一個函數(shù),然后直接調(diào)用即可,寫在PokerGameCenter類里面
//跟注
private void follow(Player player){
//總金額增加
ante+=LastPlayerBet;
//扣除這個人的籌碼
player.LostMoney(LastPlayerBet);
}
12.實(shí)現(xiàn)all-in
這個我們也是在PokerGameCenter類里面寫一個allin函數(shù)即可
原理:當(dāng)一個人選擇all-in,只需要比較一次,最大的贏。如果有任何一個人選擇了all-in,就要提示后面的人要all-in還是棄牌,只有這兩種選擇。所以我們定義一個變量記錄玩家是否選擇了all-in,并且初始化為false(在InitGame函數(shù)里初始化),再定義一個變量來記錄AllinPosition來記錄all-in的位置,先讓它=currentPlayerIndex(在All-in函數(shù)里賦值)。
private boolean Allin;
private int AllinPosition;
在satrtbets函數(shù)里的循環(huán)開始的時候,我們要先判斷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的人數(shù),再進(jìn)行比較
//沒人all-in
if(smallestAllinBet==0){
return;
}
//將max之外所有多于all-in的人的錢返還
int totalReturn=0;
for(Player player:players){
//找到?jīng)]有棄牌并且不是當(dāng)前最大的那個人
if(!player.equals(max)&&player.playState==Constants.IPlayerState.HAND){
player.returnMoney(player.currentBet-smallestAllinBet);
totalReturn+=(player.currentBet-smallestAllinBet);
}
}
//從max中退回多余的錢
max.LostMoney(totalReturn);
因?yàn)樗饕?1這個需要多次使用,所以我們將它寫成一個方法在PokerGameCenter類里面
private void changeCurrentIndex(){
//當(dāng)前玩家索引值指向下一個
currentPlayerIndex++;
if(currentPlayerIndex>totalPlayer){
currentPlayerIndex=1;
}
}
同時在satrtBet方法也需要修改一下,在獲取一個玩家的信息之后要先判斷其是否棄牌,如果棄牌那么之后所有的case操作都沒必要進(jìn)行
//判斷當(dāng)前這個人是否已經(jīng)棄牌
if(player.playState==Constants.IPlayerState.DISCARD){
//這個人已經(jīng)棄牌,下面的不用做
changeCurrentIndex();
continue;
}
那么all-in函數(shù)的完整代碼如下
private void allin(Player player){
if(Allin){
//比較兩個All-in從值
if(player.chips<smallestAllinBet){
smallestAllinBet=player.chips;
}
}else {
//第一個人第一次all-in,記錄當(dāng)前最小值
Allin=true;
smallestAllinBet=player.chips;
//記錄當(dāng)前all-in起始點(diǎn)
AllinPosition=currentPlayerIndex;
}
//當(dāng)前這個人all-in
player.currentBet=player.chips;
//總金額
ante+=player.chips;
//下注所有
player.LostMoney(player.chips);
}
那么我們所有的功能都已經(jīng)實(shí)現(xiàn)了,只需要在主函數(shù)里面創(chuàng)建按一個對象即可
public class MyClass {
public static void main(String[] args) {
PokerGameCenter center = PokerGameCenter.GetInstance();
}
}
之后我們運(yùn)行這段代碼,就會顯示一下內(nèi)容
C5H}Q97{FOHM6(C_0IR1WN8.png
IY9AL1%2WN3AT_Z{3H5FPLK.png
然后選擇你想要的操作即可,這就是我們今天的全部內(nèi)容了,我會將所有的源代碼放在最后
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(){
//初始化游戲本身的數(shù)據(jù)
initGame();
//初始化玩家
initPlayers();
//初始化撲克
initPokers();
}
protected abstract void initGame();
protected abstract void initPokers();
protected abstract void initPlayers();
protected abstract void start();
@Override
public void onInitSuccess() {
//對成功的計(jì)數(shù)器+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;//實(shí)例化一個對象
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() {
//創(chuàng)建對象
playerManager=playerManager.GetManager();
pokerManager=pokerManager.GetManager();
ante=0;
totalPlayer=3;
Bottom=5;
Allin=false;
currentPlayerIndex=1;
LiveCount=totalPlayer;
//設(shè)置監(jiān)聽者
playerManager.setListener(this);
pokerManager.setListener(this);
//初始化完畢,成功的計(jì)數(shù)器+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;
//實(shí)現(xiàn)發(fā)牌
dealCards();
//開始下注
startBets();
}
//下注
private void startBets(){
while(LiveCount>1) {
if(currentPlayerIndex==AllinPosition){
//直接比大小
break;
}
//判斷當(dāng)前這個人的提示信息
Player player = playerManager.getPlayer(currentPlayerIndex - 1);
//判斷當(dāng)前這個人是否已經(jīng)棄牌
if(player.playState==Constants.IPlayerState.DISCARD){
//這個人已經(jīng)棄牌,下面的不用做
changeCurrentIndex();
continue;
}
if (player.chips <= LastPlayerBet) {
Util.show(true, true, Constants.IBet.LESS);
//獲取當(dāng)前玩家信息
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);
//獲取當(dāng)前玩家信息
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();
}
}
//游戲結(jié)束
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,記錄當(dāng)前最小值
Allin=true;
smallestAllinBet=player.chips;
//記錄當(dāng)前all-in起始點(diǎn)
AllinPosition=currentPlayerIndex;
}
//當(dāng)前這個人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("輸入數(shù)據(jù)不正確,請重新輸入");
}
}
private void dealCards () {
int count = playerManager.getPlayerCount();
for (int i = 0; i < count; i++) {
//從撲克中心獲取一張牌
Poker poker = PokerManager.GetManager().getOnePoker();
//將這張牌發(fā)給對應(yīng)的人
Player player = PlayerManager.GetManager().getPlayer(i);
player.poker = poker;
}
System.out.println(playerManager.players);
}
//棄牌
private void giveup(Player player){
player.playState = Constants.IPlayerState.DISCARD;
//棄牌之后,在玩的玩家數(shù)減一
LiveCount--;
}
private void changeCurrentIndex(){
//當(dāng)前玩家索引值指向下一個
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;//玩家的狀態(tài)
public int currentBet;//記錄當(dāng)前下注金額
public Player(int id, String name, int chips) {
this.id = id;
this.name = name;
this.chips = chips;
playState=Constants.IPlayerState.HAND;//初始化狀態(tài)
}
//扣錢
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){
//創(chuàng)建輸出
players=new ArrayList<>();
for(int i=0;i<totalPlayer;i++){
//獲取玩家名字
String name=Util.AutoGeneName();
//創(chuàng)建玩家對象
Player player=new Player(i+1,name, Constants.IPlayer.chips);
//保存玩家
players.add(player);
}
//當(dāng)玩家初始化成功就回調(diào)成功的事件給監(jiān)聽者(游戲中心)
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){
//找到?jīng)]有棄牌并且不是當(dāng)前最大的那個人
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;//管理牌的點(diǎn)數(shù)
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;//花色對應(yīng)的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(){
//初始化數(shù)組對象
pokers=new ArrayList<>();
//創(chuàng)建撲克牌
for(String dot: Constants.IPoker.DOTS){
//這樣就取出來了一張牌,之后選擇花色
for(Poker.PicType type:Constants.IPoker.PIC_TYPES){
//創(chuàng)建一張牌
Poker poker=new Poker(dot,type);
//添加到數(shù)組中保存
pokers.add(poker);
}
}
//打亂順序-洗牌
Collections.shuffle(pokers);
//當(dāng)撲克牌初始化成功就回調(diào)成功的事件給監(jiān)聽者(游戲中心)
if(Listener!=null){
Listener.onInitSuccess();
}
}
public Poker getOnePoker(){
//因?yàn)榕埔呀?jīng)被打亂了,所以獲取第一張,再將其刪除即可
if(pokers.size()>0){
Poker poker=pokers.get(0);
//將這張牌從數(shù)組里面刪除
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{
//點(diǎn)數(shù)
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();
//姓名的隨機(jī)數(shù)
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);//把數(shù)組里面的都追加過來
}
}else{
for(String content:args){
builder.append(content+" ");
}
}
if(nextLine){
System.out.println(builder.toString());
}else{
System.out.print(builder.toString());
}
}
//輸出一行不換行,不需要編號的數(shù)據(jù)
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();
}
}