Beispiel #1
0
        public string DrawMoves(ChessPiece focus, ChessOwner perspective, ChessIconFormat format = ChessIconFormat.Text)
        {
            List <Coordinate> moves = GetMoves(focus);
            var text = new StringBuilder();

            text.AppendLine("```");
            text.AppendLine(DrawRanks(perspective));

            bool isFlipped = perspective == ChessOwner.Black;

            for (int column = isFlipped ? Max : Min; isFlipped?column >= Min : column <= Max; column += isFlipped ? -1 : 1)
            {
                text.Append(column + 1);

                for (int row = isFlipped ? Max : Min; isFlipped?row >= Min : row <= Max; row += isFlipped ? -1 : 1)
                {
                    ChessPiece piece = GetPiece(row, column);
                    string     tile  = piece == null
                        ? moves.Contains(new Coordinate(row, column)) ? "o"
                        : EmptyTile
                        : moves.Contains(new Coordinate(row, column)) && piece.Rank == row && piece.File == column
                            ? "x"
                            : ChessPiece.GetString(piece.Piece, perspective, format);

                    text.Append($" {tile}");
                }

                text.AppendLine();
            }

            text.AppendLine("```");
            return(text.ToString());
        }
Beispiel #2
0
 public Chess(ChessOwner co, int pos, int n)
 {
     owner    = co;
     posId    = pos;
     chessNum = n;
     state    = ChessState.ALIVE;
 }
Beispiel #3
0
        public string DrawBoard(ChessOwner perspective, ChessIconFormat format = ChessIconFormat.Text)
        {
            var text = new StringBuilder();

            text.AppendLine("```");
            text.AppendLine(DrawRanks(perspective));

            bool isFlipped = perspective == ChessOwner.Black;

            for (int column = isFlipped ? Max : Min; isFlipped?column >= Min : column <= Max; column += isFlipped ? -1 : 1)
            {
                text.Append(column + 1);

                for (int row = isFlipped ? Max : Min; isFlipped?row >= Min : row <= Max; row += isFlipped ? -1 : 1)
                {
                    ChessPiece piece = GetPiece(row, column);
                    string     tile  = piece == null ? EmptyTile
                        : ChessPiece.GetString(piece.Piece, piece.Owner, format);
                    text.Append($" {tile}");
                }

                text.AppendLine();
            }

            text.AppendLine("```");
            return(text.ToString());
        }
Beispiel #4
0
        public static string GetString(ChessRank rank, ChessOwner player, ChessIconFormat format = ChessIconFormat.Text)
        {
            bool   isBlack = player == ChessOwner.Black;
            bool   isEmote = format == ChessIconFormat.Emote;
            string text    = rank switch
            {
                ChessRank.Pawn when isEmote => isBlack ? "♙" : "♟",
                   ChessRank.Pawn => "P",
                   ChessRank.Knight when isEmote => isBlack ? "♘" : "♞",
                   ChessRank.Knight => "N",
                   ChessRank.Bishop when isEmote => isBlack ? "♗" : "♝",
                   ChessRank.Bishop => "B",
                   ChessRank.Rook when isEmote => isBlack ? "♖" : "♜",
                   ChessRank.Rook => "R",
                   ChessRank.Queen when isEmote => isBlack ? "♕" : "♛",
                   ChessRank.Queen => "Q",
                   ChessRank.King when isEmote => isBlack ? "♔" : "♚",
                   ChessRank.King => "K",
                   _ => throw new ArgumentException("Unknown rank")
            };

            if (isBlack && !isEmote)
            {
                text = text.ToLower();
            }

            return(text);
        }
Beispiel #5
0
        public bool IsInCheck(ChessOwner player)
        {
            if (GetPieces(player).All(x => x.Piece != ChessRank.King))
            {
                return(false);
            }

            ChessPiece king = GetKing(player);

            ChessOwner enemy = player == ChessOwner.Black ? ChessOwner.White : ChessOwner.Black;

            return(GetPossibleMoves(enemy).Any(x => x.X == king.Rank && x.Y == king.File));
        }
Beispiel #6
0
        public bool IsCheckmate(ChessOwner player)
        {
            if (!IsInCheck(player))
            {
                return(false);
            }

            ChessPiece king = GetKing(player);

            bool canMoveKing            = GetDefaultMoves(king).Count > 0;
            List <ChessPiece> blockers  = GetBlockerPieces(king);
            List <ChessPiece> attackers = GetAttackerPieces(king);

            if (blockers.Count > 0)
            {
                attackers.RemoveAll(attacker => GetBlockableTiles(attacker, king).Any(c => blockers.Any(blocker => GetDefaultMoves(blocker).Contains(c))));
            }

            // Checkmate occurs if all attackers cannot be blocked or killed
            return(!canMoveKing && attackers.Count > 0);
        }
Beispiel #7
0
        private void RemoveDangerMoves(ref List <Coordinate> moves, ChessOwner player)
        {
            ChessOwner enemy = player == ChessOwner.Black ? ChessOwner.White : ChessOwner.Black;

            moves.RemoveAll(GetPossibleMoves(enemy).Contains);
        }
Beispiel #8
0
 public List <Coordinate> GetUsedTiles(ChessOwner owner)
 {
     return(Pieces.Where(x => x.Owner == owner).Select(x => new Coordinate(x.Rank, x.File)).ToList());
 }
Beispiel #9
0
 public List <ChessPiece> GetPieces(ChessOwner owner)
 {
     return(Pieces.Where(x => x.Owner == owner).ToList());
 }
Beispiel #10
0
        public List <ChessPiece> GetAttackerPieces(ChessPiece piece)
        {
            ChessOwner enemy = piece.Owner == ChessOwner.Black ? ChessOwner.White : ChessOwner.Black;

            return(GetPieces(enemy).Where(x => GetBaseMoves(x).Any(c => c.X == piece.Rank && c.Y == piece.File)).ToList());
        }
Beispiel #11
0
 public ChessPiece GetKing(ChessOwner player)
 {
     return(GetPieces(player).FirstOrDefault(x => x.Piece == ChessRank.King) ?? throw new Exception("Expected a king piece"));
 }
Beispiel #12
0
        private double CalcAi(double alpha, double beta, int d = 0)
        {
            //PrintHash();
            //Console.WriteLine(d);

            if (d >= CalcTime * 0.7 + 5)
            {
                return(Eval());
            }

            //double maxx = double.MinValue;
            // 胜负判断
            if (chessBoard[ChessBoardView.CHESS_BOARD_SIZE - 1, ChessBoardView.CHESS_BOARD_SIZE - 1] == ChessOwner.PLAYER1)
            {
                return(200 + Eval());    // AI胜,返回很大的收益
            }
            else if (chessBoard[0, 0] == ChessOwner.PLAYER2)
            {
                return(-200 + Eval());   // AI负,返回很小的收益
            }
            int cnt1 = 0, cnt2 = 0;

            // 对 AI 的棋子向各个方向移动后逐一评估收益,获取最大收益 alpha
            for (int i = 0; i < ChessBoardView.CHESS_BOARD_SIZE; i++)
            {
                for (int j = 0; j < ChessBoardView.CHESS_BOARD_SIZE; j++)
                {
                    // PLAYER1 表示 AI
                    if (chessBoard[i, j] == ChessOwner.PLAYER1)
                    {
                        cnt1++;
                        // 获取棋盘上AI[i, j]棋子可以移动的几个方向
                        ArrayList list = GetMoveRange(Turn.AI, i, j);

                        foreach (Object o in list)
                        {
                            // 将位置 id 转为m、n
                            // posid = m * CHESS_BOARD_SIZE + n
                            int        m   = ((int)o) / ChessBoardView.CHESS_BOARD_SIZE;
                            int        n   = ((int)o) % ChessBoardView.CHESS_BOARD_SIZE;
                            ChessOwner obk = chessBoard[m, n];
                            chessBoard[i, j] = ChessOwner.EMPTY;
                            chessBoard[m, n] = ChessOwner.PLAYER1;
                            alpha            = Math.Max(CalPlayer(alpha, beta, d + 1), alpha);

                            // 估价完成后恢复原来的棋盘状态
                            chessBoard[m, n] = obk;
                            chessBoard[i, j] = ChessOwner.PLAYER1;

                            // 发生 alpha 剪枝
                            if (alpha >= beta)
                            {
                                return(alpha);
                            }
                        }
                    }
                    if (chessBoard[i, j] == ChessOwner.PLAYER2)
                    {
                        cnt2++;
                    }
                }
            }

            if (cnt1 == 0)
            {
                return(-200 + Eval());
            }
            if (cnt2 == 0)
            {
                return(200 + Eval());
            }

            return(alpha);
        }
Beispiel #13
0
 private List <Coordinate> GetPossibleMoves(ChessOwner player)
 {
     return(GetPieces(player).SelectMany(GetBaseMoves).ToList());
 }
Beispiel #14
0
        public void MovePiece(ChessPiece piece, Coordinate tile)
        {
            ChessPiece focus = GetPiece(piece.Rank, piece.File);

            if (focus == null)
            {
                return;
            }

            if (LastMove != null)
            {
                Console.WriteLine($"{LastMove.Piece} ({LastMove.Rank}, {LastMove.File} => {LastMove.To.X}, {LastMove.To.Y})");
            }

            if (LastMove != null &&
                LastMove.Piece == ChessRank.Pawn &&
                LastMove.Player != focus.Owner &&
                LastMove.File == ((LastMove.Player == ChessOwner.Black) ? 1 : 6) &&
                LastMove.To.Y == ((LastMove.Player == ChessOwner.Black) ? 3 : 4) &&
                focus.Piece == ChessRank.Pawn &&
                tile.X == LastMove.To.X &&
                (LastMove.Player == ChessOwner.Black
                    ? LastMove.To.Y - ((LastMove.Player == ChessOwner.Black) ? 2 : 5)
                    : ((LastMove.Player == ChessOwner.Black) ? 2 : 5) - LastMove.To.Y) == 1)
            {
                ChessPiece target = GetPiece(LastMove.To.X, LastMove.To.Y);

                if (target == null)
                {
                    throw new Exception("Expected pawn at specified tile");
                }

                Pieces.Remove(target);

                ChessOwner      enemy  = focus.Owner == ChessOwner.Black ? ChessOwner.White : ChessOwner.Black;
                ChessMoveAction action = 0;

                if (IsCheckmate(enemy))
                {
                    action |= ChessMoveAction.Checkmate;
                }
                else if (IsInCheck(enemy))
                {
                    action |= ChessMoveAction.Check;
                }

                LastMove   = new ChessMove(StartedAt, focus, tile, action | ChessMoveAction.EnPassant);
                focus.Rank = tile.X;
                focus.File = tile.Y;
            }
            else
            {
                ChessPiece target = GetPiece(tile.X, tile.Y);

                ChessOwner enemy = focus.Owner == ChessOwner.Black ? ChessOwner.White : ChessOwner.Black;

                ChessMoveAction action = 0;

                if (IsCheckmate(enemy))
                {
                    action |= ChessMoveAction.Checkmate;
                }
                else if (IsInCheck(enemy))
                {
                    action |= ChessMoveAction.Check;
                }

                if (target != null)
                {
                    Pieces.Remove(target);
                    action |= ChessMoveAction.Capture;
                }

                LastMove   = new ChessMove(StartedAt, focus, tile, action);
                focus.Rank = tile.X;
                focus.File = tile.Y;
            }
        }
Beispiel #15
0
        //[Command("drawmoves")]
        public async Task DrawPieceMovesAsync(int whitePieceCount, int blackPieceCount, ChessOwner perspective)
        {
            ChessBoard board = ChessBoard.GetRandom(whitePieceCount, blackPieceCount);

            await Context.Channel.SendMessageAsync(board.DrawMoves(Randomizer.Choose(board.Pieces), perspective));
        }
        private void AiTurn()
        {
            moveChessNum = DiceUtil.GetChessNum();
            turn         = Turn.PLAYER1;
            IPlayer p = player1;

            diceLabel.Text       = moveChessNum.ToString();
            player1Label.Visible = true;
            player2Label.Visible = false;



            ArrayList candidates = new ArrayList();
            Minimax   mm;
            int       pos;

            Application.DoEvents();
            //Thread.Sleep(200);
            if ((p.Chesses[moveChessNum] as Chess).state == ChessState.ALIVE)
            {
                candidates.Add(moveChessNum);
            }
            if (candidates.Count != 0)
            {
                mm = new Minimax(this);

                pos = mm.Calc((p.Chesses[moveChessNum] as Chess).posId);
                Thread.Sleep(1000);
                Console.WriteLine((pos / ChessBoardView.CHESS_BOARD_SIZE).ToString() + ", " + (pos % ChessBoardView.CHESS_BOARD_SIZE).ToString());
                MoveTo(pos);
                return;
            }

            /*int dis = 1;
             * while (candidates.Count == 0 && dis <= 5)
             * {
             *  if (moveChessNum + dis <= 5 && (p.Chesses[moveChessNum + dis] as Chess).state == ChessState.ALIVE)
             *      candidates.Add(moveChessNum + dis);
             *  if (moveChessNum - dis >= 0 && (p.Chesses[moveChessNum - dis] as Chess).state == ChessState.ALIVE)
             *      candidates.Add(moveChessNum - dis);
             *  dis++;
             * }*/

            for (int i = moveChessNum + 1; i <= 5; i++)
            {
                if ((p.Chesses[i] as Chess).state == ChessState.ALIVE)
                {
                    candidates.Add(i);
                    break;
                }
            }

            for (int i = moveChessNum - 1; i >= 0; i--)
            {
                if ((p.Chesses[i] as Chess).state == ChessState.ALIVE)
                {
                    candidates.Add(i);
                    break;
                }
            }

            if (candidates.Count == 0)
            {
                MessageBox.Show("Player2 Win");
                return;
            }

            double bestEval    = double.MinValue;
            int    bestMoveNum = (int)candidates[0];

            Console.Write("Candidates: ");
            for (int i = 0; i < candidates.Count; i++)
            {
                Console.Write((int)candidates[i]);
                Console.Write("\t");
            }
            Console.WriteLine();
            for (int i = 0; i < candidates.Count; i++)
            {
                moveChessNum = (int)candidates[i];
                ArrayList range  = GetMoveRange(player1, moveChessNum);
                int       curPos = (p.Chesses[moveChessNum] as Chess).posId;

                int cm = curPos / ChessBoardView.CHESS_BOARD_SIZE;
                int cn = curPos % ChessBoardView.CHESS_BOARD_SIZE;

                for (int j = 0; j < range.Count; j++)
                {
                    int pid = (int)range[j];

                    int pm = pid / ChessBoardView.CHESS_BOARD_SIZE;
                    int pn = pid % ChessBoardView.CHESS_BOARD_SIZE;

                    ChessOwner obk = chessBoardView.chessBoardHash[pm, pn];
                    chessBoardView.chessBoardHash[cm, cn] = ChessOwner.EMPTY;
                    chessBoardView.chessBoardHash[pm, pn] = ChessOwner.PLAYER1;
                    mm = new Minimax(this);
                    if (bestEval < mm.Eval())
                    {
                        bestEval    = mm.Eval();
                        bestMoveNum = moveChessNum;
                    }
                    chessBoardView.chessBoardHash[pm, pn] = obk;
                    chessBoardView.chessBoardHash[cm, cn] = ChessOwner.PLAYER1;
                }
            }

            moveChessNum = bestMoveNum;
            mm           = new Minimax(this);
            pos          = mm.Calc((p.Chesses[moveChessNum] as Chess).posId);
            Thread.Sleep(1000);
            Console.WriteLine((pos / ChessBoardView.CHESS_BOARD_SIZE).ToString() + ", " + (pos % ChessBoardView.CHESS_BOARD_SIZE).ToString());
            MoveTo(pos);

            return;
        }
Beispiel #17
0
        private double CalPlayer(double alpha, double beta, int d = 0)
        {
            //Console.WriteLine(d);


            //double mini = double.MaxValue;

            if (chessBoard[ChessBoardView.CHESS_BOARD_SIZE - 1, ChessBoardView.CHESS_BOARD_SIZE - 1] == ChessOwner.PLAYER1)
            {
                return(200 + Eval());
            }
            else if (chessBoard[0, 0] == ChessOwner.PLAYER2)
            {
                return(-200 + Eval());
            }

            int cnt1 = 0, cnt2 = 0;

            for (int i = 0; i < ChessBoardView.CHESS_BOARD_SIZE; i++)
            {
                for (int j = 0; j < ChessBoardView.CHESS_BOARD_SIZE; j++)
                {
                    // PLAYER2 表示 用户
                    if (chessBoard[i, j] == ChessOwner.PLAYER2)
                    {
                        cnt2++;
                        // 获取棋盘上USER[i, j]棋子可以移动的几个方向
                        ArrayList list = GetMoveRange(Turn.USER, i, j);

                        foreach (Object o in list)
                        {
                            // 将位置 id 转为m、n
                            // posid = m * CHESS_BOARD_SIZE + n
                            int        m   = ((int)o) / ChessBoardView.CHESS_BOARD_SIZE;
                            int        n   = ((int)o) % ChessBoardView.CHESS_BOARD_SIZE;
                            ChessOwner obk = chessBoard[m, n];
                            chessBoard[i, j] = ChessOwner.EMPTY;
                            chessBoard[m, n] = ChessOwner.PLAYER2;
                            beta             = Math.Min(CalcAi(alpha, beta, d + 1), beta);

                            // 估价完成后恢复原来的棋盘状态
                            chessBoard[m, n] = obk;
                            chessBoard[i, j] = ChessOwner.PLAYER2;

                            // 发生 beta 剪枝
                            if (alpha >= beta)
                            {
                                return(beta);
                            }
                        }
                    }
                    if (chessBoard[i, j] == ChessOwner.PLAYER1)
                    {
                        cnt1++;
                    }
                }
            }
            if (cnt1 == 0)
            {
                return(-200 + Eval());
            }
            if (cnt2 == 0)
            {
                return(200 + Eval());
            }
            return(beta);
        }
Beispiel #18
0
        // 0 to 7
        // file = y
        // rank = x
        private List <Coordinate> GetBaseMoves(ChessOwner owner, ChessRank piece, int rank, int file)
        {
            var moves = new List <Coordinate>();

            switch (piece)
            {
            case ChessRank.King:
                moves.AddRange(new List <Coordinate>
                {
                    new Coordinate(rank + 1, file),
                    new Coordinate(rank - 1, file),
                    new Coordinate(rank, file + 1),
                    new Coordinate(rank, file - 1),
                    new Coordinate(rank + 1, file + 1),
                    new Coordinate(rank - 1, file + 1),
                    new Coordinate(rank + 1, file - 1),
                    new Coordinate(rank - 1, file - 1)
                });

                break;

            case ChessRank.Knight:
                moves.AddRange(new List <Coordinate>
                {
                    new Coordinate(rank + 1, file - 2),
                    new Coordinate(rank - 1, file - 2),
                    new Coordinate(rank + 1, file + 2),
                    new Coordinate(rank - 1, file + 2),
                    new Coordinate(rank + 2, file - 1),
                    new Coordinate(rank - 2, file - 1),
                    new Coordinate(rank + 2, file + 1),
                    new Coordinate(rank - 2, file + 1)
                });

                break;

            case ChessRank.Rook:
                MoveWest(ref moves, rank, file);
                MoveEast(ref moves, rank, file);
                MoveNorth(ref moves, rank, file);
                MoveSouth(ref moves, rank, file);
                break;

            case ChessRank.Bishop:
                MoveNorthWest(ref moves, rank, file);
                MoveNorthEast(ref moves, rank, file);
                MoveSouthWest(ref moves, rank, file);
                MoveSouthEast(ref moves, rank, file);
                break;

            case ChessRank.Queen:
                MoveWest(ref moves, rank, file);
                MoveEast(ref moves, rank, file);
                MoveNorth(ref moves, rank, file);
                MoveSouth(ref moves, rank, file);
                MoveNorthWest(ref moves, rank, file);
                MoveNorthEast(ref moves, rank, file);
                MoveSouthWest(ref moves, rank, file);
                MoveSouthEast(ref moves, rank, file);
                break;

            case ChessRank.Pawn:
                if (owner == ChessOwner.Black)
                {
                    moves.Add(new Coordinate(rank, file + 1));

                    if (file == 1)
                    {
                        moves.Add(new Coordinate(rank, file + 2));
                    }
                }
                else
                {
                    moves.Add(new Coordinate(rank, file - 1));

                    if (file == 6)
                    {
                        moves.Add(new Coordinate(rank, file - 2));
                    }
                }
                break;
            }

            return(moves.Where(Exclude).ToList());
        }
Beispiel #19
0
 private static string DrawRanks(ChessOwner perspective)
 {
     return(perspective == ChessOwner.Black
         ? "- H G F E D C B A"
         : "- A B C D E F G H");
 }