1
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user