删除长麻冗余代码

master
zhouwei 2026-02-24 17:26:14 +08:00
parent c9eb0078d9
commit d3c6f363af
21 changed files with 20 additions and 5194 deletions

View File

@ -1,102 +1,6 @@
package robot.mj;
public class Config {
public static final int FENGDING_SCORE = 28;
public static final int XIPAI_SCORE = 10;
public static final int ANCHOU_SCORE = 10;
public static final String ROOM_CONFIG_ZIMO = "zimo";
public static final String ROOM_CONFIG_ZHUANGXIAN = "zhuangxian";
public static final String ROOM_CONFIG_NIAO = "niao";
public static final String ROOM_CONFIG_NIAO_TYPE = "niao_type";
public static final String ROOM_CONFIG_PIAO_NIAO = "piao_niao"; //0:不嫖 1:自由票 2:固定票
public static final String ROOM_CONFIG_PIAO_NIAO_AUTO = "auto_piao"; //piao fen
public static final String ROOM_CONFIG_PIAO_NIAO_OPT = "piao_niao_opt"; //piao fen
public static final String ROOM_CONFIG_ZT_LIULIUSHUN = "zhongtuliuliushun";
public static final String ROOM_CONFIG_ZT_DASIXI = "zhongtusixi";
public static final String ROOM_CONFIG_QS_JIEJIEGAO = "jiejiegao";
public static final String ROOM_CONFIG_QS_SANTONG = "santong";
public static final String ROOM_CONFIG_QS_YIZHIHUA = "yizhihua";
public static final String ROOM_CONFIG_QUEYIMEN = "queyimen";
public static final String ROOM_CONFIG_FENGDING = "fengding";
public static final String ROOM_CONFIG_FENGDING_SCORE = "fengding_score";
public static final String ROOM_CONFIG_XIPAI = "xi_pai";
public static final String ROOM_CONFIG_XIPAI_SCORE = "xi_pai_score";
public static final String ROOM_CONFIG_ANCHOU_SCORE = "an_chou_score";
public static final String ROOM_CONFIG_DIFEN_SCORE = "difen_score";
public static final String ROOM_CONFIG_NIAOFEN_SCORE = "niaofen_score";
public static final String ROOM_CONFIG_NIAOFEN_OPT = "niaofen_opt"; //0中鸟加分//1中鸟加倍
public static final String ROOM_CONFIG_KAI_GONG = "kai_gong"; //0:开杠2张1:开杠四张
public static final int NIAO_TYPE_ADD = 0;
public static final int NIAO_TYPE_DOUBLE = 1;
public static final int NIAO_TYPE_CS2NIAO = 2;
public static final String ROOM_CONFIG_QS_JTYN = "two_pair";
public static final String ROOM_CONFIG_NO_JIANG = "no_jiang";
public static final String ROOM_CONFIG_NATIVE_HU = "native_hu";
public static final String ROOM_CONFIG_FOUR_WIN = "four_win";
public static final String SETTLE_XIAO_DIAN_PAO = "xiao_dian_pao";
public static final String SETTLE_XIAO_JIE_PAO = "xiao_jie_pao";
public static final String SETTLE_XIAO_ZIMO = "xiao_zimo";
public static final String SETTLE_DA_DIAN_PAO = "da_dian_pao";
public static final String SETTLE_DA_JIE_PAO = "da_jie_pao";
public static final String SETTLE_DA_ZIMO = "da_zimo";
public static final String GAME_EVT_PLAYER_DEAL = "811";
public static final String GAME_DIS_CARD = "611";
public static final String GAME_EVT_DISCARD = "812";
public static final String GAME_EVT_DISCARD_TIP = "813";
public static final String GAME_EVT_FZTIPS = "814";
public static final String GAME_ACTION = "612";
public static final String GAME_EVT_ACTION = "815";
public static final String GAME_EVT_HU = "816";
public static final String GAME_EVT_RESULT1 = "817";
public static final String GAME_EVT_RESULT2 = "818";
public static final String GAME_EVT_DRAW = "819";
public static final String GAME_EVT_CHANGE_ACTIVE_PLAYER = "820";
public static final String GAME_EVT_NIAO = "821";
public static final String GAME_EVT_QSTIP = "822";
public static final String GAME_EVT_QSWIN = "823";
public static final String GAME_EVT_OPENKONG = "824";
public static final String GAME_EVT_HAIDITIP = "825";
public static final String GAME_EVT_PIAONIAO_TIP = "833";
public static final String GAME_EVT_PIAONIAO = "834";
public static final String GAME_EVT_TING_TIP = "835";
public static final String GAME_EVT_TING = "836";
public static final String CREATE_ROOM_ROBOT = "create_room_for_robot";
public static final String INIT_CONNECTION = "init_connection";
@ -111,16 +15,6 @@ public class Config {
*/
public static final String GAME_READY = "2003";
/**
* 退 - robot_mgr to robot_mj_cs
*/
public static final String EXIT_ROOM = "2005";
/**
* - robot_mgr to robot_mj_cs
*/
public static final String RECONNECT = "2006";
/**
* - robot_mj_cs to game_mj_cs
*/
@ -131,8 +25,4 @@ public class Config {
*/
public static final String JOIN_ROOM_CS = "1002";
/**
* 退 - robot_mgr to game_mj_cs
*/
public static final String EXIT_ROOM_CS = "1005";
}

View File

@ -1,9 +0,0 @@
package robot.mj;
public class EXActionEvent {
public static final String EVENT_ACTION = "action";
public static final String EVENT_DISCARD = "discard";
}

View File

@ -6,18 +6,12 @@ import com.robot.GameController;
import com.robot.MainServer;
import com.robot.data.Player;
import com.robot.data.Room;
import com.taurus.core.entity.ITObject;
import com.taurus.core.entity.TObject;
import com.taurus.core.plugin.redis.Redis;
import com.taurus.permanent.TPServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import robot.mj.info.RobotUser;
import taurus.client.NetManager;
import taurus.client.TaurusClient;
import java.util.concurrent.TimeUnit;
import static robot.mj.EXGameController.robotRoomMapping;
@ -29,8 +23,6 @@ public class EXMainServer extends MainServer{
private static final Logger log = LoggerFactory.getLogger(EXMainServer.class);
private static final RobotConnectionManager robotConnectionManager = new RobotConnectionManager();
private static final EXGameController exGameController = new EXGameController();
private volatile boolean connectionCheckRunning = true;
@Override
public void onStart() {
@ -68,48 +60,6 @@ public class EXMainServer extends MainServer{
}
}
// TPServer.me().getTimerPool().scheduleAtFixedRate(new Runnable() {
// @Override
// public void run() {
//
// for(Map.Entry<String, RobotUser> entry : robotRoomMapping.entrySet()) {
// RobotUser robotUser = entry.getValue();
// //1、登录
// //判断是否登录
// if(!robotUser.isLogin){
// robotConnectionManager.login(robotUser);
// }
// /*//2、链接
// //判断是否链接
// System.out.println("robotUser.isconnect"+robotUser.getIsconnect());
// if(!robotUser.getIsconnect()){
// robotConnectionManager.connectGame(robotUser);
// }else{
// robotConnectionManager.renconnect(robotUser);
// }
//
//
// //4、加入房间
// if(robotUser.getStatus()==0){
// //没状态时候进入加入房间
// ITObject params = new TObject();
// params.putString("connecId", robotUser.getRoomId()+"_"+robotUser.getRobotId());
// params.putString("roomId", robotUser.getRoomId());
// params.putString("groupId", robotUser.getRobotGroupid());
// params.putString("session", "{user}:"+robotUser.getRobotId());
// exGameController.joinRoom(null, params, robotUser.getClient().getId());
// }
// System.out.println("robotUser.getIntoRoomTime()"+robotUser.getIntoRoomTime());
// System.out.println("robGetTiem"+robotConnectionManager.getTime());
// if(robotUser.getIntoRoomTime()+6<=robotConnectionManager.getTime()){
// //5、退出房间
// robotConnectionManager.outoRoom(robotUser);
// }*/
//
// }
// }
// }, 0, 5 ,TimeUnit.SECONDS);
//5、干活
log.info("长沙麻将机器人服务器已启动");
log.info("服务器将监听端口 {} 用于接收robot_mgr管理协议", gameSetting.port);
@ -157,8 +107,6 @@ public class EXMainServer extends MainServer{
public void onStop() {
super.onStop();
// 停止连接检查线程
connectionCheckRunning = false;
log.info("长沙麻将机器人服务器已停止");
}
}

View File

@ -1,15 +1,7 @@
package robot.mj;
import com.robot.Util;
import com.robot.data.Player;
import com.robot.data.Room;
import com.robot.data.Score;
import com.taurus.core.entity.ITArray;
import com.taurus.core.entity.ITObject;
import com.taurus.core.entity.TArray;
import com.taurus.core.entity.TObject;
import java.util.*;
/**
*

View File

@ -7,34 +7,13 @@ import java.util.Map;
public class EXRoom extends Room {
//
public EXRoom(String roomid, Map<String, String> redis_room_map) {
super(roomid, redis_room_map);
}
public void checkAction() {
}
@Override
protected void roomResult() {
}
@Override
public void endGame() {
super.endGame();

View File

@ -306,8 +306,8 @@ public class RobotConnectionManager {
}
}
}
}finally {
}catch (Exception e) {
e.printStackTrace();
}
}else {
renconnect(robotUser);
@ -343,7 +343,7 @@ public class RobotConnectionManager {
jedis2.hset(getStart, key, "2");
}
}
huNanChangSha.cardInHead(command, message, client);
huNanChangSha.cardInHead(command, message);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
@ -363,7 +363,7 @@ public class RobotConnectionManager {
Map<Integer, List<Integer>> currentPlayermingsMap = getPlayermingsMap(connecId);
Map<Integer, List<Integer>> currentPlayerzisMap = getPlayerzisMap(connecId);
// 清空旧数据,用新数据完全覆盖
//清空旧数据 用新数据完全覆盖
currentPlayerOutcardsMap.clear();
currentPlayerchisMap.clear();
currentPlayerpengsMap.clear();
@ -376,7 +376,6 @@ public class RobotConnectionManager {
int playerId = playerData.getInt("playerId");
ITArray outcardsArray = playerData.getTArray("outcards");
// 转换为List<Integer>
List<Integer> outcardsList = new ArrayList<>();
for (int j = 0; j < outcardsArray.size(); j++) {
outcardsList.add(outcardsArray.getInt(j));
@ -384,7 +383,6 @@ public class RobotConnectionManager {
//存储到当前连接的Map中覆盖旧数据
currentPlayerOutcardsMap.put(playerId, outcardsList);
}
}
@ -455,7 +453,7 @@ public class RobotConnectionManager {
}
//摸牌
else if ("819".equalsIgnoreCase(command)) {
huNanChangSha.getCard(command, message, client);
huNanChangSha.getCard(command, message);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
@ -580,7 +578,6 @@ public class RobotConnectionManager {
if (playerId == paramRobotId) {
String gpid = jedis0.hget(roomKey, "gpid");
String gpId = jedis0.hget(roomKey, "group");
//更新机器人剩余数量
if (count != null && count.containsKey(Integer.parseInt(gpid))) {
@ -624,7 +621,6 @@ public class RobotConnectionManager {
count.put(pid, currentValue - 1);
}
}
//更新机器人剩余数量
updateLeftoverRobot(Integer.parseInt(robotUser.getRobotId()));
}
@ -677,7 +673,6 @@ public class RobotConnectionManager {
client.send("612", params, response -> {
});
}
} catch (Exception e) {
throw new RuntimeException(e);

View File

@ -37,7 +37,6 @@ public class RoomCreator {
log.error("没有可用的房间IDfree_room队列为空");
return null;
}
//Redis.use("group1_db1").lpush("free_room", newRoomId);
String roomKey = "room:" + newRoomId;
@ -48,7 +47,6 @@ public class RoomCreator {
if (groupInfo.isEmpty()) {
log.warn("群组信息不存在群组ID: {},正在创建默认群组信息", groupId);
createDefaultGroupInfo(jedis11, groupId);
groupInfo = jedis11.hgetAll(groupKey);
}
//确保游戏配置存在
@ -58,7 +56,6 @@ public class RoomCreator {
if (gameInfo.isEmpty()) {
log.warn("游戏配置不存在玩法ID: {},正在创建长沙麻将默认游戏配置", wanfaId);
createDefaultGameConfig(jedis0, wanfaId);
gameInfo = jedis0.hgetAll(gameConfigKey);
}
//获取玩法配置

View File

@ -21,13 +21,6 @@ import com.taurus.web.Controller;
import com.taurus.web.WebException;
import redis.clients.jedis.Jedis;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@ -36,71 +29,7 @@ import java.util.Set;
public class AccountBusiness extends Controller {
private static Logger logger = Logger.getLogger(AccountBusiness.class);
public static String request(String httpUrl, String httpArg) {
BufferedReader reader = null;
String result = null;
StringBuffer sbf = new StringBuffer();
httpUrl = httpUrl + "?" + httpArg;
try {
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
InputStream is = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String strRead = reader.readLine();
if (strRead != null) {
sbf.append(strRead);
while ((strRead = reader.readLine()) != null) {
sbf.append("\n");
sbf.append(strRead);
}
}
reader.close();
result = sbf.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static String md5(String plainText) {
StringBuffer buf = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(plainText.getBytes());
byte b[] = md.digest();
int i;
buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0)
i += 256;
if (i < 16)
buf.append("0");
buf.append(Integer.toHexString(i));
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return buf.toString();
}
public static String encodeUrlString(String str, String charset) {
String strret = null;
if (str == null)
return str;
try {
strret = java.net.URLEncoder.encode(str, charset);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return strret;
}
private final ITObject fillLoginData(String session, int accountid) {
private ITObject fillLoginData(String session, int accountid) {
ITObject resData = TObject.newInstance();
ITObject userData = TObject.newInstance();
resData.putTObject("account", userData);
@ -151,8 +80,7 @@ public class AccountBusiness extends Controller {
return resData;
}
public final ITObject fastLogin(int userid) throws Exception {
public final ITObject fastLogin(int userid) {
Jedis jedis = Redis.use("group1_db0").getJedis();
ITObject resData = null;
try {
@ -189,7 +117,6 @@ public class AccountBusiness extends Controller {
public final ITObject idPasswordLogin(int id, String password) throws Exception {
logger.info("id:" + id + " login");
Jedis jedis0 = Redis.use("group1_db0").getJedis();
@ -214,8 +141,6 @@ public class AccountBusiness extends Controller {
}
String idPwdBan = Redis.use("group1_db0").get(id + "_login_ban");
if (StringUtil.isNotEmpty(idPwdBan)) {
System.out.println("进入了77777777777777777777");
@ -261,17 +186,6 @@ public class AccountBusiness extends Controller {
if (resultArray.size() > 0) {
this.setSession(session);
String old_nick = acc_bean.nick;
String old_portrait = acc_bean.portrait;
// String new_nick = reqData.getUtfString("nick");
// String new_portrait = reqData.getUtfString("portrait");
// if (!old_nick.equals(new_nick) || !old_portrait.equals(new_portrait)) {
// ITObject userData1 = TObject.newInstance();
// userData1.putUtfString("nick", userData.getUtfString("nick"));
// userData1.putUtfString("portrait", userData.getUtfString("portrait"));
// userData1.putInt("sex", userData.getInt("sex"));
// updateSession(userData, accountid);
// }
}
ITObject resData = fillLoginData(session, accountid);
@ -283,13 +197,6 @@ public class AccountBusiness extends Controller {
Redis.use("group1_db0").hset(token, "create_time", "" + System.currentTimeMillis() / 1000);
Redis.use("group1_db0").expire(token, 172800);
// Set<String> allToken = Redis.use("group1_db0").smembers(session + "_token");
// for (String temp : allToken) {
// if (!Redis.use("group1_db0").exists(temp)) {
// Redis.use("group1_db0").srem(session + "_token", temp);
// logger.info("delte timeout token:" + temp);
// }
// }
System.out.println("进入了2222222222222");
long tokenNum = Redis.use("group1_db0").scard(session + "_token");
@ -350,9 +257,8 @@ public class AccountBusiness extends Controller {
/**
*
* @return
* @throws Exception
*/
private final int UpdateUserData(ITObject reqData, long id) throws Exception {
private int UpdateUserData(ITObject reqData, long id) {
ITObject userData = TObject.newInstance();
userData.putInt("id", (int) id);

View File

@ -1,113 +0,0 @@
package robot.mj.network;
import com.robot.MainServer;
import com.taurus.core.entity.ITObject;
import com.taurus.core.entity.TObject;
import com.taurus.core.util.Logger;
import com.taurus.permanent.data.Session;
import java.util.concurrent.atomic.AtomicInteger;
/**
* TCP
*/
public class TaurusTcpListener {
private static final Logger log = Logger.getLogger(TaurusTcpListener.class);
private AtomicInteger connectionCount = new AtomicInteger(0);
private volatile boolean running = false;
/**
* TCP
*/
public void start() {
if (running) {
log.warn("TCP监听已在运行中");
return;
}
try {
running = true;
log.info("基于Taurus框架的TCP监听已启动");
} catch (Exception e) {
log.error("启动Taurus TCP监听失败", e);
}
}
/**
* TCP
*/
public void stop() {
if (!running) {
return;
}
try {
running = false;
log.info("Taurus TCP监听已停止");
} catch (Exception e) {
log.error("停止Taurus TCP监听时发生错误", e);
}
}
/**
*
*/
public void sendWelcomeMessage(Session session) {
try {
ITObject welcomeMsg = TObject.newInstance();
welcomeMsg.putString("type", "welcome");
welcomeMsg.putString("message", "连接到长沙麻将机器人服务器");
welcomeMsg.putInt("server_id", 7701);
welcomeMsg.putLong("timestamp", System.currentTimeMillis());
MainServer.instance.sendResponse(0, 0, welcomeMsg, session);
log.debug("已发送欢迎消息 - SessionId: {}", session.getId());
} catch (Exception e) {
log.error("发送欢迎消息失败", e);
}
}
/**
*
*/
public void processAndRespond(Session session, ITObject requestData, int gid) {
try {
ITObject response = TObject.newInstance();
response.putString("type", "response");
response.putTObject("original_data", requestData);
response.putBoolean("processed", true);
response.putLong("timestamp", System.currentTimeMillis());
//发送响应
MainServer.instance.sendResponse(gid, 0, response, session);
log.info("已发送响应 - SessionId: {}", session.getId());
} catch (Exception e) {
log.error("处理客户端消息时发生错误", e);
//发送错误响应
ITObject errorResponse = TObject.newInstance();
errorResponse.putString("type", "error");
errorResponse.putString("message", "处理请求时发生错误: " + e.getMessage());
errorResponse.putLong("timestamp", System.currentTimeMillis());
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
}
}
public boolean isRunning() {
return running;
}
public int getConnectionCount() {
return connectionCount.get();
}
}

View File

@ -3,77 +3,6 @@ package taurus.util;
import java.util.*;
public class ChangshaWinSplitCard {
// 获取数值
// 获取数值
public static int GetCardValue(int cbCardData) {
return cbCardData % 100;
}
// 获取花色
public static int GetCardColor(int cbCardData) {
return cbCardData / 100;
}
// 扑克转换
public static int SwitchToCardData(int cbCardIndex) {
int cbCardColor = cbCardIndex / 10;
int cbCardValue = cbCardIndex % 10;
if (cbCardIndex < 27) { // 9 -> 200 + 1 //10 -> 202 //11 -> 203 // 17 -> 209 // 18 -> 301 19->302 20 ->
// 303 26->309
if (cbCardValue + (cbCardColor + 1) >= 10) {
return (cbCardColor + 2) * 100 + (cbCardValue + (cbCardColor + 1)) % 10 + 1;
} else {
return (cbCardColor + 1) * 100 + cbCardValue + (cbCardColor + 1);
}
} else { // 27 -> 400 //28 -> 403 // 29 -> 406 // 30 -> 409 //31 -> 412 // 32 -> 415 //
// 33 -> 418
if (cbCardValue + (cbCardColor + 1) >= 10) {
return (cbCardColor + 2) * 100 + (cbCardValue + (cbCardColor + 1)) % 10 * 3;
} else {
return (cbCardColor + 1) * 100 + (cbCardValue + cbCardColor) * 3;
}
}
}
// 扑克转换
public static int SwitchToCardIndex(int cbCardData) {
// 扑克属性
int cbCardColor = GetCardColor(cbCardData);
int cbCardValue = GetCardValue(cbCardData);
if (cbCardColor <= 3) {
return (cbCardColor - 1) * 10 + cbCardValue - cbCardColor;
} else {
return (cbCardColor - 1) * 10 + cbCardValue / 3 - cbCardColor + 1;
}
}
// 扑克转换
public static int[] SwitchToCardData(List<Integer> cardInhand) {
int[] cardIndex = new int[34];
for (int i = 0; i < cardIndex.length; i++) {
cardIndex[i] = 0;
}
for (int i = 0; i < cardInhand.size(); i++) {
int pos = SwitchToCardIndex(cardInhand.get(i));
cardIndex[pos]++;
}
return cardIndex;
}
// 扑克转换
public static List<Integer> SwitchToCardIndex(int[] cardIndex) {
List<Integer> cardIndexList = new ArrayList<Integer>();
for (int i = 0; i < cardIndex.length; i++) {
for (int j = 0; j < cardIndex[i]; j++) {
int card = SwitchToCardData(i);
cardIndexList.add(card);
}
}
return cardIndexList;
}
// 统计牌数
public static int[][] countTiles(List<Integer> cardInHand) {
@ -448,16 +377,6 @@ public class ChangshaWinSplitCard {
return cardInHand;
}
public static int ckeckOutCard(List<Integer> cardInhand) {
int card = 0;
Collections.sort(cardInhand);
System.out.println("手牌:" + cardInhand);
Map<String, Object> map = new HashMap<String, Object>();
checkNormalHu(cardInhand, map);
return card;
}
public static List<Integer> checktingpai(List<Integer> cardhand) {
List<Integer> tpcards = new ArrayList<>();
List<Integer> tmphc = cardhand;
@ -486,30 +405,6 @@ public class ChangshaWinSplitCard {
return tpcards;
}
public static boolean isJiangPai(int card) {
if (card % 100 == 2 || card % 100 == 5 || card % 100 == 8) {
return true;
}
return false;
}
public static int checkduijiang(List<Integer> cardInHand, Map<String, List<Integer>> map) {
Map<Integer, Integer> countMap = new HashMap<>();
for (Integer item : cardInHand) {
countMap.put(item, countMap.getOrDefault(item, 0) + 1);
}
int jiangnum = 0;
for (int key : countMap.keySet()) {
if (isJiangPai(key) && countMap.get(key) >= 2) {
jiangnum++;
List<Integer> tmpI = new ArrayList<>();
tmpI.add(key);
map.put("jiangcard", tmpI);
}
}
return jiangnum;
}
// 分析最优出牌
public static List<Integer> analyzeBestDiscard(List<Integer> cardInHand) {
@ -635,89 +530,6 @@ public class ChangshaWinSplitCard {
return zuizhongchupai;
}
// 计算听牌数量(简化版,只计算数量不具体分析是哪些牌)
private static int countTingCards(List<Integer> hand) {
int tingCount = 0;
// 只尝试添加万、筒、条牌1-9
for (int type = 1; type <= 3; type++) {
for (int value = 1; value <= 9; value++) {
int testCard = type * 100 + value;
// 模拟添加这张牌
List<Integer> testHand = new ArrayList<>(hand);
testHand.add(testCard);
Collections.sort(testHand);
// 检查是否能胡牌
Map<String, Object> testMap = new HashMap<>();
if (checkNormalHu(testHand, testMap) == 0) {
tingCount++;
}
}
}
// 风牌和箭牌(可能性较小,但也要考虑)
for (int type = 4; type <= 5; type++) {
int max = (type == 4) ? 4 : 3;
for (int value = 1; value <= max; value++) {
int testCard = type * 100 + value;
List<Integer> testHand = new ArrayList<>(hand);
testHand.add(testCard);
Collections.sort(testHand);
Map<String, Object> testMap = new HashMap<>();
if (checkNormalHu(testHand, testMap) == 0) {
tingCount++;
}
}
}
return tingCount;
}
// 或者使用更简洁的lambda写法确保能进入
// 或者更灵活的版本,可以指定优先级
public static Integer selectBestCardByPriority(List<Integer> cards) {
if (cards == null || cards.isEmpty()) {
return null;
}
Integer bestCard = null;
int bestPriority = Integer.MAX_VALUE;
for (Integer card : cards) {
int value = card % 100;
int priority = getCardPriority(value);
if (priority < bestPriority) {
bestPriority = priority;
bestCard = card;
} else if (priority == bestPriority) {
// 优先级相同,比较牌值(小的优先)
if (bestCard == null || value < (bestCard % 100)) {
bestCard = card;
}
}
}
return bestCard;
}
// 牌的优先级(数字越小优先级越高)
private static int getCardPriority(int value) {
if (value == 9)
return 1;
if (value == 1)
return 2;
if (value == 2 || value == 8)
return 3; // 靠近边张
if (value >= 3 && value <= 7)
return 4; // 中间牌
return 5; // 其他
}
public static Integer selectBestCardRemove258(List<Integer> cards) {
if (cards == null || cards.isEmpty()) {
return null;

View File

@ -21,5 +21,4 @@ public class HandAnalysis {
public boolean hasPengPengHu = false; //是否有碰碰胡
public Set<Integer> usedInPairs = new HashSet<>(); //用于对子/将的牌
public List<Integer> remainingCards = new ArrayList<>(); //剩余需要分析的牌
public int lastDrawnCard = 0; //最后摸的牌
}

View File

@ -7,26 +7,6 @@ import com.robot.Util;
public class Paixing {
private final static boolean qs_yijihua_check(Map<Integer, Integer> cardMap,int se,int index) {
Integer num = cardMap.get(se+index);
if(num!=null&&num==1) {
for(int i=1;i<=9;++i) {
if(i !=index) {
if(cardMap.containsKey(se+i)){
return false;
}
}
}
return true;
}
return false;
}
public static void main(String[] args) {
List<Integer> cardInhand = new java.util.ArrayList<>();
List<Integer> opCards = new java.util.ArrayList<>();
@ -179,10 +159,6 @@ public class Paixing {
}
}
public static boolean checkWin(Map<Integer, WinCardType> map, List<Integer> opCards, List<Integer> cardInhand,int drawCard, int difen) {
return checkWin(map,opCards,cardInhand,drawCard,true, difen);
}
public static boolean checkWin(Map<Integer, WinCardType> map, List<Integer> opCards, List<Integer> cardInhand,int drawCard,boolean jiang, int difen) {
int qixiaodui = qixiaodui(opCards,cardInhand, drawCard);
if (qixiaodui != -1) {
@ -270,19 +246,4 @@ public class Paixing {
return win.tryWin();
}
static public boolean tingKongCheck(List<Integer> opCards,List<Integer> cardInhand,int kongCard,boolean jiang) {
if (quanqiuren(opCards,cardInhand, 0))return true;
if (jiangjiang(opCards,cardInhand, kongCard))return true;
if (pongpong(opCards,cardInhand, 0,false))return true;
if (qingyise(opCards,cardInhand, kongCard)) {
WinCard win = new WinCard(cardInhand, 0);
win.jiang = false;
return win.tryWin();
}
WinCard win = new WinCard(cardInhand, 0);
win.jiang = jiang;
return win.tryWin();
}
}

View File

@ -19,58 +19,6 @@ public class PlayerState {
this.isZhuang = false;
}
public PlayerState(List<Integer> handCards) {
this();
this.handCards = new ArrayList<>(handCards);
}
// 添加碰牌组
public void addPongGroup(List<Integer> pongGroup) {
if (pongGroup.size() == 3) {
this.pongGroups.add(new ArrayList<>(pongGroup));
}
}
// 添加杠牌组
public void addGangGroup(List<Integer> gangGroup) {
if (gangGroup.size() == 4) {
this.gangGroups.add(new ArrayList<>(gangGroup));
}
}
// 添加吃牌组
public void addChiGroup(List<Integer> chiGroup) {
if (chiGroup.size() == 3) {
this.chiGroups.add(new ArrayList<>(chiGroup));
}
}
// 获取所有碰牌(扁平化)
public List<Integer> getAllPongCards() {
List<Integer> all = new ArrayList<>();
for (List<Integer> group : pongGroups) {
all.addAll(group);
}
return all;
}
// 获取所有杠牌(扁平化)
public List<Integer> getAllGangCards() {
List<Integer> all = new ArrayList<>();
for (List<Integer> group : gangGroups) {
all.addAll(group);
}
return all;
}
// 获取所有吃牌(扁平化)
public List<Integer> getAllChiCards() {
List<Integer> all = new ArrayList<>();
for (List<Integer> group : chiGroups) {
all.addAll(group);
}
return all;
}
// 获取碰牌组数
public int getPongGroupCount() {
@ -87,8 +35,4 @@ public class PlayerState {
return chiGroups.size();
}
// 获取总组数
public int getTotalGroupCount() {
return pongGroups.size() + gangGroups.size() + chiGroups.size();
}
}

View File

@ -1,50 +1,9 @@
package taurus.util;
import com.robot.Util;
import robot.mj.handler.HuNanChangSha;
import java.util.*;
public class TinHuChi {
public static boolean isMoreThanLast = false;
public static int lastTingCount = 0;
public static int[][] countTiles(List<Integer> cardInHand) {
int[][] counts = new int[5][10]; // 类型×值
for (Integer card : cardInHand) {
if (card == 0) {
continue;
}
counts[card / 100 - 1][card % 100]++;
}
return counts;
}
public static boolean isJiangPai(int card){
if (card%100==2||card%100==5||card%100==8){
return true;
}
return false;
}
public static int checkduijiang(List<Integer> cardInHand) {
Map<Integer, Integer> countMap = new HashMap<>();
for (Integer item : cardInHand) {
countMap.put(item, countMap.getOrDefault(item, 0) + 1);
}
int jiangnum = 0;
for (int key : countMap.keySet()) {
if (isJiangPai(key)&&countMap.get(key)>=2){
jiangnum++;
}
}
return jiangnum;
}
/**
*
@ -120,149 +79,6 @@ public class TinHuChi {
}
// List<Integer> temphand = new ArrayList<>();
// temphand.addAll(hand1);
// temphand.add(104);
// Util.removeCard(temphand, 104, 3);
// List<Integer> checktingpai1 = TinHuChi.checktingpai(temphand);
// System.out.println("checktingpai1" + checktingpai1);
//hand1.add(101);
// Map<String, Object> map = new HashMap<>();
// Map<String, Object> map2 = new HashMap<>();
//
// List<List<Integer>> lists = checkChi(hand1, addcard);
// //吃之前的逻辑
// int jiangnum = checkduijiang(hand1);
// hand1.add(addcard);
// System.out.println(hand1);
// ChangshaWinSplitCard.checkNormalHu(hand1, map);
//
// System.out.println("checkNormalHu" + map.get("cardResiue"));
//
// System.out.println("checktingpai1" + lists);
// int index = 0;
// int flag = 0;
// for (List<Integer> list : lists) {
// List<Integer> temphand = hand1;
// //temphand.add(addcard);
// Util.removeCard(temphand,list.get(0),1);
// Util.removeCard(temphand,list.get(1),1);
// Util.removeCard(temphand,list.get(2),1);
// System.out.println("temphand" + temphand);
// ChangshaWinSplitCard.checkNormalHu(temphand, map2);
// //判断两个map是否找到更优
// System.out.println("map1:"+Integer.parseInt(map.get("remainingMelds").toString()));
// System.out.println("map2:"+Integer.parseInt(map2.get("remainingMelds").toString()));
//
//
// if (Integer.parseInt(map2.get("remainingMelds").toString()) < Integer.parseInt(map.get("remainingMelds").toString()) ){
// flag=index+1;
// }else if (Integer.parseInt(map2.get("remainingMelds").toString()) == Integer.parseInt(map.get("remainingMelds").toString())){
// int size2 = ((List<Integer>) map2.get("cardResiue")).size();
// System.out.println("size2" + size2);
// int size1 = ((List<Integer>) map.get("cardResiue")).size();
// System.out.println("size1" + size1);
// if (size2 < size1){
// flag=index+1;
// }
//
// //如果手里没有将,则可以吃
// if (jiangnum>0) {
// int chihoujiangnum = checkduijiang(temphand);
// if (chihoujiangnum>0){
// //吃之后还有将
// flag=index+1;
// }
// }else{
// System.out.println("没队将");
// //孤章1张 差一手 不是将 而且card不是将
// if (Integer.parseInt(map.get("remainingMelds").toString())==1&&size1==1&&!isJiangPai(((List<Integer>) map.get("cardResiue")).get(0))&&!isJiangPai(addcard)){
// //吃
// break;
// }
// flag=index+1;
// // break;
// }
//
//
//
// }
//
// index ++ ;
// System.out.println("checkNormalHu2" + map2);
// }
// System.out.println("flag" + flag);
/*List<Integer> shifoutingpai = shifoutingpai(hand1);
System.out.println("shifoutingpai" + shifoutingpai);
//
// List<Integer> checktingpai = checktingpai(hand1);
// System.out.println("checktingpai" + checktingpai);
//
//
List<List<Integer>> lists = checkChi(hand1, addcard);
int index = 0;
int flag = 0;
for (List<Integer> list : lists) {
List<Integer> temphand = hand1;
temphand.add(addcard);
Util.removeCard(temphand,list.get(0),1);
Util.removeCard(temphand,list.get(1),1);
Util.removeCard(temphand,list.get(2),1);
List<Integer> checktingpai1 = checktingpai(temphand);
if (checktingpai1.size() > 0) {
flag =index +1;
}
index ++ ;
System.out.println("checktingpai1" + checktingpai1);
}
System.out.println("flag" + flag);
System.out.println(lists);
*/
public static List<Integer> shifoutingpai(List<Integer> cardhand) {
List<Integer> tpcards = new ArrayList<>();
List<Integer> tmphc = cardhand;
for (int i = 0; i < cardhand.size(); i++) {
int tmpcard = tmphc.get(i);
// tmphc.remove(i);
for (int j = 101; j <= 109; j++) {
WinCard win = new WinCard(tmphc, j);
if (win.tryWin()) {
if (!tpcards.contains(j)) {
tpcards.add(j);
}
}
}
for (int j = 201; j <= 209; j++) {
WinCard win = new WinCard(tmphc, j);
if (win.tryWin()) {
if (!tpcards.contains(j)) {
tpcards.add(j);
}
}
}
// tmphc.add(tmpcard);
}
return tpcards;
}
public static List<Integer> checktingpai(List<Integer> cardhand) {
List<Integer> tpcards = new ArrayList<>();
List<Integer> tmphc = cardhand;
@ -291,714 +107,6 @@ public class TinHuChi {
return tpcards;
}
public static List<List<Integer>> checkChi(List<Integer> hand, int card) {
List<List<Integer>> result = new ArrayList<>();
if (Util.checkCard(card-1, hand ) &&Util.checkCard(card - 2, hand)) {
List<Integer> opcard = new ArrayList<>();
opcard.add(card-1);
opcard.add(card - 2);
opcard.add(card);
result.add(opcard);
}
if (Util.checkCard(card + 1, hand) && Util.checkCard(card - 1, hand)) {
List<Integer> opcard = new ArrayList<>();
opcard.add(card + 1);
opcard.add(card - 1);
opcard.add(card);
result.add(opcard);
}
if (Util.checkCard(card + 1, hand) && Util.checkCard(card + 2, hand)) {
List<Integer> opcard = new ArrayList<>();
opcard.add(card + 1);
opcard.add(card + 2);
opcard.add(card);
result.add(opcard);
}
return result;
}
public static boolean canChi(List<Integer> handCards, int card) {
int type = card / 100;
int value = card % 100;
if (type >= 4) return false; // 字牌不能吃
System.out.println("\n要吃的牌: " + value + getTypeName(type));
System.out.println("当前手牌数量: " + handCards.size() + "张");
List<int[]> chiOptions = new ArrayList<>(); // 存储所有能吃的方式
// 检查三种吃法并记录
if (value >= 3) {
int prev2 = type * 100 + (value - 2);
int prev1 = type * 100 + (value - 1);
if (handCards.contains(prev2) && handCards.contains(prev1)) {
chiOptions.add(new int[]{prev2, prev1});
System.out.println(" 可以组成" + (value - 2) + (value - 1) + value + "顺子");
}
}
if (value >= 2 && value <= 8) {
int prev = type * 100 + (value - 1);
int next = type * 100 + (value + 1);
if (handCards.contains(prev) && handCards.contains(next)) {
chiOptions.add(new int[]{prev, next});
System.out.println(" 可以组成" + (value - 1) + value + (value + 1) + "顺子");
}
}
if (value <= 7) {
int next1 = type * 100 + (value + 1);
int next2 = type * 100 + (value + 2);
if (handCards.contains(next1) && handCards.contains(next2)) {
chiOptions.add(new int[]{next1, next2});
System.out.println(" 可以组成" + value + (value + 1) + (value + 2) + "顺子");
}
}
if (chiOptions.isEmpty()) {
System.out.println(" 没有能吃的方式");
return false; // 没有能吃的方式
}
System.out.println("发现" + chiOptions.size() + "种吃法");
// 记录所有能听牌的吃法及其听牌详情
List<TingChiOption> tingOptions = new ArrayList<>();
for (int[] chiPair : chiOptions) {
System.out.println("\n尝试吃法: 用" + (chiPair[0] % 100) + getTypeName(type) +
"和" + (chiPair[1] % 100) + getTypeName(type) +
"吃" + value + getTypeName(type));
// 检查这种吃法能听多少张牌以及听什么牌
TingResult tingResult = getTingResultAfterChi(handCards, card, chiPair[0], chiPair[1]);
if (tingResult != null && tingResult.tingCount > 0) {
tingOptions.add(new TingChiOption(chiPair, tingResult.tingCount, tingResult.tingCards, tingResult.discardCard));
System.out.println(" → 打" + (tingResult.discardCard % 100) + getTypeName(tingResult.discardCard / 100) +
"可听" + tingResult.tingCount + "张牌: " + formatCards(tingResult.tingCards));
} else {
System.out.println(" → 不能听牌");
}
}
// 如果有能听牌的吃法
if (!tingOptions.isEmpty()) {
// 选择听牌数量最多的吃法
tingOptions.sort((a, b) -> {
// 优先按听牌数量排序
if (b.tingCount != a.tingCount) {
return b.tingCount - a.tingCount;
}
// 如果听牌数量相同,可以考虑其他因素,比如听牌质量
return 0;
});
TingChiOption bestOption = tingOptions.get(0);
System.out.println("\n=== 选择最佳吃法 ===");
System.out.println("用" + (bestOption.chiPair[0] % 100) + getTypeName(type) +
"和" + (bestOption.chiPair[1] % 100) + getTypeName(type) +
"吃" + value + getTypeName(type));
System.out.println("打" + (bestOption.bestDiscard % 100) + getTypeName(bestOption.bestDiscard / 100));
System.out.println("听" + bestOption.tingCount + "张牌: " + formatCards(bestOption.tingCards));
// 分析听牌类型
analyzeTingType(bestOption.tingCards);
return true;
}
return false; // 所有吃法都不能形成好牌型
}
// 新增:获取吃牌后的听牌数量
public static int getTingCountAfterChi(List<Integer> handCards, int chiCard,
int remove1, int remove2) {
// 模拟吃牌
List<Integer> afterChi = new ArrayList<>(handCards);
afterChi.remove(Integer.valueOf(remove1));
afterChi.remove(Integer.valueOf(remove2));
Collections.sort(afterChi);
boolean needs258 = !checkSuitCount(afterChi);
int targetSizeAfterDiscard = afterChi.size() - 1;
int maxTingCount = 0;
Set<Integer> uniqueCards = new HashSet<>(afterChi);
for (int discardCard : uniqueCards) {
List<Integer> afterDiscard = new ArrayList<>(afterChi);
afterDiscard.remove(Integer.valueOf(discardCard));
Collections.sort(afterDiscard);
if (afterDiscard.size() == targetSizeAfterDiscard) {
int tingCount = countTingCards(afterDiscard, needs258);
maxTingCount = Math.max(maxTingCount, tingCount);
}
}
return maxTingCount;
}
// 新增:统计听牌数量
public static int countTingCards(List<Integer> hand, boolean needs258) {
if (hand.size() % 3 != 1) return 0; // 听牌时手牌应该是3n+1张
Set<Integer> tingCards = new HashSet<>();
Set<Integer> allCards = new HashSet<>();
// 生成所有可能的牌
for (int type = 1; type <= 3; type++) {
for (int value = 1; value <= 9; value++) {
allCards.add(type * 100 + value);
}
}
for (int testCard : allCards) {
List<Integer> tempHand = new ArrayList<>(hand);
tempHand.add(testCard);
if (canHu(tempHand, needs258)) {
tingCards.add(testCard);
}
}
return tingCards.size();
}
// 修改后的 TingChiOption 类
static class TingChiOption {
int[] chiPair;
int tingCount;
Set<Integer> tingCards;
int bestDiscard;
TingChiOption(int[] chiPair, int tingCount, Set<Integer> tingCards, int bestDiscard) {
this.chiPair = chiPair;
this.tingCount = tingCount;
this.tingCards = tingCards;
this.bestDiscard = bestDiscard;
}
}
// 新增:获取吃牌后的听牌结果
public static TingResult getTingResultAfterChi(List<Integer> handCards, int chiCard,
int remove1, int remove2) {
// 模拟吃牌
List<Integer> afterChi = new ArrayList<>(handCards);
afterChi.remove(Integer.valueOf(remove1));
afterChi.remove(Integer.valueOf(remove2));
Collections.sort(afterChi);
boolean needs258 = !checkSuitCount(afterChi);
int targetSizeAfterDiscard = afterChi.size() - 1;
TingResult bestResult = null;
Set<Integer> uniqueCards = new HashSet<>(afterChi);
for (int discardCard : uniqueCards) {
List<Integer> afterDiscard = new ArrayList<>(afterChi);
afterDiscard.remove(Integer.valueOf(discardCard));
Collections.sort(afterDiscard);
if (afterDiscard.size() == targetSizeAfterDiscard) {
Set<Integer> tingCards = getTingCards(afterDiscard, needs258);
int tingCount = tingCards.size();
if (tingCount > 0) {
if (bestResult == null || tingCount > bestResult.tingCount) {
bestResult = new TingResult(tingCount, tingCards, discardCard);
}
}
}
}
return bestResult;
}
// 新增:获取具体的听牌集合
public static Set<Integer> getTingCards(List<Integer> hand, boolean needs258) {
if (hand.size() % 3 != 1) return new HashSet<>(); // 听牌时手牌应该是3n+1张
Set<Integer> tingCards = new HashSet<>();
Set<Integer> allCards = new HashSet<>();
// 生成所有可能的牌
for (int type = 1; type <= 3; type++) {
for (int value = 1; value <= 9; value++) {
allCards.add(type * 100 + value);
}
}
for (int testCard : allCards) {
List<Integer> tempHand = new ArrayList<>(hand);
tempHand.add(testCard);
if (canHu(tempHand, needs258)) {
tingCards.add(testCard);
}
}
return tingCards;
}
// 新增:格式化牌显示
public static String formatCards(Set<Integer> cards) {
List<String> cardStrs = new ArrayList<>();
for (int card : cards) {
int type = card / 100;
int value = card % 100;
cardStrs.add(value + getTypeName(type));
}
return String.join(", ", cardStrs);
}
// 新增:记录听牌结果的类
static class TingResult {
int tingCount;
Set<Integer> tingCards;
int discardCard; // 打哪张牌能达到这个听牌
TingResult(int tingCount, Set<Integer> tingCards, int discardCard) {
this.tingCount = tingCount;
this.tingCards = tingCards;
this.discardCard = discardCard;
}
}
/**
* -
*/
public static boolean canTingAfterChiAndDiscard(List<Integer> handCards, int chiCard,
int remove1, int remove2) {
// 1. 模拟吃牌:移除两张牌,吃的牌不加入手牌
List<Integer> afterChi = new ArrayList<>(handCards);
afterChi.remove(Integer.valueOf(remove1));
afterChi.remove(Integer.valueOf(remove2));
Collections.sort(afterChi);
System.out.println(" 吃后手牌(" + afterChi.size() + "张): " + convertToReadable(afterChi));
// 2. 检查是否需要258将花色是否>=10张
System.out.println(chiCard);
System.out.println(afterChi);
boolean needs258 = !checkSuitCount(afterChi);
if (needs258) {
System.out.println(" 花色牌数不足10张需要258做将");
}
// 3. 根据手牌数量确定目标手牌数
int originalSize = handCards.size();
int targetSizeAfterDiscard;
if (originalSize == 13) {
// 标准情况13张手牌 -> 吃后11张 -> 打后10张
targetSizeAfterDiscard = 10;
} else if (originalSize == 14) {
// 你的例子14张手牌 -> 吃后12张 -> 打后11张
targetSizeAfterDiscard = 11;
} else {
// 其他情况根据吃后手牌数减1
targetSizeAfterDiscard = afterChi.size() - 1;
System.out.println(" 非标准手牌数,目标手牌数: " + targetSizeAfterDiscard);
}
// 4. 尝试打每一张不同的牌
Set<Integer> uniqueCards = new HashSet<>(afterChi);
boolean foundTing = false;
for (int discardCard : uniqueCards) {
List<Integer> afterDiscard = new ArrayList<>(afterChi);
afterDiscard.remove(Integer.valueOf(discardCard));
Collections.sort(afterDiscard);
int discardType = discardCard / 100;
int discardValue = discardCard % 100;
System.out.println("---打牌-----" + discardValue);
System.out.print("\n 打" + discardValue + getTypeName(discardType) +
" → 剩余" + afterDiscard.size() + "张: " +
convertToReadable(afterDiscard));
// 5. 检查打牌后是否能听牌
boolean canTing = checkCanTing(afterDiscard, needs258, targetSizeAfterDiscard);
if (canTing) {
//HuNanChangSha.isTinChi = true;
ChangShaSuanFaTest.isChi=true;
System.out.println(" ✓ 听牌!");
foundTing = true;
// 分析听牌详情
analyzeTingDetails(afterDiscard, needs258);
} else {
// // 如果不能听牌,检查是否是好牌型
// System.out.print(" [手牌分析中...]");
//
// if (isGoodHandForTing(afterDiscard, needs258, targetSizeAfterDiscard)) {
// System.out.println(" ✓ 好牌型(接近听牌)");
// foundTing = true;
// } else {
System.out.println(" ✗ 不听");
// }
}
}
return foundTing;
}
/**
*
*/
public static boolean checkCanTing(List<Integer> hand, boolean needs258, int targetSize) {
if (hand.size() != targetSize) {
return false;
}
// 获取所有可能的牌
Set<Integer> allCards = new HashSet<>();
// 生成所有可能的牌
for (int type = 1; type <= 3; type++) {
for (int value = 1; value <= 9; value++) {
allCards.add(type * 100 + value);
}
}
for (int testCard : allCards) {
List<Integer> tempHand = new ArrayList<>(hand);
tempHand.add(testCard);
Collections.sort(tempHand);
// 检查是否能胡牌
if (canHu(tempHand, needs258)) {
return true;
}
}
return false;
}
/**
* 258
*/
public static boolean canHu(List<Integer> handCards, boolean needs258) {
// 手牌排序
List<Integer> sorted = new ArrayList<>(handCards);
Collections.sort(sorted);
// 胡牌时手牌数必须是3n+2
if (sorted.size() % 3 != 2) {
return false;
}
// 检查七对子(特殊胡牌)
if (checkQiDuiZi(sorted)) {
// 七对子不需要258将
return true;
}
// 如果需要258将检查普通胡牌必须有258将
if (needs258) {
return checkNormalHuWith258(sorted);
} else {
// 不需要258将检查普通胡牌
return checkNormalHu(sorted);
}
}
/**
*
*/
public static void analyzeTingDetails(List<Integer> hand, boolean needs258) {
Set<Integer> tingCards = new HashSet<>();
Set<Integer> allCards = new HashSet<>();
// 生成所有可能的牌
for (int type = 1; type <= 3; type++) {
for (int value = 1; value <= 9; value++) {
allCards.add(type * 100 + value);
}
}
for (int testCard : allCards) {
List<Integer> tempHand = new ArrayList<>(hand);
tempHand.add(testCard);
if (canHu(tempHand, needs258)) {
tingCards.add(testCard);
}
}
if (!tingCards.isEmpty()) {
System.out.print(" 听" + tingCards.size() + "张牌: ");
List<String> tingCardStrs = new ArrayList<>();
// 比较当前数量和上次数量
if (tingCards.size() > lastTingCount) {
isMoreThanLast = true;
// System.out.print("(比上次多" + (tingCards.size() - lastTingCount) + "张) ");
} else if (tingCards.size() < lastTingCount) {
// System.out.print("(比上次少" + (lastTingCount - tingCards.size()) + "张) ");
} else {
// System.out.print("(与上次相同) ");
}
for (int card : tingCards) {
int type = card / 100;
int value = card % 100;
tingCardStrs.add(value + getTypeName(type));
}
System.out.println(String.join(", ", tingCardStrs));
// 更新上次听牌数量
lastTingCount = tingCards.size();
// 分析听牌类型
analyzeTingType(tingCards);
} else {
System.out.println(" 无听牌");
// 比较当前数量和上次数量
if (0 > lastTingCount) {
isMoreThanLast = true;
}
// 更新上次听牌数量
lastTingCount = 0;
}
}
// 修改 analyzeTingType 方法以接收 Set<Integer>
public static void analyzeTingType(Set<Integer> tingCards) {
if (tingCards.size() == 1) {
System.out.println("听牌类型: 单吊");
} else if (tingCards.size() == 2) {
List<Integer> tingList = new ArrayList<>(tingCards);
int type1 = tingList.get(0) / 100;
int type2 = tingList.get(1) / 100;
if (type1 == type2) {
System.out.println("听牌类型: 对倒");
} else {
System.out.println("听牌类型: 双面听");
}
} else if (tingCards.size() >= 3) {
System.out.println("听牌类型: 多面听(" + tingCards.size() + "张)");
}
}
/**
* >=10
*/
public static boolean checkSuitCount(List<Integer> hand) {
// 统计万、筒、条各自的数量
Map<Integer, Integer> suitCount = new HashMap<>();
for (int card : hand) {
int type = card / 100;
if (type < 4) { // 只统计万筒条
suitCount.put(type, suitCount.getOrDefault(type, 0) + 1);
}
}
// 检查是否有某种花色>=10张
for (int count : suitCount.values()) {
if (count >= 10) {
return true; // 有花色>=10张不需要258将
}
}
return false; // 没有花色>=10张需要258将
}
/**
*
*/
public static boolean checkQiDuiZi(List<Integer> handCards) {
if (handCards.size() != 14) return false;
Map<Integer, Integer> countMap = new HashMap<>();
for (int card : handCards) {
countMap.put(card, countMap.getOrDefault(card, 0) + 1);
}
// 检查是否都是对子
for (int count : countMap.values()) {
if (count != 2) {
return false;
}
}
return true;
}
/**
* 258
*/
public static boolean checkNormalHuWith258(List<Integer> handCards) {
// 尝试每种258作为将牌
for (int card : handCards) {
int value = card % 100;
// 检查是否是258
if (value == 2 || value == 5 || value == 8) {
// 检查是否有至少2张相同的牌做将
int count = Collections.frequency(handCards, card);
if (count >= 2) {
// 移除将牌
List<Integer> remaining = new ArrayList<>(handCards);
for (int i = 0; i < 2; i++) {
remaining.remove(Integer.valueOf(card));
}
// 检查剩余牌是否能组成顺子/刻子
if (canGroup(remaining)) {
return true;
}
}
}
}
return false;
}
/**
* 258
*/
public static boolean checkNormalHu(List<Integer> handCards) {
return checkNormalHuRecursive(new ArrayList<>(handCards), false);
}
public static boolean checkNormalHuRecursive(List<Integer> handCards, boolean hasJiang) {
if (handCards.isEmpty()) {
return true; // 所有牌都分组成功
}
Collections.sort(handCards);
// 统计第一张牌的数量
int firstCard = handCards.get(0);
int count = Collections.frequency(handCards, firstCard);
// 尝试作为刻子(三张相同)
if (count >= 3) {
List<Integer> remaining = new ArrayList<>(handCards);
for (int i = 0; i < 3; i++) {
remaining.remove(Integer.valueOf(firstCard));
}
if (checkNormalHuRecursive(remaining, hasJiang)) {
return true;
}
}
// 尝试作为顺子(三张连续)
int type = firstCard / 100;
int value = firstCard % 100;
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
int second = type * 100 + (value + 1);
int third = type * 100 + (value + 2);
if (handCards.contains(second) && handCards.contains(third)) {
List<Integer> remaining = new ArrayList<>(handCards);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(second));
remaining.remove(Integer.valueOf(third));
if (checkNormalHuRecursive(remaining, hasJiang)) {
return true;
}
}
}
// 尝试作为将(对子)- 只能有一个将
if (!hasJiang && count >= 2) {
List<Integer> remaining = new ArrayList<>(handCards);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(firstCard));
if (checkNormalHuRecursive(remaining, true)) {
return true;
}
}
return false;
}
/**
*
*/
public static boolean canGroup(List<Integer> cards) {
if (cards.isEmpty()) {
return true; // 所有牌都分组成功
}
List<Integer> sorted = new ArrayList<>(cards);
Collections.sort(sorted);
int firstCard = sorted.get(0);
int count = Collections.frequency(sorted, firstCard);
// 尝试作为刻子(三张相同)
if (count >= 3) {
List<Integer> remaining = new ArrayList<>(sorted);
for (int i = 0; i < 3; i++) {
remaining.remove(Integer.valueOf(firstCard));
}
if (canGroup(remaining)) {
return true;
}
}
// 尝试作为顺子(三张连续)
int type = firstCard / 100;
int value = firstCard % 100;
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
int second = type * 100 + (value + 1);
int third = type * 100 + (value + 2);
if (sorted.contains(second) && sorted.contains(third)) {
List<Integer> remaining = new ArrayList<>(sorted);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(second));
remaining.remove(Integer.valueOf(third));
if (canGroup(remaining)) {
return true;
}
}
}
return false;
}
/**
*
*/
public static Set<Integer> getAllCards() {
Set<Integer> allCards = new HashSet<>();
// 万条筒 1-9
for (int type = 1; type <= 3; type++) {
for (int value = 1; value <= 9; value++) {
allCards.add(type * 100 + value);
}
}
return allCards;
}
/**
*
*/
public static String convertToReadable(List<Integer> cards) {
StringBuilder sb = new StringBuilder();
for (int card : cards) {
int type = card / 100;
int value = card % 100;
sb.append(value).append(getTypeName(type)).append(" ");
}
return sb.toString();
}
/**
*
*/
@ -1016,7 +124,4 @@ public class TinHuChi {
}
public static boolean isMoreThanLast() {
return isMoreThanLast;
}
}

View File

@ -1,404 +0,0 @@
package taurus.util;
import java.util.*;
public class TinHuGang {
/**
*
*/
public static boolean canGang(List<Integer> handCards, int card, boolean isMingGang) {
int type = card / 100;
int value = card % 100;
System.out.println("\n检查" + (isMingGang ? "明" : "暗") + "杠" + value + getTypeName(type) + ":");
// 检查是否符合杠牌条件
int count = Collections.frequency(handCards, card);
if (isMingGang) {
// 明杠:手牌中需要有三张相同的牌
if (count < 3) {
System.out.println(" 手牌中没有三张相同的" + value + getTypeName(type) + ",不能明杠");
return false;
}
System.out.println(" 发现三张" + value + getTypeName(type) + ",可以明杠");
} else {
// 暗杠:手牌中需要有四张相同的牌
if (count < 4) {
System.out.println(" 手牌中没有四张相同的" + value + getTypeName(type) + ",不能暗杠");
return false;
}
System.out.println(" 发现四张" + value + getTypeName(type) + ",可以暗杠");
}
// 检查杠牌后是否立即听牌(杠牌后手牌本身就是听牌状态)
return canTingImmediatelyAfterGang(handCards, card, isMingGang);
}
/**
*
*/
private static boolean canTingImmediatelyAfterGang(List<Integer> handCards, int gangCard, boolean isMingGang) {
int type = gangCard / 100;
int value = gangCard % 100;
System.out.println("\n模拟" + (isMingGang ? "明" : "暗") + "杠" + value + getTypeName(type) + ":");
// 1. 模拟杠牌:移除手牌中的牌
List<Integer> afterGang = new ArrayList<>(handCards);
if (isMingGang) {
// 明杠:移除手牌中的三张牌
for (int i = 0; i < 3; i++) {
afterGang.remove(Integer.valueOf(gangCard));
}
// 杠牌后手牌数13张 → 10张
} else {
// 暗杠:移除手牌中的四张牌
for (int i = 0; i < 4; i++) {
afterGang.remove(Integer.valueOf(gangCard));
}
// 暗杠后需要补牌,但这里先不处理
}
Collections.sort(afterGang);
System.out.println(" 杠后手牌(" + afterGang.size() + "张): " + convertToReadable(afterGang));
// 2. 检查是否需要258将
boolean needs258 = !checkSuitCount(afterGang);
if (needs258) {
System.out.println(" 花色牌数不足10张需要258做将");
}
// 3. 检查杠牌后手牌本身是否就是听牌状态
// 注意杠牌后手牌数是10张这10张牌本身应该是听牌状态
// 也就是说,随便摸一张牌(任何牌)都能胡牌
System.out.println("\n 检查杠后手牌是否听牌:");
if (afterGang.size() != 10) {
System.out.println(" 手牌数不是10张不符合听牌条件");
return false;
}
// 检查这10张牌是否听牌
boolean canTing = checkIfHandIsTingPai(afterGang, needs258);
if (canTing) {
System.out.println(" ✓ 杠后手牌是听牌状态!");
// 显示听哪些牌
Set<Integer> tingCards = getTingCards(afterGang, needs258);
if (!tingCards.isEmpty()) {
System.out.print(" 听" + tingCards.size() + "张牌: ");
List<String> tingStrs = new ArrayList<>();
for (int tingCard : tingCards) {
tingStrs.add((tingCard%100) + getTypeName(tingCard/100));
}
System.out.println(String.join(", ", tingStrs));
}
return true;
} else {
System.out.println(" ✗ 杠后手牌不是听牌状态");
return false;
}
}
/**
*
*/
private static boolean checkIfHandIsTingPai(List<Integer> hand, boolean needs258) {
if (hand.size() != 10) {
return false;
}
// 听牌状态:再摸任何一张牌都能胡牌
// 我们需要检查是否至少有一张牌能让这手牌胡牌
Set<Integer> allCards = getAllCards();
int tingCount = 0;
for (int testCard : allCards) {
List<Integer> tempHand = new ArrayList<>(hand);
tempHand.add(testCard);
if (canHu(tempHand, needs258)) {
tingCount++;
}
}
System.out.println(" 可胡" + tingCount + "张牌");
return tingCount > 0;
}
/**
*
*/
private static Set<Integer> getTingCards(List<Integer> hand, boolean needs258) {
Set<Integer> tingCards = new HashSet<>();
if (hand.size() != 10) {
return tingCards;
}
Set<Integer> allCards = getAllCards();
for (int testCard : allCards) {
List<Integer> tempHand = new ArrayList<>(hand);
tempHand.add(testCard);
if (canHu(tempHand, needs258)) {
tingCards.add(testCard);
}
}
return tingCards;
}
/**
*
*/
private static boolean canHu(List<Integer> handCards, boolean needs258) {
// 手牌排序
List<Integer> sorted = new ArrayList<>(handCards);
Collections.sort(sorted);
// 胡牌时手牌数必须是3n+2
if (sorted.size() != 11 && sorted.size() != 14) {
return false;
}
// 检查七对子
if (checkQiDuiZi(sorted)) {
// 七对子不需要258将
return true;
}
// 如果需要258将检查普通胡牌必须有258将
if (needs258) {
return checkNormalHuWith258(sorted);
} else {
// 不需要258将检查普通胡牌
return checkNormalHu(sorted);
}
}
/**
*
*/
private static boolean checkQiDuiZi(List<Integer> handCards) {
if (handCards.size() != 14) return false;
Map<Integer, Integer> countMap = new HashMap<>();
for (int card : handCards) {
countMap.put(card, countMap.getOrDefault(card, 0) + 1);
}
// 检查是否都是对子
for (int count : countMap.values()) {
if (count != 2) {
return false;
}
}
return true;
}
/**
* 258
*/
private static boolean checkNormalHuWith258(List<Integer> handCards) {
// 尝试每种258作为将牌
for (int card : handCards) {
int value = card % 100;
// 检查是否是258
if (value == 2 || value == 5 || value == 8) {
// 检查是否有至少2张相同的牌做将
int count = Collections.frequency(handCards, card);
if (count >= 2) {
// 移除将牌
List<Integer> remaining = new ArrayList<>(handCards);
for (int i = 0; i < 2; i++) {
remaining.remove(Integer.valueOf(card));
}
// 检查剩余牌是否能组成顺子/刻子
if (canGroup(remaining)) {
return true;
}
}
}
}
return false;
}
/**
* 258
*/
private static boolean checkNormalHu(List<Integer> handCards) {
return checkNormalHuRecursive(new ArrayList<>(handCards), false);
}
private static boolean checkNormalHuRecursive(List<Integer> handCards, boolean hasJiang) {
if (handCards.isEmpty()) {
return true; // 所有牌都分组成功
}
Collections.sort(handCards);
// 统计第一张牌的数量
int firstCard = handCards.get(0);
int count = Collections.frequency(handCards, firstCard);
// 尝试作为刻子(三张相同)
if (count >= 3) {
List<Integer> remaining = new ArrayList<>(handCards);
for (int i = 0; i < 3; i++) {
remaining.remove(Integer.valueOf(firstCard));
}
if (checkNormalHuRecursive(remaining, hasJiang)) {
return true;
}
}
// 尝试作为顺子(三张连续)
int type = firstCard / 100;
int value = firstCard % 100;
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
int second = type * 100 + (value + 1);
int third = type * 100 + (value + 2);
if (handCards.contains(second) && handCards.contains(third)) {
List<Integer> remaining = new ArrayList<>(handCards);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(second));
remaining.remove(Integer.valueOf(third));
if (checkNormalHuRecursive(remaining, hasJiang)) {
return true;
}
}
}
// 尝试作为将(对子)- 只能有一个将
if (!hasJiang && count >= 2) {
List<Integer> remaining = new ArrayList<>(handCards);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(firstCard));
if (checkNormalHuRecursive(remaining, true)) {
return true;
}
}
return false;
}
/**
*
*/
private static boolean canGroup(List<Integer> cards) {
if (cards.isEmpty()) {
return true; // 所有牌都分组成功
}
List<Integer> sorted = new ArrayList<>(cards);
Collections.sort(sorted);
int firstCard = sorted.get(0);
int count = Collections.frequency(sorted, firstCard);
// 尝试作为刻子(三张相同)
if (count >= 3) {
List<Integer> remaining = new ArrayList<>(sorted);
for (int i = 0; i < 3; i++) {
remaining.remove(Integer.valueOf(firstCard));
}
if (canGroup(remaining)) {
return true;
}
}
// 尝试作为顺子(三张连续)
int type = firstCard / 100;
int value = firstCard % 100;
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
int second = type * 100 + (value + 1);
int third = type * 100 + (value + 2);
if (sorted.contains(second) && sorted.contains(third)) {
List<Integer> remaining = new ArrayList<>(sorted);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(second));
remaining.remove(Integer.valueOf(third));
if (canGroup(remaining)) {
return true;
}
}
}
return false;
}
/**
* >=10
*/
private static boolean checkSuitCount(List<Integer> hand) {
Map<Integer, Integer> suitCount = new HashMap<>();
for (int card : hand) {
int type = card / 100;
if (type < 4) {
suitCount.put(type, suitCount.getOrDefault(type, 0) + 1);
}
}
for (int count : suitCount.values()) {
if (count >= 10) {
return true;
}
}
return false;
}
/**
*
*/
private static Set<Integer> getAllCards() {
Set<Integer> allCards = new HashSet<>();
for (int type = 1; type <= 3; type++) {
for (int value = 1; value <= 9; value++) {
allCards.add(type * 100 + value);
}
}
return allCards;
}
/**
*
*/
private static String convertToReadable(List<Integer> cards) {
StringBuilder sb = new StringBuilder();
for (int card : cards) {
int type = card / 100;
int value = card % 100;
sb.append(value).append(getTypeName(type)).append(" ");
}
return sb.toString();
}
/**
*
*/
private static String getTypeName(int type) {
switch(type) {
case 1: return "万";
case 2: return "筒";
case 3: return "条";
default: return "字";
}
}
}

View File

@ -1,425 +0,0 @@
package taurus.util;
import robot.mj.handler.HuNanChangSha;
import java.util.*;
public class TinHuPeng {
/**
*
*/
public boolean canPeng(List<Integer> handCards, int card) {
int type = card / 100;
int value = card % 100;
if (type >= 4) return false; // 字牌不能碰(长沙麻将没有字牌)
System.out.println("\n要碰的牌: " + value + getTypeName(type));
System.out.println("当前手牌数量: " + handCards.size() + "张");
// 检查基本碰牌条件手牌至少有2张相同的牌
if (!canPengBasic(handCards, card)) {
System.out.println(" 基本碰牌条件不满足手牌没有2张" + value + getTypeName(type));
return false;
}
System.out.println(" ✓ 手牌有2张" + value + getTypeName(type) + ",可以碰");
ChangShaSuanFaTest.isPeng = true;
// 检查碰牌后是否能听牌
return canTingAfterPengAndDiscard(handCards, card);
}
/**
*
*/
private boolean canPengBasic(List<Integer> handCards, int card) {
// 碰牌手牌有2张相同的牌别人打出第3张
int count = 0;
for (int c : handCards) {
if (c == card) {
count++;
}
}
return count >= 2;
}
/**
*
*/
private boolean canTingAfterPengAndDiscard(List<Integer> handCards, int pengCard) {
// 1. 模拟碰牌:移除两张相同的牌,碰的牌不加入手牌
List<Integer> afterPeng = new ArrayList<>(handCards);
// 移除2张相同的牌
int removed = 0;
for (int i = 0; i < handCards.size() && removed < 2; i++) {
if (handCards.get(i) == pengCard) {
afterPeng.remove(Integer.valueOf(pengCard));
removed++;
}
}
Collections.sort(afterPeng);
System.out.println(" 碰后手牌(" + afterPeng.size() + "张): " + convertToReadable(afterPeng));
// 2. 检查是否需要258将花色是否>=10张
boolean needs258 = !checkSuitCount(afterPeng);
if (needs258) {
System.out.println(" 花色牌数不足10张需要258做将");
}
// 3. 根据碰后手牌数确定目标手牌数
// 碰牌前后手牌数变化碰前N张 -> 碰后(N-2)张 -> 打后(N-3)张
int targetSizeAfterDiscard = afterPeng.size() - 1;
System.out.println(" 目标手牌数: " + targetSizeAfterDiscard);
// 4. 尝试打每一张不同的牌
Set<Integer> uniqueCards = new HashSet<>(afterPeng);
boolean foundTing = false;
for (int discardCard : uniqueCards) {
List<Integer> afterDiscard = new ArrayList<>(afterPeng);
afterDiscard.remove(Integer.valueOf(discardCard));
Collections.sort(afterDiscard);
int discardType = discardCard / 100;
int discardValue = discardCard % 100;
System.out.print("\n 打" + discardValue + getTypeName(discardType) +
" → 剩余" + afterDiscard.size() + "张: " +
convertToReadable(afterDiscard));
// 5. 检查打牌后是否能听牌
boolean canTing = checkCanTing(afterDiscard, needs258, targetSizeAfterDiscard);
if (canTing) {
HuNanChangSha.isTinPeng = true;
System.out.println(" ✓ 听牌!");
foundTing = true;
// 分析听牌详情
analyzeTingDetails(afterDiscard, needs258);
} else {
System.out.println(" ✗ 不听");
}
}
return foundTing;
}
/**
*
*/
private boolean checkCanTing(List<Integer> hand, boolean needs258, int targetSize) {
if (hand.size() != targetSize) {
System.out.print(" [手牌数" + hand.size() + "≠目标" + targetSize + "]");
return false;
}
// 获取所有可能的牌
Set<Integer> allCards = getAllCards();
for (int testCard : allCards) {
List<Integer> tempHand = new ArrayList<>(hand);
tempHand.add(testCard);
Collections.sort(tempHand);
// 检查是否能胡牌
if (canHu(tempHand, needs258)) {
return true;
}
}
return false;
}
/**
* 258
*/
private boolean canHu(List<Integer> handCards, boolean needs258) {
// 手牌排序
List<Integer> sorted = new ArrayList<>(handCards);
Collections.sort(sorted);
// 胡牌时手牌数必须是3n+2
if (sorted.size() % 3 != 2) {
return false;
}
// 检查七对子(特殊胡牌)
if (checkQiDuiZi(sorted)) {
// 七对子不需要258将
return true;
}
// 如果需要258将检查普通胡牌必须有258将
if (needs258) {
return checkNormalHuWith258(sorted);
} else {
// 不需要258将检查普通胡牌
return checkNormalHu(sorted);
}
}
/**
*
*/
private void analyzeTingDetails(List<Integer> hand, boolean needs258) {
Set<Integer> tingCards = new HashSet<>();
Set<Integer> allCards = getAllCards();
for (int testCard : allCards) {
List<Integer> tempHand = new ArrayList<>(hand);
tempHand.add(testCard);
if (canHu(tempHand, needs258)) {
tingCards.add(testCard);
}
}
if (!tingCards.isEmpty()) {
System.out.print(" 听" + tingCards.size() + "张牌: ");
List<String> tingCardStrs = new ArrayList<>();
for (int card : tingCards) {
int type = card / 100;
int value = card % 100;
tingCardStrs.add(value + getTypeName(type));
}
System.out.println(String.join(", ", tingCardStrs));
}
}
/**
* >=10
*/
private boolean checkSuitCount(List<Integer> hand) {
// 统计万、筒、条各自的数量
Map<Integer, Integer> suitCount = new HashMap<>();
for (int card : hand) {
int type = card / 100;
if (type < 4) { // 只统计万筒条
suitCount.put(type, suitCount.getOrDefault(type, 0) + 1);
}
}
// 检查是否有某种花色>=10张
for (int count : suitCount.values()) {
if (count >= 10) {
return true; // 有花色>=10张不需要258将
}
}
return false; // 没有花色>=10张需要258将
}
/**
*
*/
private boolean checkQiDuiZi(List<Integer> handCards) {
if (handCards.size() != 14) return false;
Map<Integer, Integer> countMap = new HashMap<>();
for (int card : handCards) {
countMap.put(card, countMap.getOrDefault(card, 0) + 1);
}
// 检查是否都是对子
for (int count : countMap.values()) {
if (count != 2) {
return false;
}
}
return true;
}
/**
* 258
*/
private boolean checkNormalHuWith258(List<Integer> handCards) {
// 尝试每种258作为将牌
for (int card : handCards) {
int value = card % 100;
// 检查是否是258
if (value == 2 || value == 5 || value == 8) {
// 检查是否有至少2张相同的牌做将
int count = Collections.frequency(handCards, card);
if (count >= 2) {
// 移除将牌
List<Integer> remaining = new ArrayList<>(handCards);
for (int i = 0; i < 2; i++) {
remaining.remove(Integer.valueOf(card));
}
// 检查剩余牌是否能组成顺子/刻子
if (canGroup(remaining)) {
return true;
}
}
}
}
return false;
}
/**
* 258
*/
private boolean checkNormalHu(List<Integer> handCards) {
return checkNormalHuRecursive(new ArrayList<>(handCards), false);
}
private boolean checkNormalHuRecursive(List<Integer> handCards, boolean hasJiang) {
if (handCards.isEmpty()) {
return true; // 所有牌都分组成功
}
Collections.sort(handCards);
// 统计第一张牌的数量
int firstCard = handCards.get(0);
int count = Collections.frequency(handCards, firstCard);
// 尝试作为刻子(三张相同)
if (count >= 3) {
List<Integer> remaining = new ArrayList<>(handCards);
for (int i = 0; i < 3; i++) {
remaining.remove(Integer.valueOf(firstCard));
}
if (checkNormalHuRecursive(remaining, hasJiang)) {
return true;
}
}
// 尝试作为顺子(三张连续)
int type = firstCard / 100;
int value = firstCard % 100;
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
int second = type * 100 + (value + 1);
int third = type * 100 + (value + 2);
if (handCards.contains(second) && handCards.contains(third)) {
List<Integer> remaining = new ArrayList<>(handCards);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(second));
remaining.remove(Integer.valueOf(third));
if (checkNormalHuRecursive(remaining, hasJiang)) {
return true;
}
}
}
// 尝试作为将(对子)- 只能有一个将
if (!hasJiang && count >= 2) {
List<Integer> remaining = new ArrayList<>(handCards);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(firstCard));
if (checkNormalHuRecursive(remaining, true)) {
return true;
}
}
return false;
}
/**
*
*/
private boolean canGroup(List<Integer> cards) {
if (cards.isEmpty()) {
return true; // 所有牌都分组成功
}
List<Integer> sorted = new ArrayList<>(cards);
Collections.sort(sorted);
int firstCard = sorted.get(0);
int count = Collections.frequency(sorted, firstCard);
// 尝试作为刻子(三张相同)
if (count >= 3) {
List<Integer> remaining = new ArrayList<>(sorted);
for (int i = 0; i < 3; i++) {
remaining.remove(Integer.valueOf(firstCard));
}
if (canGroup(remaining)) {
return true;
}
}
// 尝试作为顺子(三张连续)
int type = firstCard / 100;
int value = firstCard % 100;
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
int second = type * 100 + (value + 1);
int third = type * 100 + (value + 2);
if (sorted.contains(second) && sorted.contains(third)) {
List<Integer> remaining = new ArrayList<>(sorted);
remaining.remove(Integer.valueOf(firstCard));
remaining.remove(Integer.valueOf(second));
remaining.remove(Integer.valueOf(third));
if (canGroup(remaining)) {
return true;
}
}
}
return false;
}
/**
*
*/
private Set<Integer> getAllCards() {
Set<Integer> allCards = new HashSet<>();
// 万条筒 1-9
for (int type = 1; type <= 3; type++) {
for (int value = 1; value <= 9; value++) {
allCards.add(type * 100 + value);
}
}
return allCards;
}
/**
*
*/
private String convertToReadable(List<Integer> cards) {
StringBuilder sb = new StringBuilder();
for (int card : cards) {
int type = card / 100;
int value = card % 100;
sb.append(value).append(getTypeName(type)).append(" ");
}
return sb.toString();
}
/**
*
*/
private String getTypeName(int type) {
switch(type) {
case 1: return "万";
case 2: return "筒";
case 3: return "条";
default: return "字";
}
}
/**
*
*/
class HandAnalysis {
int keziCount = 0; // 刻子数量
int pairCount = 0; // 对子数量
int shunziCount = 0; // 顺子数量
int singleCount = 0; // 单张数量
List<Integer> singles = new ArrayList<>(); // 单张列表
boolean has258Jiang = false; // 是否有258将
List<Integer> pairs = new ArrayList<>(); // 对子列表value
}
}

View File

@ -419,58 +419,6 @@ public class TingPaiChecker {
return possibleCards;
}
/**
*
*/
private boolean canFormAllMelds(List<Integer> cards) {
if (cards.isEmpty()) {
return true;
}
return dfsFormMelds(new ArrayList<>(cards));
}
private boolean dfsFormMelds(List<Integer> cards) {
if (cards.isEmpty()) {
return true;
}
Collections.sort(cards);
int firstCard = cards.get(0);
int count = Collections.frequency(cards, firstCard);
// 尝试刻子
if (count >= 3) {
List<Integer> newCards = new ArrayList<>(cards);
for (int i = 0; i < 3; i++) {
newCards.remove(Integer.valueOf(firstCard));
}
if (dfsFormMelds(newCards)) {
return true;
}
}
// 尝试顺子
int type = getCardType(firstCard);
int value = getCardValue(firstCard);
if (type <= 3 && value <= 7) {
int secondCard = firstCard + 1;
int thirdCard = firstCard + 2;
if (cards.contains(secondCard) && cards.contains(thirdCard)) {
List<Integer> newCards = new ArrayList<>(cards);
newCards.remove(Integer.valueOf(firstCard));
newCards.remove(Integer.valueOf(secondCard));
newCards.remove(Integer.valueOf(thirdCard));
if (dfsFormMelds(newCards)) {
return true;
}
}
}
return false;
}
/**
*
*/

View File

@ -231,7 +231,6 @@ public class WinCard {
public static void main(String[] args) {
long time = System.currentTimeMillis();
// for (int i = 0; i < 1000000; ++i) {
ArrayList<Integer> cardInhand = new ArrayList<Integer>();
cardInhand.add(207);
cardInhand.add(207);
@ -248,24 +247,9 @@ public class WinCard {
cardInhand.add(102);
cardInhand.add(102);
// cardInhand.add(301);
// cardInhand.add(301);
// cardInhand.add(108);
// cardInhand.contains(204);
// Util.checkCard(204, cardInhand);
// CardUtil.checkCardAndRomve(204, cardInhand, 2);
// if(Util.checkCard(204, cardInhand)) {
// CardUtil.removeCard(cardInhand, 204, 2);
// }
WinCard win = new WinCard(cardInhand, 104);
boolean c = win.tryWin();
System.out.println(c);
// Paixing.tingKongCheck(new ArrayList<>(), cardInhand, 301);
// }
//Map<Integer, WinCardType> map = new HashMap<Integer, WinCardType>();
//Paixing.checkWin(map, new ArrayList<>(), cardInhand, 305, room.difen_score);
System.out.println(System.currentTimeMillis() - time);

View File

@ -1,8 +1,3 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package taurus.util;
import java.util.ArrayList;
@ -17,11 +12,6 @@ import java.util.stream.Collectors;
public class ai {
private static final Set<Integer> JIANG_PAIS;
private static final int DOOR_NONE = 0;
private static final int DOOR_BIAN = 1;
private static final int DOOR_GE = 2;
private static final int DOOR_XIANGLIN = 3;
private static final int DOOR_DUIZI = 4;
public boolean isTinAi = false;
public boolean isTingpai = false;
private Map<String, Double> scoreCache = new HashMap();
@ -395,18 +385,6 @@ public class ai {
}
}
private boolean isInSequenceMiddle(int card, List<Integer> hand) {
int type = this.getCardType(card);
this.getCardValue(card);
if (type > 3) {
return false;
} else {
int prevCard = card - 1;
int nextCard = card + 1;
return hand.contains(prevCard) && hand.contains(nextCard);
}
}
private double evaluatePairsAndPongsFinal(int card, PlayerState state) {
int originalCount = 0;