之前说好的一定要研究透彻扑克牌项目,小弟说到做到。在下面我将把每一段代码的功能都尽可能描述清楚,一方面是帮助我理解这个项目的执行过程,另一方面也是希望能对大家有所帮助。
一.总
![](https://i-blog.csdnimg.cn/blog_migrate/b69e2a2f6e91fca43b1930443e844f9f.png)
AGameCenter是抽象类并实现IGameInitListener接口,主要是用来“被继承”
Constants接口里面保存一些常量,比如玩家姓名,扑克牌花色等等
IGameInitListener是接口,用来监听初始化是否成功。
PokerGameCenter继承AGameCenter,主要负责控制整个游戏的进行
Util是工具类
Player是玩家类,里面主要有单个玩家的数据信息和操作
PlayerManager是玩家管理类,里面主要涉及操作控制所有玩家的操作
Poker是扑克类,里面主要是涉及单个扑克的操作
PokerManager是扑克管理类,主要涉及操作控制所有扑克的操作。
Main里面是程序入口(这里放的包的不合适,还望大家谅解)
二.分
为了大家能够容易看懂,我们由简到难,一个类一个类地进行说明讲解
1.Constants接口
代码如下
package game;
import Poker1.Poker;
import Poker1.Poker.PicType;
//常量
public interface Constants {
//下面是玩家提示说明
interface IBet{
String[] NORMAL = new String[] {"下注","跟注","all-in","比牌","弃牌"};//正常情况
String[] LESS = new String[] {"all-in","弃牌"};
}
//默认筹码是1000
interface IPlayer{
int CHAPS = 1000;//筹码
}
//玩家姓名常量
interface IPlayerName{
//姓名
String[] NAMES_XING = {"王","李","张","彭"};
String[] NAMES_MING_M = {"宏","涛","国","东","建","强"};
String[] NAMES_MING_L = {"高","晓","博","督","黎"};
}
//玩家状态常量
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"};//点数
//里面保存了四个花色对象,具体看后面说明
Poker.PicType[] PIC_TYPES = {
Poker.PicType.SPADE,Poker.PicType.HRARTS,
Poker.PicType.CLUBS,Poker.PicType.DIAMONDS
};
}
}
这个类总体理解起来不难,重点留意一下IPlayerName即玩家姓名常量和IPoker这两个接口,具体什么功能后面会说。
既然涉及Poker类里面的东西,那下面就介绍Poker
2.Poker类
package Poker1;
import game.Constants;
public class Poker {
public String dot;//牌的点数
public PicType type;//花色对象,这里花色是用了内部类来保存的,类的名称是PicType
//构造方法
public Poker(String dot,PicType type) {
this.dot = dot;
this.type = type;
}
//难点一
public static class PicType{
public String pic;//花色
public int tag;//花色对应的tag值
//由于是涉及花色,所以应该是不可更改的,所以都用final修饰
public static final PicType SPADE = new PicType("♠黑桃",4);//黑桃
public static final PicType HRARTS = 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 compareTo(Poker another) {
int index_m = Util.indexOfObject(this.dot,Constants.IPoker.DOTS);
int index_a = Util.indexOfObject(another.dot,Constants.IPoker.DOTS);
if(index_a == index_m) {
if(this.type.tag > another.type.tag) {
return 1;
}else {
return -1;
}
}else {
if(index_m > index_a) {
return 1;
}else {
return -1;
}
}
}
public String toString() {
return dot+type.pic;
}
}
这个类有两个难点,大家不要急,在这里我会尽可能解释明白
难点①,内部类PicType:
由于比花色是无法直接比较的,所以我们为每个花色都设置了一种映射关系,即黑桃-4 红桃-3 梅花-2 方片-1,把它们封装在内部类PicType中,就可以实现花色的比较。
如何实现?
以SPADE为例,这是PicType的一个对象,这个对象里面有两个数据成员,一个是pic,一个是tag,其中tag就是其映射的数字4,通过SPADE.tag可以取出tag,进而可以和其他花色的tag进行比较。
难点②比较两张牌的大小:
这里使用了Util类里面的一个方法,我在这里先把这个方法单独拿出来
public static int indexOfObject(String object, String ...array){
for (int i = 0; i < array.length; i++){
if (array[i].equals(object)){
return i;
}
}
return -1;
}
这个方法有两个参数,第一个参数String类的object其实传的是这张牌的点数(从这个方法的调用可以看出),然后第二个参数array其实传的是Constants类里面的DOTS数组,这个数组是所有点数,按照从小到大的顺序来排列的,这一点尤为重要,其实也是为什么传递这个数组的原因。因为牌游戏的点数比大小不是简单的2<3,其中还涉及A和JQK这些的比较,而这些不是数字,所以无法与纯数字2345678910直接比较,所以就需要借用它们所在数组的索引值来比较大小,而这个indexOfObject方法其实就是的到这个点数的索引值。
解释到这里,indexOfObject函数就可以先扔一边了,继续看Poker类,我们用了两个变量index_m和index_a来分别保存此牌和另外一张牌点数的索引值。比较两张牌的话,肯定首先比较点数,如果两张牌索引值一样,那么就说明它们点数相同,点数相同就要比较花色,如何比较花色呢?其实前面已经说了,分别取出这两张牌花色的tag值来代替花色进行比较,如果这张牌的花色大,就返回1,如果另外一张牌的花色大,就返回-1.
如果点数不相同,就更好说了,如果这张牌的点数大,就返回1,如果另外一张牌的点数大,就返回-1
3.PokerManager类
package Poker1;
import java.util.*;
import game.Constants;
import game.IGameInitListener;
public class PokerManager {
//监听器,这个东西的功能我一直很迷糊,知道前几天才理解透彻,在这里与大家分享
private IGameInitListener listener;
private ArrayList<Poker> pokers;//保存扑克牌
//创建单例
private static PokerManager manager;//注意这里要是静态
private PokerManager() {
}
//获得PokerManager对象的方法,注意这里需要加锁,这里一定要会写,属于基本功。
public static PokerManager getManager() {
if(manager == null) {
synchronized(PokerManager.class) {