携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第二天,点击查看活动详情
上一章写的是洗牌发牌,接下来就要玩家出牌,系统判断玩家出的牌是否符合规则,然后按照玩家出的牌模拟人机出牌。
循环所有的牌,玩家出牌后在list中删除所出的牌,知道出完所有的牌,结束游戏
List<String> boards = new ArrayList();
int m = 0;
while (allPok.size() > 0) {
if (boards != null && boards.size() > 0) {
//如果返回end,则结束游戏
if (boards.get(0).equals("end")) {
break;
}
}
for (Integer key : peoperMap.keySet()) {//keySet获取map集合key的集合 然后在遍历key即可
if (key == m && m != 0) {
//如果后面的玩家都要不起,则由当前玩家重新出牌
boards.clear();
}
//地主需要第一个出牌
if (!(key == randomLand) && m == 0) {
continue;
}
//输出带颜色的提示信息,好分辨是哪个玩家的信息
printSingleColor("", key + 31, key + 31, "【" + peoperMap.get(key) + "】出牌=====================================");
try {
//休眠一段时间防止出牌速度过快
Thread.sleep(Long.valueOf(RandomStringUtils.randomNumeric(3)));
} catch (InterruptedException e) {
e.printStackTrace();
}
//当前玩家可以看到自己的牌,不能看到其他人的牌
if (local.equals(peoperMap.get(key))) {
System.out.println("【" + peoperMap.get(key) + "】的牌为:" + pokMap.get(peoperMap.get(key)).toString());
}
//如果是手动出牌,则列出所有的牌
if (!self && local.equals(peoperMap.get(key))) {
// boards.clear();
String board = "";
System.out.print("请输入你要出的牌:");
board = scanner.nextLine();
//调用方法判断是否出牌有误
while (!checkBoard(board, pokMap.get(peoperMap.get(key)), boards, valueMap)) {
System.out.print("出牌有误,请输入你要出的牌:");
board = scanner.nextLine();
}
if (StringUtils.isNotEmpty(board)) {
char[] chars = board.toCharArray();
boards = new ArrayList() {{
for (char c1 : chars) {
String s = String.valueOf(c1);
if (s.contains("大") || s.contains("小")) {
s = s.contains("大") ? "大王" : "小王";
} else if (s.contains("王")) {
continue;
} else if (s.contains("0")) {
s = "10";
} else if (s.contains("1")) {
continue;
}
final String p = s;
//根据出牌的数字匹配对应的牌号
//要存储不同符号的牌号
String v = pokMap.get(peoperMap.get(key)).stream().filter(t ->
getNum(t.toString()).equals(StringUtils.upperCase(p)) && !contains(t)).findFirst().get().toString();
add(v);
}
}};
} else {
boards.clear();
}
}
//模拟出牌操作,判断出牌是否有误
List retBoards = playHandPlayer1(peoperMap.get(key), pokMap, valueMap, allPok, boards, local, self);
List b = new ArrayList();
if (retBoards != null) {
b.addAll(retBoards);
}
//如果下家都要不起,则由该玩家重新出牌
if (retBoards != null && retBoards.size() > 0) {
//记录最后出牌的玩家
m = key;
boards.clear();
boards.addAll(b);
if (b.get(0).equals("end")) {
break;
}
}
}
}
- 该方法为checkBoard方法,根据牌的序号数判断该玩家的牌出的是否符合规则
循环玩家所出的牌,判断是否在玩家的牌池(之前随机分发给玩家的牌)中,放入list集合中
//如果玩家输入的出牌为空则表示要不起
if (StringUtils.isEmpty(board)) {
if (retBoards == null || retBoards.size() == 0) {
return false;
}
return true;
}
Map<String, String> map = new HashMap();
char[] chars = board.toCharArray();
List<String> charBoard = new ArrayList() {{
for (char c1 : chars) {
String s = String.valueOf(c1);
final String p = s;
//判断玩家是否有这张牌
Object v = pokList.stream().filter(t ->
getNum(t).equals(StringUtils.upperCase(p)) && !contains(t)).findFirst();
if (v == null) {
add("false");
break;
}
//大王小王以及10等字符可通过是否包含方式进行判断
if (s.contains("大") || s.contains("小")) {
add(s.contains("大") ? "大王" : "小王");
} else if (s.contains("0")) {
add("10");
} else if (s.contains("王")) {
continue;
} else if (s.contains("1")) {
continue;
} else {
add(s.toUpperCase());
}
}
}};
if (charBoard.contains("false")) {
return false;
}
charBoard为玩家出的牌,打印效果如下
- 初始化牌,将相同的牌提取出来,为自动出牌做准备
Map<Integer, List<String>> initMap = initBoard(charBoard, valueMap);
获取玩家卡牌中重复的牌,如对子,三张,炸弹等,其中王炸也在炸弹中,将之放入各个对应的List集合中
public static Map<Integer, List<String>> initBoard(List<String> poker, Map<String, Integer> valueMap) {
//判断数组中重复的数字与次数
Map<Integer, Long> repetMap = poker.stream()
.filter(p -> valueMap.get(p) != null).collect(
Collectors.groupingBy(p -> valueMap.get(p), Collectors.counting()));
Map<String, Long> repetNum = new HashMap<>();
repetMap.keySet().forEach(m -> {
poker.stream().forEach(p -> {
if (valueMap.get(p) == m) {
repetNum.put(p, repetMap.get(m));
}
});
});
List<String> oneList = new ArrayList<>();
List<String> twoList = new ArrayList<>();
List<String> threeList = new ArrayList<>();
List<String> fourList = new ArrayList<>();
repetNum.forEach((k, v) -> {
switch (v.intValue()) {
case 1:
oneList.add(k);
break;
case 2:
twoList.add(k);
break;
case 3:
threeList.add(k);
break;
case 4:
fourList.add(k);
break;
}
});
if (oneList.contains("大王") && oneList.contains("小王")) {
fourList.add("大王");
fourList.add("小王");
oneList.remove("大王");
oneList.remove("小王");
}
//两张牌加三张牌组为连对
// twoList.addAll(threeList);
Map<Integer, List<String>> listMap = new HashMap<>();
listMap.put(1, oneList);
listMap.put(2, twoList);
listMap.put(3, threeList);
listMap.put(4, fourList);
return listMap;
}
- 将初始化之后的牌整理归类,判断是否连续
//判断只能有一个list大小大于0
int m = initMap.keySet().stream().filter(n -> initMap.get(n).size() > 0).toArray().length;
if (m >= 2) {
return false;
}
//取出不为空list的数值
Integer num = initMap.keySet().stream().filter(n -> initMap.get(n).size() > 0).findFirst().get();
//获取出不为空的list
List<String> list = initMap.get(num);
if (retBoards.size() == 0) {
//判断是否连续
switch (num) {
case 1:
//如果是单张的牌,则需要判断是否是顺子,最少为五张连续的牌
if (list.size() == 1) {
return true;
}
if (list.size() >= 5) {
Map map1 = clocks(list, valueMap, 5);
if (map1.size() > 0) {
return true;
}
}
return false;
case 2:
//如果是对子,则判断是否为连对,最少需要三次连续的牌
if (list.size() == 1) {
return true;
}
if (list.size() >= 3) {
Map map1 = clocks(list, valueMap, 3);
if (map1.size() > 0) {
return true;
}
}
return false;
case 3:
//如果是三张,则判断是否为飞机,最少需要两次连续的牌
if (list.size() == 1) {
return true;
}
if (list.size() >= 2) {
Map map1 = clocks(list, valueMap, 2);
if (map1.size() > 0) {
return true;
}
}
return false;
}
}
判断是否是顺序的牌
/**
* 获取顺序的牌的第一张与张数
*
* @param valueMap
* @param num 顺子至少需要连续的五张牌 连对则需三对 飞机为2
* @return
*/
public static Map<String, Integer> clocks(List<String> list, Map<String, Integer> valueMap, int num) {
//先去重
ArrayList<String> li = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(o ->
getNum(o)))), ArrayList::new));
Map<String, Integer> clocksMap = new HashMap();
Stream.iterate(0, i -> i + 1).limit(li.size()).forEach(index -> {
int returnIndex = checkClockAfter(li, index, valueMap);
//数据相减后与传过来的数据减一做对比,如顺子最大的index为5,最小的index为1,相减后为4
if (returnIndex - index >= num - 1) {
//key : 连对第一张牌 value : 连对对数
clocksMap.put(li.get(index), returnIndex - index + 1);
}
});
return clocksMap;
}
- 上面的方法是判断这一次出牌是否无误,接下来要判断该出牌是否大于上家出的牌,以及是否与上家出的牌匹配
//同样初始化数据,取出单张对子三张炸弹等牌
Map<Integer, List<String>> rbtInitMap = initBoard(retBoards, valueMap);
//获取出不为空的list
Integer num1 = rbtInitMap.keySet().stream().filter(n -> rbtInitMap.get(n).size() > 0).findFirst().get();
List<String> list1 = rbtInitMap.get(num1);
switch (num) {
case 1:
if (num1 != 1) {
return false;
}
if (list.size() == 1) {
//从valueMap中取出牌对应的数字,判断出牌的数字是否大于上家的出牌
if (valueMap.get(list.get(0).length() == 1 ? "♥" + list.get(0) : list.get(0)) <= valueMap.get(list1.get(0))) {
return false;
}
}
if (list.size() >= 5) {
//判断顺子出牌是否有误且最小的顺子数是否大于上家的出牌
List retBoard = checkOtherPok(initMap.get(1), null, valueMap, rbtInitMap.get(1).get(0), 1);
if (retBoard == null) {
return false;
}
}
break;
case 2:
if (num1 != 2) {
return false;
}
if (list.size() == 1) {
if (valueMap.get("♥" + list.get(0)) <= valueMap.get(list1.get(0))) {
return false;
}
}
if (list.size() >= 3) {
List retBoard = checkOtherPok(initMap.get(2), null, valueMap, rbtInitMap.get(2).get(0), 2);
if (retBoard == null) {
return false;
}
}
break;
case 3:
if (num1 != 3) {
return false;
}
if (list.size() == 1) {
if (valueMap.get("♥" + list.get(0)) <= valueMap.get(list1.get(0))) {
return false;
}
}
if (list.size() >= 2) {
List retBoard = checkOtherPok(initMap.get(3), null, valueMap, rbtInitMap.get(3).get(0), 3);
if (retBoard == null) {
return false;
}
}
break;
case 4:
if (list.size() == 1) {
if (list1.size() > 1) {
return true;
}
if (valueMap.get("♥" + list.get(0)) <= valueMap.get(list1.get(0))) {
return false;
}
}
//王炸则直接返回成功
if (list.size() == 2) {
return true;
} else {
List retBoard = checkOtherPok(initMap.get(4), null, valueMap, rbtInitMap.get(4).get(0), 4);
if (retBoard == null) {
return false;
}
}
break;
}
return true;
判断当前出牌是否大于上家的出牌
/**
* 获取单张或者对子或者三带一
*
* @param list 匹配对应的list
* @param ownMap 匹配对应的map
* @param valueMap
* @param val 对方出的牌
* @param bNum
* @return
*/
public static List checkOtherPok(List<String> list, Map<String, Integer> ownMap, Map<String, Integer> valueMap, String val, int bNum) {
List<String> boards = new ArrayList<>();
list.stream().forEach(li -> {
if ((StringUtils.isNotEmpty(val) && valueMap.get(li) > valueMap.get(val)) || StringUtils.isEmpty(val)) {
if (ownMap != null) {
int len = ownMap.keySet().stream().filter(n -> getNum(n).equals(getNum(li))).toArray().length;
if (len == 0) {
//防止需要两张却获取三张的情况
//如果是连对则放入两张牌 飞机则为三张
int len1 = boards.stream().filter(n -> getNum(n).equals(getNum(li))).toArray().length;
if (len1 < bNum && boards.size() < bNum) {
boards.add(li);
}
}
} else {
//防止需要两张却获取三张的情况
//如果是连对则放入两张牌 飞机则为三张
int len = boards.stream().filter(n -> getNum(n).equals(getNum(li))).toArray().length;
if (len < bNum && boards.size() < bNum) {
boards.add(li);
}
}
}
});
return boards;
}
后续明天再写,over