using System;
using UnityEngine;
///
/// 象棋对局总管理(普通类,由 ChineseChessMainPanel 持有并统一控制)
/// 负责:开局、回合、走棋校验与应用、将军/胜负判断、悔棋、网络同步数据封装
///
/// 联网方案:帧同步——走法与规则判断全在前端本地跑,
/// 走子数据通过 SyncGameData 透传给对方(后端不解析),后端只负责胜负结算
///
public class ChessGameManager
{
/// 棋盘数据管理
public ChessBoardManager board = new ChessBoardManager();
/// 规则管理
public ChessRulesManager rules = new ChessRulesManager();
/// 悔棋记录管理
public ChessMoveRecorder recorder = new ChessMoveRecorder();
/// 本地玩家阵营
public ChessCamp myCamp;
/// 当前轮到哪方走(红先黑后)
public ChessCamp currentTurn;
/// 已走的半回合数(同时作为帧序号)
public int moveCount;
/// 对局是否已结束
public bool isGameOver;
/// 胜方
public ChessCamp winnerCamp;
/// 走棋成功(本地或网络同步),参数含完整走子数据
public event Action OnMoveApplied;
/// 悔棋完成,参数为回退的步数
public event Action OnUndoApplied;
/// 对局结束(本地规则判定),参数为胜方
public event Action OnGameOver;
/// 回合切换
public event Action OnTurnChanged;
/// 现在是否轮到本地玩家
public bool IsMyTurn => !isGameOver && currentTurn == myCamp;
/// 开一局新对局
public void StartGame(ChessCamp myCamp)
{
this.myCamp = myCamp;
board.InitDefaultBoard();
recorder.Clear();
moveCount = 0;
isGameOver = false;
winnerCamp = ChessCamp.None;
currentTurn = ChessCamp.Red; // 红先
OnTurnChanged?.Invoke(currentTurn);
}
///
/// 本地玩家尝试走棋(完整校验:回合、归属、规则、送将),失败返回 false
///
public bool TryLocalMove(Vector2Int from, Vector2Int to)
{
if (isGameOver || currentTurn != myCamp) return false;
var piece = board.GetPiece(from);
if (piece == null || piece.camp != myCamp) return false;
if (!rules.GetLegalMoves(board, piece).Contains(to)) return false;
ApplyMoveInternal(piece, to, true);
return true;
}
///
/// 应用网络同步过来的走棋(对方走的)。带帧序号校验,重复/乱序帧直接丢弃
///
public bool ApplyRemoteMove(ChessMoveData move)
{
if (isGameOver || move == null) return false;
// 帧序号校验
if (move.seq < moveCount) return false; // 重复帧
if (move.seq > moveCount)
{
Debug.LogWarning($"[Chess] 丢帧:收到 seq={move.seq},本地 moveCount={moveCount}");
return false; // 乱序帧
}
var from = new Vector2Int(move.fromX, move.fromY);
var to = new Vector2Int(move.toX, move.toY);
var piece = board.GetPiece(from);
if (piece == null || piece.camp == myCamp || piece.camp != currentTurn) return false;
if (!rules.GetLegalMoves(board, piece).Contains(to)) return false;
ApplyMoveInternal(piece, to, false);
return true;
}
/// 应用一步棋(数据层),并触发相关事件
private void ApplyMoveInternal(ChessPieceData piece, Vector2Int to, bool isLocal)
{
Vector2Int from = piece.pos;
ChessPieceData captured = board.ApplyMove(piece, to);
moveCount++;
recorder.Push(new ChessMoveRecord { piece = piece, from = from, to = to, captured = captured });
ChessCamp moverCamp = piece.camp;
currentTurn = moverCamp == ChessCamp.Red ? ChessCamp.Black : ChessCamp.Red;
// 胜负与将军判断(纯前端本地判定)
bool check = false;
bool gameOver = false;
if (captured != null && captured.pieceType == ChessPieceType.Jiang)
{
gameOver = true; // 将/帅被吃
}
else
{
check = rules.IsInCheck(board, currentTurn);
if (!rules.HasAnyLegalMove(board, currentTurn))
{
gameOver = true; // 对方无任何合法走法 → 将死或困毙
}
}
var args = new ChessMoveEventArgs
{
move = new ChessMoveData { seq = moveCount - 1, fromX = from.x, fromY = from.y, toX = to.x, toY = to.y },
movePieceId = piece.id,
capturedPieceId = captured != null ? captured.id : -1,
isLocal = isLocal,
isCheck = check,
moverCamp = moverCamp
};
OnMoveApplied?.Invoke(args);
if (gameOver) SetGameOver(moverCamp);
else OnTurnChanged?.Invoke(currentTurn);
}
///
/// 悔棋:回退最近一步(一个半回合,双方确认后各调一次,两端回退同一手)
///
public bool UndoOneStep()
{
var r = recorder.PopLast();
if (r == null) return false;
board.UndoMove(r.piece, r.from, r.captured);
currentTurn = r.piece.camp;
moveCount--;
isGameOver = false;
winnerCamp = ChessCamp.None;
OnUndoApplied?.Invoke(1);
OnTurnChanged?.Invoke(currentTurn);
return true;
}
private void SetGameOver(ChessCamp winner)
{
isGameOver = true;
winnerCamp = winner;
OnGameOver?.Invoke(winner);
}
}