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 moveRecords; public EventHandler 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( 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(); } }