文章目录
1. 前言
之前写了一片文章Java实现斗地主?原来如此简单(页面效果版),主要是实现了斗地主游戏发牌的效果,项目比较简单,没有任何游戏逻辑上的判断和验证。这次直接完整实现了斗地主游戏,满足斗地主游戏的基本需求,包括:玩家准备、抢地主、出牌、牌规则验证、出牌验证等,核心代码一共一千多行,项目运行之后就可以正常游戏,与小伙伴们用自研的项目玩游戏,想想都不错,哈哈哈。后端使用的技术栈是Springboot+SpringCache+Websocket,项目中运用了Java基础及面向对象的各类技术,类、接口、对象、枚举、集合、Map、数组、排序、算法、缓存等都有使用…前端使用的是Thymeleaf+原生的js/jquery,接下来就一起来看一看吧!文章结尾处有项目源码地址、游戏录屏视频
2. 项目说明
1. 单牌定义
斗地主的规则在这里就不多说了,项目中首先要准备一副扑克牌(体现在Java代码中就是一个集合,包含54个对象),每个对象(名称)的命名方式为【花色-牌面】,其中1234分别代表♠♥♣♦4个花色,A~K代表13个牌面,例如红桃6就是【2-6】、黑桃7就是【1-7】、大王表示为【0-L】、小王表示为【0-S】
2. 牌型定义
牌型整理,通过枚举类来整理,一共整理了37种牌型,不知道有没有漏的,程序中目前就集成了这么多,枚举中包括两个字段,分别是牌名及牌数量,枚举类如下:
/**
* 定义枚举用于存放各类牌型
*/
public enum PokerEnum {
A("单牌", 1),
AA("对子", 2),
AAA("3不带", 3),
AAA_B("3带1", 4),
AAA_BB("3带2", 5),
AAAA("炸弹", 4),
SL("王炸",2),
A_B_C_D_E_5("顺子5",5),
A_B_C_D_E_6("顺子6",6),
A_B_C_D_E_7("顺子7",7),
A_B_C_D_E_8("顺子8",8),
A_B_C_D_E_9("顺子9",9),
A_B_C_D_E_10("顺子10",10),
A_B_C_D_E_11("顺子11",11),
A_B_C_D_E_12("顺子12",12),
AA_BB_CC_3("3连对",6),
AA_BB_CC_4("4连对",8),
AA_BB_CC_5("5连对",10),
AA_BB_CC_6("6连对",12),
AA_BB_CC_7("7连对",14),
AA_BB_CC_8("8连对",16),
AA_BB_CC_9("9连对",18),
AA_BB_CC_10("10连对",20),
AAA_BBB_2("飞机不带",6),
AAA_BBB_3("3连飞机不带",9),
AAA_BBB_4("4连飞机不带",12),
AAA_BBB_5("5连飞机不带",15),
AAA_BBB_6("6连飞机不带",18),
AAA_BBB_C_D_2("飞机带1",8),
AAA_BBB_C_D_3("3连飞机带1",12),
AAA_BBB_C_D_4("4连飞机带1",16),
AAA_BBB_C_D_5("5连飞机带1",20),
AAA_BBB_CC_DD_2("飞机带2",10),
AAA_BBB_CC_DD_3("3连飞机带2",15),
AAA_BBB_CC_DD_4("4连飞机带2",20),
AAAA_B_C("4带2",6),
AAAA_BB_CC("4带2对",8),
;
private String name;
private int num;
PokerEnum(String name, int num){
this.name = name;
this.num = num;
}
public int getNum() {
return num;
}
public String getName() {
return name;
}
}
3. 程序规则设计
预先准备三个玩家,分别是玩家A、玩家B、玩家C,三个玩家都准备好之后,由某一个玩家抢地主,然后按序出牌、牌规则验证(验证是否为合理的牌型)、出牌验证(出牌比大小)等,优先出牌结束的玩家获胜
4. 技术栈说明
后端:Java、面向对象、Springboot、SpringCache、ConcurrentHashMap、Websocket
核心代码使用一千多行Java代码,使用Springboot作为项目框架,项目中运用了Java基础及面向对象的各类技术,类、接口、对象、枚举、集合、Map、数组、排序、算法、缓存等都有使用,各家牌、出牌记录、地主、出牌轮次等关键信息全部存储到SpringCache中,轻量级无DB交互。接入Websocket,牌型发生变化实时推送到前端页面中
前端:Thymeleaf、h5、js、jquery、css、Websocket
使用原生的h5、js、jquery实现前端页面的简单渲染,非专职前端,所以页面效果一般,哈哈哈。使用Thymeleaf作为模板引擎渲染前端,Websocket监听后端推送的地址,业务实现前端效果的各类交互
3. 核心算法
1. 牌型验证
按照牌数量进行验证,验证的结果信息进行枚举匹配,然后返回构造的对象(包括枚举信息及最大值),这边只能介绍个大概,就不拆开说了,具体细节还需看代码逻辑一一消化了,示例代码如下:
/**
* 根据牌集合匹配牌对应枚举(验证牌属性)
* @param pokerNames 牌集合
* @return
*/
public static PokerEnumVo findEnumByPokers(List<String> pokerNames){
if(pokerNames == null || pokerNames.size() == 0){
return null;
}
//忽略花色,提取实际的牌面,并排序
List<String> pokerStrList = pokerNames.stream().map(i -> {
String j = i.split("-")[1];
return j;
}).sorted().collect(Collectors.toList());
Integer size = pokerStrList.size();
PokerEnumVo vo = PokerEnumVo.builder().build();
switch (size) {
case 1:
//单牌
vo.setPokerEnum(findEnumByNum("单牌", 1));
vo.setMaxInt(pokerValueToInt(pokerStrList.get(0)));
return vo;
case 2:
if (!allEqual(pokerStrList)) {
//2个值不一致,如果包括大小王,则为王炸,否则为非常规牌型
if (pokerStrList.contains("S") && pokerStrList.contains("L")) {
vo.setPokerEnum(findEnumByNum("王炸", 2));
vo.setMaxInt(20);
return vo;
} else {
return null;
}
}
//对子
vo.setPokerEnum(findEnumByNum("对子", 2));
vo.setMaxInt(pokerValueToInt(pokerStrList.get(0)));
return vo;
case 3:
if (!allEqual(pokerStrList)) {
//3个值不一致,为非常规牌型
return null;
}
vo.setPokerEnum(findEnumByNum("3不带", 3));
vo.setMaxInt(pokerValueToInt(pokerStrList.get(0)));
return vo;
case 4:
if (!allEqual(pokerStrList)) {
//4个值不一致,验证是否为3带1,否则为非常规牌型
List<NumValue> numValues = arrangeNumValue(pokerStrList);
if (numValues.size() == 2 && numValues.get(0).getNum() == 3) {
vo.setPokerEnum(findEnumByNum("3带1", 4));
vo.setMaxInt(pokerValueToInt(numValues.get(0).getValue()));
return vo;
}
return null;
}
vo.setPokerEnum(findEnumByNum("炸弹", 4));
vo.setMaxInt(pokerValueToInt(pokerStrList.get(0)));
return vo;
case 5:
List<NumValue> numValues5 = arrangeNumValue(pokerStrList);
if (numValues5.size() == 2) {
if (numValues5.get(0).getNum() == 3) {
vo.setPokerEnum(findEnumByNum("3带2", 5));
vo.setMaxInt(pokerValueToInt(numValues5.get(0).getValue()));
return vo;
}
}
if (numValues5.size() == 5 && !pokerStrList.contains("S") && !pokerStrList.contains("L")) {
ChainFlag chain = isChain(pokerStrList);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("顺子5", 5));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
return null;
case 6:
List<NumValue> numValues6 = arrangeNumValue(pokerStrList);
if (numValues6.size() == 6 && !pokerStrList.contains("S") && !pokerStrList.contains("L")) {
ChainFlag chain = isChain(pokerStrList);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("顺子6", 6));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
List<String> singleValue6 = numValues6.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (numValues6.size() == 3) {
if (numValues6.get(0).getNum() == 2 && numValues6.get(1).getNum() == 2) {
ChainFlag chain = isChain(singleValue6);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("3连对", 6));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues6.size() == 2 && numValues6.get(0).getNum() == 3) {
ChainFlag chain = isChain(singleValue6);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("飞机不带", 6));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
if (numValues6.size() == 3 || numValues6.size() == 2) {
if (numValues6.get(0).getNum() == 4) {
vo.setPokerEnum(findEnumByNum("4带2", 6));
vo.setMaxInt(pokerValueToInt(numValues6.get(0).getValue()));
return vo;
}
}
return null;
case 7:
List<NumValue> numValues7 = arrangeNumValue(pokerStrList);
if (numValues7.size() == 7 && !pokerStrList.contains("S") && !pokerStrList.contains("L")) {
ChainFlag chain = isChain(pokerStrList);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("顺子7", 7));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
return null;
case 8:
List<NumValue> numValues8 = arrangeNumValue(pokerStrList);
if (numValues8.size() == 8 && !pokerStrList.contains("S") && !pokerStrList.contains("L")) {
ChainFlag chain = isChain(pokerStrList);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("顺子8", 8));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
List<String> singleValue8 = numValues8.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (numValues8.size() == 4) {
if (numValues8.get(0).getNum() == 2 && numValues8.get(1).getNum() == 2 && numValues8.get(2).getNum() == 2) {
ChainFlag chain = isChain(singleValue8);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("4连对", 8));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues8.size() == 4 || numValues8.size() == 3) {
if (numValues8.get(0).getNum() == 3 && numValues8.get(1).getNum() == 3) {
List<String> strings = singleValue8.subList(0, 2);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("飞机带1", 8));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues8.size() == 3) {
if (numValues8.get(0).getNum() == 4 && numValues8.get(1).getNum() == 2) {
//AAAA_BB_CC
vo.setPokerEnum(findEnumByNum("4带2对", 8));
vo.setMaxInt(pokerValueToInt(numValues8.get(0).getValue()));
return vo;
}
}
if (numValues8.size() == 2) {
if (numValues8.get(0).getNum() == 4) {
//AAAA_BB_BB
vo.setPokerEnum(findEnumByNum("4带2对", 8));
vo.setMaxInt(pokerValueToInt(numValues8.get(0).getValue()));
return vo;
}
}
return null;
case 9:
List<NumValue> numValues9 = arrangeNumValue(pokerStrList);
if (numValues9.size() == 9 && !pokerStrList.contains("S") && !pokerStrList.contains("L")) {
ChainFlag chain = isChain(pokerStrList);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("顺子9", 9));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
List<String> singleValue9 = numValues9.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (singleValue9.size() == 3) {
if (numValues9.get(0).getNum() == 3 && numValues9.get(1).getNum() == 3) {
ChainFlag chain = isChain(singleValue9);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("3连飞机不带", 9));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
return null;
case 10:
List<NumValue> numValues10 = arrangeNumValue(pokerStrList);
if (numValues10.size() == 10 && !pokerStrList.contains("S") && !pokerStrList.contains("L")) {
ChainFlag chain = isChain(pokerStrList);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("顺子10", 10));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
List<String> singleValue10 = numValues10.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (numValues10.size() == 5) {
if (numValues10.get(0).getNum() == 2 && numValues10.get(1).getNum() == 2 && numValues10.get(2).getNum() == 2 && numValues10.get(3).getNum() == 2) {
ChainFlag chain = isChain(singleValue10);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("5连对", 10));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (singleValue10.size() == 4) {
if (numValues10.get(0).getNum() == 3 && numValues10.get(1).getNum() == 3 && numValues10.get(2).getNum() == 2) {
List<String> strings = singleValue10.subList(0, 2);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("飞机带2", 10));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
return null;
case 11:
List<NumValue> numValues11 = arrangeNumValue(pokerStrList);
if (numValues11.size() == 11 && !pokerStrList.contains("S") && !pokerStrList.contains("L")) {
ChainFlag chain = isChain(pokerStrList);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("顺子11", 11));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
return null;
case 12:
List<NumValue> numValues12 = arrangeNumValue(pokerStrList);
if (numValues12.size() == 12 && !pokerStrList.contains("S") && !pokerStrList.contains("L")) {
ChainFlag chain = isChain(pokerStrList);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("顺子12", 12));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
List<String> singleValue12 = numValues12.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (numValues12.size() == 6) {
if (numValues12.get(0).getNum() == 2 && numValues12.get(1).getNum() == 2 && numValues12.get(2).getNum() == 2
&& numValues12.get(3).getNum() == 2 && numValues12.get(4).getNum() == 2) {
ChainFlag chain = isChain(singleValue12);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("6连对", 12));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (singleValue12.size() == 4) {
if (numValues12.get(0).getNum() == 3 && numValues12.get(1).getNum() == 3 && numValues12.get(2).getNum() == 3) {
ChainFlag chain = isChain(singleValue12);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("4连飞机不带", 12));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
ChainFlag chainLeft = isChainLeft(singleValue12, 1);
if (chainLeft.isFlag()) {
//3连飞机+AAA
vo.setPokerEnum(findEnumByNum("3连飞机带1", 12));
vo.setMaxInt(chainLeft.getMaxInt());
return vo;
}
ChainFlag chainRight = isChainRight(singleValue12, 1);
if (chainRight.isFlag()) {
//AAA+3连飞机
vo.setPokerEnum(findEnumByNum("3连飞机带1", 12));
vo.setMaxInt(chainRight.getMaxInt());
return vo;
}
}
}
if (numValues12.size() == 6 || numValues12.size() == 5) {
if (numValues12.get(0).getNum() == 3 && numValues12.get(1).getNum() == 3 && numValues12.get(2).getNum() == 3) {
List<String> strings = singleValue12.subList(0, 3);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("3连飞机带1", 12));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
return null;
case 14:
List<NumValue> numValues14 = arrangeNumValue(pokerStrList);
if (numValues14.size() == 7) {
if (numValues14.get(0).getNum() == 2 && numValues14.get(1).getNum() == 2 && numValues14.get(2).getNum() == 2
&& numValues14.get(3).getNum() == 2 && numValues14.get(4).getNum() == 2 && numValues14.get(5).getNum() == 2) {
List<String> singleValue14 = numValues14.stream().map(i -> i.getValue()).collect(Collectors.toList());
ChainFlag chain = isChain(singleValue14);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("7连对", 14));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
return null;
case 15:
List<NumValue> numValues15 = arrangeNumValue(pokerStrList);
List<String> singleValue15 = numValues15.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (numValues15.size() == 5) {
if (numValues15.get(0).getNum() == 3 && numValues15.get(1).getNum() == 3 && numValues15.get(2).getNum() == 3 && numValues15.get(3).getNum() == 3) {
ChainFlag chain = isChain(singleValue15);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("5连飞机不带", 15));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues15.size() == 6) {
if (numValues15.get(0).getNum() == 3 && numValues15.get(1).getNum() == 3 && numValues15.get(2).getNum() == 3
&& numValues15.get(3).getNum() == 2 && numValues15.get(4).getNum() == 2) {
List<String> strings = singleValue15.subList(0, 3);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("3连飞机带2", 15));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
return null;
case 16:
List<NumValue> numValues16 = arrangeNumValue(pokerStrList);
List<String> singleValue16 = numValues16.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (numValues16.size() == 8) {
if (numValues16.get(0).getNum() == 2 && numValues16.get(1).getNum() == 2 && numValues16.get(2).getNum() == 2
&& numValues16.get(3).getNum() == 2 && numValues16.get(4).getNum() == 2 && numValues16.get(5).getNum() == 2
&& numValues16.get(6).getNum() == 2) {
ChainFlag chain = isChain(singleValue16);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("8连对", 16));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues16.size() == 5) {
if (numValues16.get(0).getNum() == 4 && numValues16.get(1).getNum() == 3 && numValues16.get(2).getNum() == 3 && numValues16.get(3).getNum() == 3) {
List<String> strings = singleValue16.subList(1, 5);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
//4连飞机+AAAA
vo.setPokerEnum(findEnumByNum("4连飞机带1", 16));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues16.size() >= 6 && numValues16.size() <= 8) {
if (numValues16.get(0).getNum() == 3 && numValues16.get(1).getNum() == 3 && numValues16.get(2).getNum() == 3 && numValues16.get(3).getNum() == 3) {
if (numValues16.size() == 8 || numValues16.size() == 7) {
List<String> strings = singleValue16.subList(0, 4);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
//4连飞机+A+B+C+D 或 4连飞机+AA+B+C
vo.setPokerEnum(findEnumByNum("4连飞机带1", 16));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
if (numValues16.size() == 6) {
if (numValues16.get(4).getNum() == 2) {
List<String> strings = singleValue16.subList(0, 4);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
//4连飞机+AA+BB
vo.setPokerEnum(findEnumByNum("4连飞机带1", 16));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
if (numValues16.get(4).getNum() == 3) {
List<String> strings = singleValue16.subList(0, 5);
ChainFlag chainLeft = isChainLeft(strings, 1);
if (chainLeft.isFlag()) {
//4连飞机+AAA+B
vo.setPokerEnum(findEnumByNum("4连飞机带1", 16));
vo.setMaxInt(chainLeft.getMaxInt());
return vo;
}
ChainFlag chainRight = isChainRight(strings, 1);
if (chainRight.isFlag()) {
//AAA+B+4连飞机
vo.setPokerEnum(findEnumByNum("4连飞机带1", 16));
vo.setMaxInt(chainRight.getMaxInt());
return vo;
}
}
}
}
}
return null;
case 18:
List<NumValue> numValues18 = arrangeNumValue(pokerStrList);
List<String> singleValue18 = numValues18.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (numValues18.size() == 9) {
if (numValues18.get(0).getNum() == 2 && numValues18.get(1).getNum() == 2 && numValues18.get(2).getNum() == 2
&& numValues18.get(3).getNum() == 2 && numValues18.get(4).getNum() == 2 && numValues18.get(5).getNum() == 2
&& numValues18.get(6).getNum() == 2 && numValues18.get(7).getNum() == 2) {
ChainFlag chain = isChain(singleValue18);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("9连对", 18));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues18.size() == 6) {
if (numValues18.get(0).getNum() == 3 && numValues18.get(1).getNum() == 3 && numValues18.get(2).getNum() == 3
&& numValues18.get(3).getNum() == 3 && numValues18.get(4).getNum() == 3) {
ChainFlag chain = isChain(singleValue18);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("6连飞机不带", 18));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
return null;
case 20:
List<NumValue> numValues20 = arrangeNumValue(pokerStrList);
List<String> singleValue20 = numValues20.stream().map(i -> i.getValue()).collect(Collectors.toList());
if (numValues20.size() == 10) {
if (numValues20.get(0).getNum() == 2 && numValues20.get(1).getNum() == 2 && numValues20.get(2).getNum() == 2
&& numValues20.get(3).getNum() == 2 && numValues20.get(4).getNum() == 2 && numValues20.get(5).getNum() == 2
&& numValues20.get(6).getNum() == 2 && numValues20.get(7).getNum() == 2 && numValues20.get(8).getNum() == 2) {
ChainFlag chain = isChain(singleValue20);
if (chain.isFlag()) {
vo.setPokerEnum(findEnumByNum("10连对", 20));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues20.size() == 7) {
if (numValues20.get(0).getNum() == 4 && numValues20.get(1).getNum() == 3 && numValues20.get(2).getNum() == 3
&& numValues20.get(3).getNum() == 3 && numValues20.get(4).getNum() == 3 && numValues20.get(5).getNum() == 3) {
List<String> strings = singleValue20.subList(1, 6);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
//5连飞机+AAAA+B
vo.setPokerEnum(findEnumByNum("5连飞机带1", 20));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues20.size() >= 7 && numValues20.size() <= 10) {
if (numValues20.get(0).getNum() == 3 && numValues20.get(1).getNum() == 3 && numValues20.get(2).getNum() == 3
&& numValues20.get(3).getNum() == 3 && numValues20.get(4).getNum() == 3) {
if (numValues20.get(5).getNum() == 3) {
List<String> strings = singleValue20.subList(0, 6);
ChainFlag chainLeft = isChainLeft(strings, 1);
if (chainLeft.isFlag()) {
//5连飞机+AAA+BB 或 5连飞机+AAA+B+C
vo.setPokerEnum(findEnumByNum("5连飞机带1", 20));
vo.setMaxInt(chainLeft.getMaxInt());
return vo;
}
ChainFlag chainRight = isChainRight(strings, 1);
if (chainRight.isFlag()) {
//AAA+5连飞机+BB 或 AAA+5连飞机+B+C
vo.setPokerEnum(findEnumByNum("5连飞机带1", 20));
vo.setMaxInt(chainRight.getMaxInt());
return vo;
}
} else {
List<String> strings = singleValue20.subList(0, 5);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
//5连飞机 普通版
vo.setPokerEnum(findEnumByNum("5连飞机带1", 20));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
}
if (numValues20.size() == 6) {
if (numValues20.get(0).getNum() == 4 && numValues20.get(1).getNum() == 4 && numValues20.get(2).getNum() == 3
&& numValues20.get(3).getNum() == 3 && numValues20.get(4).getNum() == 3) {
List<String> strings = singleValue20.subList(2, 6);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
//AAAA+BBBB+4连飞机
vo.setPokerEnum(findEnumByNum("4连飞机带2", 20));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues20.size() == 7) {
if (numValues20.get(0).getNum() == 4 && numValues20.get(1).getNum() == 3 && numValues20.get(2).getNum() == 3
&& numValues20.get(3).getNum() == 3 && numValues20.get(4).getNum() == 3 && numValues20.get(5).getNum() == 2) {
List<String> strings = singleValue20.subList(1, 5);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
//AAAA+4连飞机+BB+CC
vo.setPokerEnum(findEnumByNum("4连飞机带2", 20));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
if (numValues20.size() == 8) {
if (numValues20.get(0).getNum() == 3 && numValues20.get(1).getNum() == 3 && numValues20.get(2).getNum() == 3
&& numValues20.get(3).getNum() == 3 && numValues20.get(4).getNum() == 2 && numValues20.get(5).getNum() == 2
&& numValues20.get(6).getNum() == 2) {
List<String> strings = singleValue20.subList(0, 4);
ChainFlag chain = isChain(strings);
if (chain.isFlag()) {
//4连飞机+AA+BB+CC+DD
vo.setPokerEnum(findEnumByNum("4连飞机带2", 20));
vo.setMaxInt(chain.getMaxInt());
return vo;
}
}
}
return null;
}
return null;
}
/**
* 根据牌名称和数量匹配枚举
* @param name 牌名称
* @param num 数量
* @return
*/
public static PokerEnum findEnumByNum(String name, Integer num){
if(StringUtils.isEmpty(name) || num == null || num == 0){
return null;
}
for (PokerEnum value : PokerEnum.values()) {
if(name.equals(value.getName()) && num == value.getNum()){
return value;
}
}
return null;
}
/**
* 验证集合中的字符串是否全部一致
* @param list
* @return
*/
public static boolean allEqual(List<String> list){
boolean allEqual = true;
for (int i = 1; i < list.size(); i++) {
if (!list.get(i).equals(list.get(0))) { // 比较当前元素与第一个元素是否不同
allEqual = false; // 若存在不同则将allEqual设置为false
break; // 结束循环
}
}
return allEqual;
}
/**
* 整理集合中的数值规则
* @param list 排序之后的集合
* @return NumValue
*/
public static List<NumValue> arrangeNumValue(List<String> list){
List<NumValue> numList = new ArrayList<>();
List<String> tempList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (i == 0) { //第一个元素
tempList.add(list.get(i));
} else if (i == list.size() - 1) { //最后一个元素
if (list.get(i).equals(list.get(i-1))) { // 比较当前元素与上一个元素是否相同
tempList.add(list.get(i));
NumValue numValue = NumValue.builder().num(tempList.size()).value(list.get(i)).build();
numList.add(numValue);
} else {
NumValue numValue = NumValue.builder().num(tempList.size()).value(list.get(i-1)).build();
numList.add(numValue);
NumValue numValueLast = NumValue.builder().num(1).value(list.get(i)).build();
numList.add(numValueLast);
}
} else {
if (list.get(i).equals(list.get(i-1))) { // 比较当前元素与上一个元素是否相同
tempList.add(list.get(i));
} else {
NumValue numValue = NumValue.builder().num(tempList.size()).value(list.get(i-1)).build();
numList.add(numValue);
tempList.clear();
tempList.add(list.get(i));
}
}
}
//按照数量降序排序返回
List<NumValue> collect = numList.stream().sorted(Comparator.comparing(NumValue::getNum, Comparator.reverseOrder()))
.collect(Collectors.toList());
return collect;
}
/**
* 验证集合中的字符串是否为顺子
* @param list
* @return
*/
public static ChainFlag isChain(List<String> list) {
List<Integer> integers = strToIntSort(list);
return commonVerifyChain(integers);
}
/**
* 验证集合中的字符串是否为顺子(排除左边i个)
* @param list
* @param i 集合左边第几个起(下标从0开始)
* @return
*/
public static ChainFlag isChainLeft(List<String> list, Integer i) {
List<Integer> integers = strToIntSort(list).subList(i, list.size());
return commonVerifyChain(integers);
}
/**
* 验证集合中的字符串是否为顺子(排除右边i个)
* @param list
* @param i 集合右边第几个起(下标从0开始)
* @return
*/
public static ChainFlag isChainRight(List<String> list, Integer i) {
List<Integer> integers = strToIntSort(list).subList(0, list.size() - i);
return commonVerifyChain(integers);
}
/**
* 字符串集合转排序后的Int集合
* @param list
* @return
*/
private static List<Integer> strToIntSort(List<String> list) {
List<Integer> integers = list.stream().map(i->{
Integer j;
switch (i) {
case "A":
j = 14;
break;
case "K":
j = 13;
break;
case "Q":
j = 12;
break;
case "J":
j = 11;
break;
default:
j = Integer.valueOf(i);
}
return j;
}).sorted().collect(Collectors.toList());
return integers;
}
/**
* 验证顺子通用方法
* @param integers
* @return
*/
private static ChainFlag commonVerifyChain(List<Integer> integers) {
ChainFlag chainFlag = new ChainFlag();
Integer max = integers.get(integers.size() -1);
Integer min = integers.get(0);
chainFlag.setMaxInt(max);
if (min == 2) {
chainFlag.setFlag(false);
return chainFlag;
}
if (max - min + 1 == integers.size()) {
chainFlag.setFlag(true);
return chainFlag;
}
chainFlag.setFlag(false);
return chainFlag;
}
/**
* 单牌转int值,方便比大小
* @param pokerName
* @return
*/
private static Integer pokerValueToInt(String pokerName) {
String[] split = pokerName.split("-");
String s = split.length == 2 ? split[1] : split[0];
Integer j;
switch (s) {
case "L":
j = 17;
break;
case "S":
j = 16;
break;
case "2":
j = 15;
break;
case "A":
j = 14;
break;
case "K":
j = 13;
break;
case "Q":
j = 12;
break;
case "J":
j = 11;
break;
default:
j = Integer.valueOf(s);
}
return j;
}
3. 牌型比大小
各类排序比大小,比如:单牌比大小、对子比大小、顺子比大小、炸弹比大小等等,其实就是玩游戏的压牌规则,示例代码如下:
**
* 比较牌大小
* @param lastVo 上家牌属性
* @param currentVo 当前牌属性
* @return
*/
public static boolean verifyPokerProperty(PokerEnumVo lastVo, PokerEnumVo currentVo) {
String lastEnumName = lastVo.getPokerEnum().getName();
String currentEnumName = currentVo.getPokerEnum().getName();
if ("王炸".equals(lastEnumName)) {
return false;
}
if ("王炸".equals(currentEnumName)) {
return true;
}
if ("炸弹".equals(lastEnumName) && "炸弹".equals(currentEnumName)) {
if (lastVo.getMaxInt() < currentVo.getMaxInt()) {
return true;
} else {
return false;
}
}
if ("炸弹".equals(lastEnumName) && !"炸弹".equals(currentEnumName)) {
return false;
}
if (!"炸弹".equals(lastEnumName) && "炸弹".equals(currentEnumName)) {
return true;
}
//炸弹逻辑完成,常规逻辑如下
//牌型不一致,无法比较
if (!lastEnumName.equals(currentEnumName)) {
return false;
}
//牌型一致,最大值进行比较
if (lastVo.getMaxInt() < currentVo.getMaxInt()) {
return true;
}
return false;
}