ZZY 8ee9732a6f feat(chinese-chess): 实现中国象棋核心逻辑和基本功能
- 抽象出 ChessCore 类,包含游戏初始化、行棋逻辑、悔棋等功能
- 重构 Player 类,优化行棋和记录逻辑
- 更新 ChessBoard 和 ChessPiece 类,适应新逻辑
- 移除冗余代码,提高代码可读性和可维护性
2024-11-07 20:48:08 +08:00

154 lines
4.9 KiB
C#

using Vector2 = Godot.Vector2;
using System;
using System.Collections;
namespace ChineseChess;
class ChessCore {
public enum Mode {
SingleMode,
MultiMode,
DebugMode,
};
public enum TurnsSideType {
Red,
Black,
};
public enum PlayerSideType {
Self,
Opponent,
Any,
};
private TurnsSideType sideType = TurnsSideType.Red;
private readonly TurnsSideType selfSide;
public readonly VirtualBoard board = new(9, 10);
private readonly Player playerSelf;
private readonly Player playerOpponent;
private readonly MoveRecords<VirtualPiece> moveRecords;
public EventHandler<VirtualBoard.MoveEventArgs> OnMove;
public ChessCore(Mode mode, TurnsSideType selfSide) {
this.selfSide = selfSide;
playerSelf = new(board, Player.PlayerType.Human);
playerOpponent = new(board, Player.PlayerType.Human);
playerSelf.OnMove += (sender, args) => {
moveRecords.AddRecord(board.GetPiece(args.To), board.GetPiece(args.From),
args.To, args.From);
};
playerOpponent.OnMove += (sender, args) => {
moveRecords.AddRecord(board.GetPiece(args.To), board.GetPiece(args.From),
args.To, args.From);
};
moveRecords = new MoveRecords<VirtualPiece>(
onAddRecordCallback: (newNode, oldNode, newPos, oldPos) => {
playerSelf.SelectedClear();
playerOpponent.SelectedClear();
},
onUndoRecordCallback: (newNode, oldNode, newPos, oldPos) => {
// GD.Print("Undo: ", newNode, "->", oldNode, ":", newPos, "->", oldPos);
VirtualPiece newPiece = newNode;
VirtualPiece oldPiece = oldNode;
board.MovePiece(newPos, oldPos);
if (newPiece != null) {
board.InsertPiece(newPiece, newPos);
}
});
switch (mode) {
case Mode.SingleMode:
break;
case Mode.MultiMode:
break;
default:
case Mode.DebugMode:
throw new NotImplementedException();
}
}
public void InitGame() {
ArrayList blackPart = InitOnePartPieces(TurnsSideType.Black, new[] {
("车", 0, 0), ("马", 1, 0), ("象", 2, 0),
("士", 3, 0), ("将", 4, 0), ("士", 5, 0),
("象", 6, 0), ("马", 7, 0), ("车", 8, 0),
("炮", 1, 2), ("炮", 7, 2),
("卒", 0, 3), ("卒", 2, 3), ("卒", 4, 3), ("卒", 6, 3), ("卒", 8, 3)
});
ArrayList redPart = InitOnePartPieces(TurnsSideType.Red, new[] {
("车", 0, -0), ("马", 1, -0), ("象", 2, -0),
("士", 3, -0), ("将", 4, -0), ("士", 5, -0),
("象", 6, -0), ("马", 7, -0), ("车", 8, -0),
("炮", 1, -2), ("炮", 7, -2),
("卒", 0, -3), ("卒", 2, -3), ("卒", 4, -3), ("卒", 6, -3), ("卒", 8, -3)
});
if (selfSide == TurnsSideType.Red) {
playerSelf.SetAllowedPieces(redPart);
playerOpponent.SetAllowedPieces(blackPart);
} else {
playerSelf.SetAllowedPieces(blackPart);
playerOpponent.SetAllowedPieces(redPart);
}
}
private ArrayList InitOnePartPieces(TurnsSideType side, (string label, int x, int y)[] positions) {
ArrayList list = new();
foreach (var (label, x, y) in positions) {
// FIXME: use a better way to initialize pieces
Vector2 pos = new(x, y + (TurnsSideType.Red == side ? 9 : 0));
VirtualPiece piece = new(label, pos);
list.Add(piece);
board.InsertPiece(piece, pos);
}
return list;
}
public void OnPosClicked(Vector2 pos, PlayerSideType clickedSide = PlayerSideType.Any) {
if (sideType == selfSide) {
playerSelf.CanMove = true;
playerOpponent.CanMove = false;
} else {
playerSelf.CanMove = false;
playerOpponent.CanMove = true;
}
switch (clickedSide) {
case PlayerSideType.Any:
playerSelf.HandleBoardPosClick(pos);
playerOpponent.HandleBoardPosClick(pos);
break;
case PlayerSideType.Self:
playerSelf.HandleBoardPosClick(pos);
break;
case PlayerSideType.Opponent:
playerOpponent.HandleBoardPosClick(pos);
break;
}
sideType = moveRecords.Count() % 2 == 0 ? TurnsSideType.Red : TurnsSideType.Black;
}
public TurnsSideType GetTurnsType() {
sideType = moveRecords.Count() % 2 == 0 ? TurnsSideType.Red : TurnsSideType.Black;
return sideType;
}
public void Undo() {
playerSelf.SelectedClear();
playerOpponent.SelectedClear();
moveRecords.Undo();
}
public void ReInit() {
playerSelf.SelectedClear();
playerOpponent.SelectedClear();
moveRecords.Clear();
board.Clear();
InitGame();
}
}