示例#1
0
        public bool CanAttack(ChessPieceCoord target)
        {
            var dx = target.X - Coord.X;
            var dy = target.Y - Coord.Y;

            return(CanAttack(dx, dy));
        }
示例#2
0
        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--;
            }
        }
示例#3
0
 public GameMoveData(ChessMoveType moveType, ChessColor color, ChessPieceCoord from, ChessPieceCoord to)
 {
     MoveType = moveType;
     Color    = color;
     From     = from;
     To       = to;
 }
示例#4
0
        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)));
        }
示例#5
0
 public ChessDelayedAction(ChessDelayedActionType action, ChessColor color, ChessPieceCoord from, ChessPieceCoord to, bool stalemate = false)
 {
     Action    = action;
     Color     = color;
     From      = from;
     To        = to;
     Stalemate = stalemate;
 }
示例#6
0
        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));
        }
示例#7
0
        public BasePiece GetPiece(ChessPieceCoord from)
        {
            if (!from.IsValid())
            {
                return(null);
            }

            return(Board[from.X + from.Y * Chess.BoardSize]);
        }
示例#8
0
        public void RemovePiece(ChessPieceCoord target)
        {
            var piece = GetPiece(target);

            if (piece != null)
            {
                RemovePiece(piece);
            }
        }
示例#9
0
        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);
        }
示例#10
0
        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);
        }
示例#11
0
        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));
        }
示例#12
0
        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;
        }
示例#13
0
        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;
        }
示例#14
0
        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));
        }
示例#15
0
        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;
        }
示例#16
0
        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;
                }
            }
        }
示例#17
0
        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));
        }
示例#18
0
 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;
 }
示例#19
0
        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);
        }
示例#20
0
        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);
            }
        }
示例#21
0
 public QueenPiece(ChessColor color, ChessPieceCoord to)
     : base(ChessPieceType.Queen, color, to)
 {
 }
示例#22
0
 public KingPiece(ChessColor color, ChessPieceCoord to)
     : base(ChessPieceType.King, color, to)
 {
 }
示例#23
0
 public BasePiece(ChessPieceType type, ChessColor color, ChessPieceCoord to)
 {
     Type  = type;
     Color = color;
     Coord = to;
 }
示例#24
0
 public KnightPiece(ChessColor color, ChessPieceCoord to)
     : base(ChessPieceType.Knight, color, to)
 {
 }
示例#25
0
 public PawnPiece(ChessColor color, ChessPieceCoord to)
     : base(ChessPieceType.Pawn, color, to)
 {
 }
示例#26
0
 public void SetResult(ChessMoveResult result, ChessPieceCoord from, ChessPieceCoord to)
 {
     Result = result;
     From   = from;
     To     = to;
 }
示例#27
0
 public static void Write(this BinaryWriter writer, ChessPieceCoord coord)
 {
     writer.Write(coord.X);
     writer.Write(coord.Y);
 }
示例#28
0
        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;
        }
示例#29
0
 public BasePiece AddPiece(ChessColor color, ChessPieceType type, ChessPieceCoord to)
 {
     return(AddPiece(color, type, (uint)to.X, (uint)to.Y));
 }
示例#30
0
        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);
                        }
                    }
                }
            }
        }