public bool CanAttack(ChessPieceCoord target) { var dx = target.X - Coord.X; var dy = target.Y - Coord.Y; return(CanAttack(dx, dy)); }
public void UndoMove(uint count) { while (History.Count > 0 && count > 0) { var move = History.Peek(); // undo 'global' information Turn = Chess.InverseColor(move.Color); Castling = move.Castling; EnPassantCoord = move.EnPassantCoord; HalfMove = move.HalfMove; Move = move.Move; MovePiece(move.To, move.From); var flags = move.Flags; if (flags.HasFlag(ChessMoveFlag.Promotion)) { var piece = AddPiece(Turn, ChessPieceType.Pawn, move.To); piece.Guid = move.Guid; } if (flags.HasFlag(ChessMoveFlag.Capture)) { var piece = AddPiece(Turn, move.Captured, move.To); piece.Guid = move.CapturedGuid; } if (flags.HasFlag(ChessMoveFlag.EnPassantCapture)) { var enPassantFrom = new ChessPieceCoord(move.To); enPassantFrom.MoveOffset(0, move.Color == ChessColor.Black ? 1 : -1); var piece = AddPiece(Turn, ChessPieceType.Pawn, enPassantFrom); piece.Guid = move.CapturedGuid; } if ((flags & (ChessMoveFlag.KingSideCastle | ChessMoveFlag.QueenSideCastle)) != 0) { var castlingTo = new ChessPieceCoord(move.To); var castlingFrom = new ChessPieceCoord(castlingTo); if (flags.HasFlag(ChessMoveFlag.KingSideCastle)) { castlingTo.MoveOffset(1, 0); castlingFrom.MoveOffset(-1, 0); } if (flags.HasFlag(ChessMoveFlag.QueenSideCastle)) { castlingTo.MoveOffset(-2, 0); castlingFrom.MoveOffset(1, 0); } MovePiece(castlingTo, castlingFrom); } History.Pop(); count--; } }
public GameMoveData(ChessMoveType moveType, ChessColor color, ChessPieceCoord from, ChessPieceCoord to) { MoveType = moveType; Color = color; From = from; To = to; }
public void BuildMove(List <ChessMove> storage, ChessMoveFlag result, ChessColor color, ChessPieceType type, ChessPieceCoord from, ChessPieceCoord to) { var fromPiece = GetPiece(from); var toPiece = GetPiece(to); // AC's Chess implementation doesn't support underpromotion var promotion = ChessPieceType.Empty; if (fromPiece.Type == ChessPieceType.Pawn && (to.Rank == 1 || to.Rank == 8)) { promotion = ChessPieceType.Queen; result |= ChessMoveFlag.Promotion; } var captured = ChessPieceType.Empty; if (toPiece != null) { captured = toPiece.Type; } else if (result.HasFlag(ChessMoveFlag.EnPassantCapture)) { captured = ChessPieceType.Pawn; var enPassantCoord = new ChessPieceCoord(to); enPassantCoord.MoveOffset(0, color == ChessColor.Black ? 1 : -1); toPiece = GetPiece(enPassantCoord); } storage.Add(new ChessMove(result, color, type, from, to, promotion, captured, Move, HalfMove, Castling, EnPassantCoord, fromPiece.Guid, captured != ChessPieceType.Empty ? toPiece.Guid : new ObjectGuid(0))); }
public ChessDelayedAction(ChessDelayedActionType action, ChessColor color, ChessPieceCoord from, ChessPieceCoord to, bool stalemate = false) { Action = action; Color = color; From = from; To = to; Stalemate = stalemate; }
public ChessMoveResult AsyncCalculateAiSimpleMove(ChessAiAsyncTurnKey key, ref ChessPieceCoord from, ref ChessPieceCoord to) { var color = Turn; var bestBoardScore = 0.0f; ChessMove bestMove = null; var storage = new List <ChessMove>(); GenerateMoves(color, storage); var nonCheckMoves = new List <ChessMove>(); foreach (var generatedMove in storage) { // no need to evaluate the board if the ai has checkmated the other player var result = FinalizeMove(generatedMove); if (result.HasFlag(ChessMoveResult.OKMoveCheckmate)) { from = generatedMove.From; to = generatedMove.To; return(result); } if (!InCheck(color)) { var boardScore = EvaluateBoard(); if (boardScore > bestBoardScore) { bestMove = generatedMove; bestBoardScore = boardScore; } nonCheckMoves.Add(generatedMove); } UndoMove(1); } // every generated move had the same board score, pick one at random // this shouldn't happen, just here to prevent crash if (bestMove == null && nonCheckMoves.Count > 0) { var rng = ThreadSafeRandom.Next(0, nonCheckMoves.Count - 1); rng = 0; // easier debugging bestMove = nonCheckMoves[rng]; } // checkmate / stalemate if (bestMove == null) { return(ChessMoveResult.NoMoveResult); } from = bestMove.From; to = bestMove.To; return(FinalizeMove(bestMove)); }
public BasePiece GetPiece(ChessPieceCoord from) { if (!from.IsValid()) { return(null); } return(Board[from.X + from.Y * Chess.BoardSize]); }
public void RemovePiece(ChessPieceCoord target) { var piece = GetPiece(target); if (piece != null) { RemovePiece(piece); } }
public bool CanAttack(ChessColor attacker, ChessPieceCoord victim) { for (uint x = 0; x < Chess.BoardSize; x++) { for (uint y = 0; y < Chess.BoardSize; y++) { var piece = Board[x + y * Chess.BoardSize]; if (piece == null) { continue; } if (piece.Color != attacker) { continue; } if (piece.CanAttack(victim)) { // the knight can jump over other pieces and the pawn can only attack a single space if (piece.Type == ChessPieceType.Knight || piece.Type == ChessPieceType.Pawn) { return(true); } var range = Chess.PieceOffsets[piece.Type]; for (var i = 0; i < range.Count; i++) { var from = piece.Coord; var to = new ChessPieceCoord(from); while (true) { to.MoveOffset(range[i]); if (!to.IsValid()) { break; } var toPiece = GetPiece(to); if (toPiece != null) { if (to.Equals(victim)) { return(true); } break; } } } } } } return(false); }
public void CalculateWeeniePosition(ChessPieceCoord coord, ChessColor color, AFrame frame) { var heading = (uint)ChessBoard.PhysicsObj.Position.Frame.get_heading(); heading += color == ChessColor.Black ? 180u : 0u; heading %= 360; frame.Origin += new Vector3(coord.X - 3.5f, coord.Y - 3.5f, 0.0f); frame.set_heading(heading); }
public void MoveEnqueue(Player player, ChessPieceCoord from, ChessPieceCoord to) { if (State != ChessState.InProgress) { return; } var color = GetColor(player.Guid); Actions.Enqueue(new ChessDelayedAction(ChessDelayedActionType.Move, color, from, to)); }
public void MovePiece(ChessPieceCoord from, ChessPieceCoord to) { var fromPiece = GetPiece(from); fromPiece.Coord = to; RemovePiece(to); Board[to.Offset] = Board[from.Offset]; Board[from.Offset] = null; }
public void AsyncMoveAiSimple(ChessAiAsyncTurnKey key, ChessAiMoveResult result) { Debug.Assert(AiState == ChessAiState.WaitingForWorker); AiState = ChessAiState.InProgress; ChessPieceCoord from = null, to = null; var moveResult = Logic.AsyncCalculateAiSimpleMove(key, ref from, ref to); result.SetResult(moveResult, from, to); AiState = ChessAiState.WaitingForFinish; }
public ChessMoveResult DoMove(ChessColor color, ChessPieceCoord from, ChessPieceCoord to) { if (!from.IsValid()) { return(ChessMoveResult.BadMoveDestination); } if (!to.IsValid()) { return(ChessMoveResult.BadMoveDestination); } if (Turn != color) { return(ChessMoveResult.BadMoveNotYourTurn); } var fromPiece = GetPiece(from); if (fromPiece == null) { return(ChessMoveResult.BadMoveNoPiece); } if (fromPiece.Color != color) { return(ChessMoveResult.BadMoveNotYours); } var storage = new List <ChessMove>(); GenerateMoves(fromPiece, true, storage); ChessMove foundMove = null; foreach (var move in storage) { if (move.From.Equals(from) && move.To.Equals(to)) { foundMove = move; break; } } // if this fails the client and server failed to find a common valid move if (foundMove == null) { //return ChessMoveResult.BadMoveDestination; return(ChessMoveResult.BadMoveInvalidCommand); } return(FinalizeMove(foundMove)); }
public void AsyncMoveAiComplex(ChessAiAsyncTurnKey key, ChessAiMoveResult result) { Debug.Assert(AiState == ChessAiState.WaitingForWorker); AiState = ChessAiState.InProgress; ChessPieceCoord from = null, to = null; uint counter = 0; var moveResult = Logic.AsyncCalculateAiComplexMove(key, ref from, ref to, ref counter); result.SetResult(moveResult, from, to); result.ProfilingCounter = counter; AiState = ChessAiState.WaitingForFinish; }
public void DoCastleCheck(ChessColor color, ChessPieceCoord from) { var rookFlags = Chess.RookFlags[color]; foreach (var rookFlag in rookFlags) { if (from.X == rookFlag.Vector.X && from.Y == rookFlag.Vector.Y && (Castling[(int)color] & rookFlag.Flag) != 0) { Castling[(int)color] &= ~rookFlag.Flag; break; } } }
public ChessMoveResult AsyncCalculateAiComplexMove(ChessAiAsyncTurnKey key, ref ChessPieceCoord from, ref ChessPieceCoord to, ref uint counter) { uint depth = 3; var isMaximizingPower = true; var storage = new List <ChessMove>(); GenerateMoves(Turn, storage); var bestBoardScore = -9999.0f; ChessMove bestMove = null; foreach (var generatedMove in storage) { // no need to evaluate the board if the ai has checkmated the other player var result = FinalizeMove(generatedMove); if (result.HasFlag(ChessMoveResult.OKMoveCheckmate)) { from = generatedMove.From; to = generatedMove.To; return(result); } var boardScore = MinimaxAlphaBeta(depth - 1, -10000, 10000, !isMaximizingPower, ref counter); UndoMove(1); if (boardScore >= bestBoardScore) { bestMove = generatedMove; bestBoardScore = boardScore; } } // ever generated move had the same board score, pick one at random // this shouldn't happen, just here to prevent crash if (bestMove == null && storage.Count > 0) { var rng = ThreadSafeRandom.Next(0, storage.Count - 1); bestMove = storage[rng]; } Debug.Assert(bestMove != null); from = bestMove.From; to = bestMove.To; return(FinalizeMove(bestMove)); }
public ChessMove(ChessMoveFlag flags, ChessColor color, ChessPieceType type, ChessPieceCoord from, ChessPieceCoord to, ChessPieceType promotion, ChessPieceType captured, uint move, uint halfMove, List <ChessMoveFlag> castling, ChessPieceCoord enPassantCoord, ObjectGuid guid, ObjectGuid capturedGuid) { Flags = flags; Color = color; Type = type; From = new ChessPieceCoord(from); To = new ChessPieceCoord(to); Promotion = promotion; Captured = captured; Move = move; HalfMove = halfMove; Castling = castling; EnPassantCoord = enPassantCoord; Guid = guid; CapturedGuid = capturedGuid; }
public BasePiece AddPiece(ChessColor color, ChessPieceType type, uint x, uint y) { var to = new ChessPieceCoord((int)x, (int)y); Debug.Assert(to.IsValid()); BasePiece piece = null; switch (type) { case ChessPieceType.Pawn: piece = new PawnPiece(color, to); break; case ChessPieceType.Rook: piece = new RookPiece(color, to); break; case ChessPieceType.Knight: piece = new KnightPiece(color, to); break; case ChessPieceType.Bishop: piece = new BishopPiece(color, to); break; case ChessPieceType.Queen: piece = new QueenPiece(color, to); break; case ChessPieceType.King: piece = new KingPiece(color, to); break; default: Debug.Assert(false); break; } return(Board[x + y * Chess.BoardSize] = piece); }
public void FinalizeWeenieMove(ChessMoveResult result) { var move = Logic.GetLastMove(); Log.Add(move); // need to use destination coordinate as Logic has already moved the piece var piece = Logic.GetPiece(move.To); if (result.HasFlag(ChessMoveResult.OKMoveToEmptySquare)) { MoveWeeniePiece(piece); var flags = move.Flags; if ((flags & (ChessMoveFlag.KingSideCastle | ChessMoveFlag.QueenSideCastle)) != 0) { var castlingTo = new ChessPieceCoord(move.To); if (flags.HasFlag(ChessMoveFlag.KingSideCastle)) { castlingTo.MoveOffset(-1, 0); } if (flags.HasFlag(ChessMoveFlag.QueenSideCastle)) { castlingTo.MoveOffset(1, 0); } var rookPiece = Logic.GetPiece(castlingTo); Debug.Assert(rookPiece != null); MoveWeeniePiece(rookPiece); } } else if (result.HasFlag(ChessMoveResult.OKMoveToOccupiedSquare)) { AttackWeeniePiece(piece, move.CapturedGuid); } }
public QueenPiece(ChessColor color, ChessPieceCoord to) : base(ChessPieceType.Queen, color, to) { }
public KingPiece(ChessColor color, ChessPieceCoord to) : base(ChessPieceType.King, color, to) { }
public BasePiece(ChessPieceType type, ChessColor color, ChessPieceCoord to) { Type = type; Color = color; Coord = to; }
public KnightPiece(ChessColor color, ChessPieceCoord to) : base(ChessPieceType.Knight, color, to) { }
public PawnPiece(ChessColor color, ChessPieceCoord to) : base(ChessPieceType.Pawn, color, to) { }
public void SetResult(ChessMoveResult result, ChessPieceCoord from, ChessPieceCoord to) { Result = result; From = from; To = to; }
public static void Write(this BinaryWriter writer, ChessPieceCoord coord) { writer.Write(coord.X); writer.Write(coord.Y); }
public void InternalMove(ChessMove move) { var flags = move.Flags; var to = move.To; var from = move.From; var color = move.Color; var opColor = Chess.InverseColor(color); MovePiece(from, to); if (flags.HasFlag(ChessMoveFlag.EnPassantCapture)) { var enPassantCoord = new ChessPieceCoord(to); enPassantCoord.MoveOffset(0, color == ChessColor.Black ? 1 : -1); RemovePiece(enPassantCoord); } if (flags.HasFlag(ChessMoveFlag.Promotion)) { var pawnPiece = GetPiece(to); var guid = pawnPiece.Guid; RemovePiece(pawnPiece); var queenPiece = AddPiece(color, ChessPieceType.Queen, (uint)to.X, (uint)to.Y); queenPiece.Guid = guid; } if (move.Type == ChessPieceType.King) { // if we castled, move the rook next to our king if ((flags & (ChessMoveFlag.KingSideCastle | ChessMoveFlag.QueenSideCastle)) != 0) { var castlingTo = new ChessPieceCoord(move.To); var castlingFrom = new ChessPieceCoord(castlingTo); if (flags.HasFlag(ChessMoveFlag.KingSideCastle)) { castlingTo.MoveOffset(-1, 0); castlingFrom.MoveOffset(1, 0); } if (flags.HasFlag(ChessMoveFlag.QueenSideCastle)) { castlingTo.MoveOffset(1, 0); castlingFrom.MoveOffset(-2, 0); } MovePiece(castlingFrom, castlingTo); } // turn off castling, our king has moved Castling[(int)color] = ChessMoveFlag.None; } // turn off castling if we have moved one of our rooks if (Castling[(int)color] != ChessMoveFlag.None) { DoCastleCheck(color, from); } // turn off castling if we capture one of the opponent's rooks if (Castling[(int)opColor] != ChessMoveFlag.None) { DoCastleCheck(opColor, from); } if (flags.HasFlag(ChessMoveFlag.BigPawn)) { var enPassantCoord = new ChessPieceCoord(to); //enPassantCoord.MoveOffset(0, color == ChessColor.Black ? 2 : -2); enPassantCoord.MoveOffset(0, color == ChessColor.Black ? 1 : -1); EnPassantCoord = enPassantCoord; } else { EnPassantCoord = null; } History.Push(move); if (color == ChessColor.Black) { Move++; } // reset 50 move rule counter if a pawn is moved or a piece is captured if (move.Type == ChessPieceType.Pawn || (flags & (ChessMoveFlag.Capture | ChessMoveFlag.EnPassantCapture)) != 0) { HalfMove = 0; } else { HalfMove++; } Turn = opColor; }
public BasePiece AddPiece(ChessColor color, ChessPieceType type, ChessPieceCoord to) { return(AddPiece(color, type, (uint)to.X, (uint)to.Y)); }
public void GenerateMoves(BasePiece piece, bool single, List <ChessMove> storage) { var color = piece.Color; if (piece.Type == ChessPieceType.Pawn) { // single var from = new ChessPieceCoord(piece.Coord); var to = new ChessPieceCoord(from); to.MoveOffset(Chess.PawnOffsets[(int)color, 0]); if (GetPiece(to) == null) { BuildMove(storage, ChessMoveFlag.Normal, color, piece.Type, from, to); // second to = new ChessPieceCoord(from); to.MoveOffset(Chess.PawnOffsets[(int)color, 1]); if (GetPiece(to) == null && from.Rank == (color == ChessColor.White ? 2 : 7)) { BuildMove(storage, ChessMoveFlag.BigPawn, color, piece.Type, from, to); } } // capture for (uint i = 2; i < 4; i++) { to = new ChessPieceCoord(from); to.MoveOffset(Chess.PawnOffsets[(int)color, i]); if (!to.IsValid()) { continue; } var toPiece = GetPiece(to); if (toPiece != null && toPiece.Color != color) { BuildMove(storage, ChessMoveFlag.Capture, color, piece.Type, from, to); } else if (to.Equals(EnPassantCoord)) { BuildMove(storage, ChessMoveFlag.EnPassantCapture, color, piece.Type, from, EnPassantCoord); } } } else { var range = Chess.PieceOffsets[piece.Type]; for (var i = 0; i < range.Count; i++) { var from = piece.Coord; var to = new ChessPieceCoord(from); while (true) { to.MoveOffset(range[i]); if (!to.IsValid()) { break; } var toPiece = GetPiece(to); if (toPiece != null) { if (toPiece.Color != color) { BuildMove(storage, ChessMoveFlag.Capture, color, piece.Type, from, to); } break; } BuildMove(storage, ChessMoveFlag.Normal, color, piece.Type, from, to); // Knights and Kings can't move more than once if (piece.Type == ChessPieceType.Knight || piece.Type == ChessPieceType.King) { break; } } } } // only check for castling during full board generation or for a single king if (!single || piece.Type == ChessPieceType.King) { if ((Castling[(int)color] & ChessMoveFlag.KingSideCastle | ChessMoveFlag.QueenSideCastle) != 0) { var king = GetPiece(color, ChessPieceType.King); var kingCoord = king.Coord; var opColor = Chess.InverseColor(color); if ((Castling[(int)color] & ChessMoveFlag.KingSideCastle) != 0) { var castlingToK = new ChessPieceCoord(kingCoord); // destination king castlingToK.MoveOffset(2, 0); var castlingToR = new ChessPieceCoord(kingCoord); // destination rook castlingToR.MoveOffset(1, 0); if (GetPiece(castlingToR) == null && GetPiece(castlingToK) == null && !CanAttack(opColor, kingCoord) && !CanAttack(opColor, castlingToR) && !CanAttack(opColor, castlingToK)) { BuildMove(storage, ChessMoveFlag.KingSideCastle, color, ChessPieceType.King, kingCoord, castlingToK); } } if ((Castling[(int)color] & ChessMoveFlag.QueenSideCastle) != 0) { var castlingToK = new ChessPieceCoord(kingCoord); // destination king castlingToK.MoveOffset(-2, 0); var castlingToR = new ChessPieceCoord(kingCoord); // destination rook castlingToR.MoveOffset(-1, 0); var castlingToI = new ChessPieceCoord(kingCoord); // intermediate castlingToI.MoveOffset(-3, 0); if (GetPiece(castlingToR) == null && GetPiece(castlingToK) == null && GetPiece(castlingToI) == null && !CanAttack(opColor, kingCoord) && !CanAttack(opColor, castlingToR) && !CanAttack(opColor, castlingToK)) { BuildMove(storage, ChessMoveFlag.QueenSideCastle, color, ChessPieceType.King, kingCoord, castlingToK); } } } } }