|
|
@@ -3,14 +3,10 @@ package org.dromara.business.utils;
|
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
+import java.util.*;
|
|
|
|
|
|
public class ActionParserUtils {
|
|
|
|
|
|
-
|
|
|
// 阶段映射
|
|
|
private static final Map<String, String> STAGE_MAP = Map.of(
|
|
|
"PREFLOP", "翻牌前",
|
|
|
@@ -25,30 +21,63 @@ public class ActionParserUtils {
|
|
|
"CHECK", "过牌",
|
|
|
"CALL", "跟注",
|
|
|
"RAISE", "加注",
|
|
|
- "ALL_IN", "全压"
|
|
|
+ "ALL_IN", "全下",
|
|
|
+ "BET", "下注"
|
|
|
);
|
|
|
|
|
|
/**
|
|
|
* 将 JSON 中的 actions 解析为中文描述的列表
|
|
|
+ * 包括盲注、动作、摊牌信息(含底牌解析)
|
|
|
*/
|
|
|
public static List<String> parseActionsToChineseList(String json) throws Exception {
|
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
|
JsonNode rootNode = mapper.readTree(json);
|
|
|
|
|
|
- // 构建 playerId -> name 映射
|
|
|
- Map<Integer, String> playerMap = new HashMap<>();
|
|
|
+ // 提取盲注金额
|
|
|
+ JsonNode blindsNode = rootNode.get("blinds");
|
|
|
+ int sbAmount = blindsNode != null ? blindsNode.get("sb").asInt() : 0;
|
|
|
+ int bbAmount = blindsNode != null ? blindsNode.get("bb").asInt() : 0;
|
|
|
+ int anteAmount = blindsNode != null ? blindsNode.get("ante").asInt() : 0;
|
|
|
+
|
|
|
+ // 提取盲注座位号
|
|
|
+ int smallBlindSeat = rootNode.has("smallBlindSeat") ? rootNode.get("smallBlindSeat").asInt() : -1;
|
|
|
+ int bigBlindSeat = rootNode.has("bigBlindSeat") ? rootNode.get("bigBlindSeat").asInt() : -1;
|
|
|
+
|
|
|
+ // 构建 playerId -> 玩家信息(含姓名、座位、标签)
|
|
|
+ Map<Long, PlayerInfo> playerInfoMap = new HashMap<>();
|
|
|
+ String sbPlayerName = "未知";
|
|
|
+ String bbPlayerName = "未知";
|
|
|
+
|
|
|
JsonNode playersNode = rootNode.get("players");
|
|
|
if (playersNode != null && playersNode.isArray()) {
|
|
|
for (JsonNode playerNode : playersNode) {
|
|
|
- int id = playerNode.get("id").asInt();
|
|
|
+ long id = playerNode.get("id").asLong();
|
|
|
String name = playerNode.get("name").asText();
|
|
|
- playerMap.put(id, name);
|
|
|
+ int seat = playerNode.get("seat").asInt();
|
|
|
+
|
|
|
+ List<String> tags = new ArrayList<>();
|
|
|
+ if (seat == smallBlindSeat) {
|
|
|
+ tags.add("小盲");
|
|
|
+ sbPlayerName = name;
|
|
|
+ }
|
|
|
+ if (seat == bigBlindSeat) {
|
|
|
+ tags.add("大盲");
|
|
|
+ bbPlayerName = name;
|
|
|
+ }
|
|
|
+
|
|
|
+ playerInfoMap.put(id, new PlayerInfo(name, seat, tags));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
List<String> chineseActions = new ArrayList<>();
|
|
|
- JsonNode actionsNode = rootNode.get("actions");
|
|
|
|
|
|
+ // ✅ STEP 1: 插入盲注系统提示
|
|
|
+ chineseActions.add("[系统] ANTE:" + anteAmount);
|
|
|
+ chineseActions.add("[系统] 小盲(" + sbPlayerName + "):" + sbAmount);
|
|
|
+ chineseActions.add("[系统] 大盲(" + bbPlayerName + "):" + bbAmount);
|
|
|
+
|
|
|
+ // ✅ STEP 2: 添加原始动作
|
|
|
+ JsonNode actionsNode = rootNode.get("actions");
|
|
|
if (actionsNode != null && actionsNode.isArray()) {
|
|
|
for (JsonNode actionNode : actionsNode) {
|
|
|
String stageKey = actionNode.get("stage").asText();
|
|
|
@@ -57,21 +86,146 @@ public class ActionParserUtils {
|
|
|
String actionKey = actionNode.get("action").asText();
|
|
|
String action = ACTION_MAP.getOrDefault(actionKey, "未知操作");
|
|
|
|
|
|
- int playerId = actionNode.get("playerId").asInt();
|
|
|
+ long playerId = actionNode.get("playerId").asLong();
|
|
|
int addAmount = actionNode.get("addAmount").asInt();
|
|
|
int seatNumber = actionNode.get("seatNumber").asInt();
|
|
|
- String playerName = playerMap.getOrDefault(playerId, "未知玩家");
|
|
|
+
|
|
|
+ PlayerInfo playerInfo = playerInfoMap.get(playerId);
|
|
|
+ if (playerInfo == null) {
|
|
|
+ playerInfo = new PlayerInfo("未知玩家", seatNumber, Collections.emptyList());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建带标签的玩家名称
|
|
|
+ String playerNameWithTags = playerInfo.name;
|
|
|
+ if (!playerInfo.tags.isEmpty()) {
|
|
|
+ playerNameWithTags += "(" + String.join(" + ", playerInfo.tags) + ")";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 特殊处理:大盲在翻牌前免费过牌
|
|
|
+ boolean isPreflop = "PREFLOP".equals(stageKey);
|
|
|
+ boolean isBigBlind = playerInfo.tags.contains("大盲");
|
|
|
+ boolean isCallOrCheck = "CALL".equals(actionKey) || "CHECK".equals(actionKey);
|
|
|
+ boolean isBigBlindFreeAction = isPreflop && isBigBlind && (addAmount == 0 || addAmount == bbAmount);
|
|
|
+
|
|
|
+ String actionDetail = action;
|
|
|
+ if (isBigBlindFreeAction && "CALL".equals(actionKey)) {
|
|
|
+ actionDetail = "跟注(大盲免费过牌)";
|
|
|
+ }
|
|
|
|
|
|
String desc = String.format("[%s] 玩家 %s(座位%d)%s,加注金额为 %d",
|
|
|
- stage, playerName, seatNumber, action, addAmount);
|
|
|
+ stage, playerNameWithTags, seatNumber, actionDetail, addAmount);
|
|
|
|
|
|
chineseActions.add(desc);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // ✅ STEP 3: 添加 showdown 摊牌信息(使用 PokerCardParserUtils.parseHoleCardsV2)
|
|
|
+ JsonNode showdownNode = rootNode.get("showdown");
|
|
|
+ if (showdownNode != null && showdownNode.isArray() && showdownNode.size() > 0) {
|
|
|
+ Map<Long, String> holeCardsMap = new HashMap<>();
|
|
|
+ Map<Long, Integer> winAmountMap = new HashMap<>();
|
|
|
+
|
|
|
+ for (JsonNode sd : showdownNode) {
|
|
|
+ long playerId = -1;
|
|
|
+
|
|
|
+ // 优先使用 id
|
|
|
+ if (sd.has("id")) {
|
|
|
+ playerId = sd.get("id").asLong();
|
|
|
+ } else {
|
|
|
+ // 回退:通过 seatId 匹配
|
|
|
+ int seatId = sd.get("seatId").asInt();
|
|
|
+ for (Map.Entry<Long, PlayerInfo> entry : playerInfoMap.entrySet()) {
|
|
|
+ if (entry.getValue().seat == seatId) {
|
|
|
+ playerId = entry.getKey();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String holeCardsRaw = sd.has("holeCards") ? sd.get("holeCards").asText().trim() : "";
|
|
|
+ // ✅ 调用你已有的工具方法解析底牌
|
|
|
+ List<String> holeCardsList = PokerCardParserUtils.parseHoleCardsV2(holeCardsRaw);
|
|
|
+ String holeCardsFormatted = String.join(", ", holeCardsList);
|
|
|
+
|
|
|
+ int winAmount = sd.has("winAmount") ? sd.get("winAmount").asInt() : 0;
|
|
|
+
|
|
|
+ holeCardsMap.put(playerId, holeCardsFormatted);
|
|
|
+ if (winAmount > 0) {
|
|
|
+ winAmountMap.put(playerId, winAmount);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成摊牌描述
|
|
|
+ for (Map.Entry<Long, String> entry : holeCardsMap.entrySet()) {
|
|
|
+ long playerId = entry.getKey();
|
|
|
+ String formattedHoleCards = entry.getValue();
|
|
|
+ PlayerInfo playerInfo = playerInfoMap.get(playerId);
|
|
|
+ if (playerInfo == null) continue;
|
|
|
+
|
|
|
+ String playerNameWithTags = playerInfo.name;
|
|
|
+ if (!playerInfo.tags.isEmpty()) {
|
|
|
+ playerNameWithTags += "(" + String.join(" + ", playerInfo.tags) + ")";
|
|
|
+ }
|
|
|
+
|
|
|
+ int winAmount = winAmountMap.getOrDefault(playerId, 0);
|
|
|
+ String winText = winAmount > 0 ? ",+ " + winAmount : "";
|
|
|
+
|
|
|
+ String showdownDesc = String.format("[摊牌] 玩家 %s(座位%d)摊牌,底牌:%s%s",
|
|
|
+ playerNameWithTags, playerInfo.seat, formattedHoleCards, winText);
|
|
|
+
|
|
|
+ chineseActions.add(showdownDesc);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return chineseActions;
|
|
|
}
|
|
|
|
|
|
+ // 内部类:存储玩家信息(名称、座位、标签)
|
|
|
+ private static class PlayerInfo {
|
|
|
+ String name;
|
|
|
+ int seat;
|
|
|
+ List<String> tags;
|
|
|
+
|
|
|
+ public PlayerInfo(String name, int seat, List<String> tags) {
|
|
|
+ this.name = name;
|
|
|
+ this.seat = seat;
|
|
|
+ this.tags = new ArrayList<>(tags);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析盲注信息字符串:ante + 小盲(玩家) + 大盲(玩家)
|
|
|
+ */
|
|
|
+ public static String parseBlindsInfo(String json) throws Exception {
|
|
|
+ ObjectMapper mapper = new ObjectMapper();
|
|
|
+ JsonNode rootNode = mapper.readTree(json);
|
|
|
+
|
|
|
+ JsonNode blindsNode = rootNode.get("blinds");
|
|
|
+ if (blindsNode == null) return "未知盲注信息";
|
|
|
+
|
|
|
+ int anteAmount = blindsNode.get("ante").asInt();
|
|
|
+ int sbAmount = blindsNode.get("sb").asInt();
|
|
|
+ int bbAmount = blindsNode.get("bb").asInt();
|
|
|
+
|
|
|
+ int smallBlindSeat = rootNode.get("smallBlindSeat").asInt();
|
|
|
+ int bigBlindSeat = rootNode.get("bigBlindSeat").asInt();
|
|
|
+
|
|
|
+ String sbPlayerName = "未知";
|
|
|
+ String bbPlayerName = "未知";
|
|
|
+
|
|
|
+ JsonNode playersNode = rootNode.get("players");
|
|
|
+ if (playersNode != null && playersNode.isArray()) {
|
|
|
+ for (JsonNode player : playersNode) {
|
|
|
+ int seat = player.get("seat").asInt();
|
|
|
+ String name = player.get("name").asText();
|
|
|
+ if (seat == smallBlindSeat) sbPlayerName = name;
|
|
|
+ if (seat == bigBlindSeat) bbPlayerName = name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return String.format("ANTE(%d) + 小盲(%s) %d + 大盲(%s) %d",
|
|
|
+ anteAmount, sbPlayerName, sbAmount, bbPlayerName, bbAmount);
|
|
|
+ }
|
|
|
|
|
|
|
|
|
}
|