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()); }
public Chess(ChessOwner co, int pos, int n) { owner = co; posId = pos; chessNum = n; state = ChessState.ALIVE; }
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()); }
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); }
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)); }
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); }
private void RemoveDangerMoves(ref List <Coordinate> moves, ChessOwner player) { ChessOwner enemy = player == ChessOwner.Black ? ChessOwner.White : ChessOwner.Black; moves.RemoveAll(GetPossibleMoves(enemy).Contains); }
public List <Coordinate> GetUsedTiles(ChessOwner owner) { return(Pieces.Where(x => x.Owner == owner).Select(x => new Coordinate(x.Rank, x.File)).ToList()); }
public List <ChessPiece> GetPieces(ChessOwner owner) { return(Pieces.Where(x => x.Owner == owner).ToList()); }
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()); }
public ChessPiece GetKing(ChessOwner player) { return(GetPieces(player).FirstOrDefault(x => x.Piece == ChessRank.King) ?? throw new Exception("Expected a king piece")); }
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); }
private List <Coordinate> GetPossibleMoves(ChessOwner player) { return(GetPieces(player).SelectMany(GetBaseMoves).ToList()); }
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; } }
//[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; }
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); }
// 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()); }
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"); }