This commit is contained in:
2026-09-13 01:47:54 +08:00
parent 177561b78b
commit 190a44aa88
2 changed files with 81 additions and 10 deletions
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
@@ -161,6 +162,79 @@ public class ChessGameManager
return true;
}
/// <summary>
/// 超时代走:AI 自动为本地玩家走一步合法棋(不判负、不结算)
/// 策略:优先吃价值最高的子;没有吃子就避开会被攻击的位置随机走
/// 返回是否成功走棋
/// </summary>
public bool AutoMove()
{
if (isGameOver || currentTurn != myCamp) return false;
var candidates = new List<AutoCandidate>();
int bestScore = int.MinValue;
ChessCamp enemy = myCamp == ChessCamp.Red ? ChessCamp.Black : ChessCamp.Red;
foreach (var p in board.allPieces)
{
if (!p.isAlive || p.camp != myCamp) continue;
var legal = rules.GetLegalMoves(board, p);
foreach (var to in legal)
{
int score;
var target = board.GetPiece(to);
if (target != null)
{
score = GetPieceValue(target.pieceType); // 吃子按价值
}
else if (rules.IsSquareAttacked(board, to, enemy))
{
score = -GetPieceValue(p.pieceType); // 走过去会被吃的位置降权
}
else
{
score = 0;
}
if (score > bestScore) bestScore = score;
candidates.Add(new AutoCandidate { from = p.pos, to = to, score = score });
}
}
if (candidates.Count == 0) return false;
// 同分随机挑一个(避免每次 AI 走得一模一样)
var pool = new List<AutoCandidate>();
for (int i = 0; i < candidates.Count; i++)
if (candidates[i].score == bestScore) pool.Add(candidates[i]);
var pick = pool[UnityEngine.Random.Range(0, pool.Count)];
return TryLocalMove(pick.from, pick.to);
}
/// <summary>棋子价值(AI 吃子/避损评估用)</summary>
private static int GetPieceValue(ChessPieceType type)
{
switch (type)
{
case ChessPieceType.Jiang: return 1000;
case ChessPieceType.Ju: return 90; // 车
case ChessPieceType.Pao: return 45; // 炮
case ChessPieceType.Ma: return 40; // 马
case ChessPieceType.Xiang: return 20; // 象
case ChessPieceType.Shi: return 20; // 士
case ChessPieceType.Bing: return 20; // 兵
default: return 0;
}
}
/// <summary>AI 候选走法</summary>
private struct AutoCandidate
{
public Vector2Int from;
public Vector2Int to;
public int score;
}
private void SetGameOver(ChessCamp winner)
{
isGameOver = true;
@@ -547,8 +547,8 @@ public class ChineseChessMainPanel : GameMainPanel_Base
}
/// <summary>
/// 走棋倒计时:轮到我 → 显示在下方(超时自动判负,走 EndGame 通道);
/// 轮到对方 → 显示在上方(对方客户端超时会自行上报,本地只显示)
/// 走棋倒计时:轮到我 → 显示在下方(超时 AI 自动走一步,不判负不结算);
/// 轮到对方 → 显示在上方(对方客户端超时同样由它的 AI 自动走)
/// </summary>
private IEnumerator TurnCountdownRoutine(int totalSeconds, bool myTurn)
{
@@ -572,17 +572,14 @@ public class ChineseChessMainPanel : GameMainPanel_Base
if (myTurn)
{
// 我方超时 → 自动判负(与认输同款 EndGame 通道,第二个参数为胜者 userId)
if (chessGameManager != null && !chessGameManager.isGameOver && roomData != null)
// 我方超时 → AI 自动走一步(走完会触发回合切换,倒计时自动重开)
if (chessGameManager != null && !chessGameManager.isGameOver)
{
var opponent = roomData.users.Find(u => u.userId != GameManager.Instance.user.BaseInfo.number);
if (opponent != null)
{
WebSocketSendList.EndGameChineseChess(roomData.roomId, opponent.userId);
}
bool moved = chessGameManager.AutoMove();
if (moved && chessBoard != null) chessBoard.ShowToast("超时,已自动走子");
}
}
// 对方回合超时:由对方客户端上报(服务端也有 timeoutSeconds 兜底),本地只停表
// 对方回合超时:对方客户端同样 AI 自动走一步,我方等它的走子帧
}
#endregion