|
| 1 | + |
| 2 | +class GameState: |
| 3 | + |
| 4 | + def __init__(self): |
| 5 | + self.board = [ |
| 6 | + ["bR", "bN", "bB", "bQ", "bK", "bB", "bN", "bR"], |
| 7 | + ["bp", "bp", "bp", "bp", "bp", "bp", "bp", "bp"], |
| 8 | + ["--", "--", "--", "--", "--", "--", "--", "--"], |
| 9 | + ["--", "--", "--", "--", "--", "--", "--", "--"], |
| 10 | + ["--", "--", "--", "--", "--", "--", "--", "--"], |
| 11 | + ["--", "--", "--", "--", "--", "--", "--", "--"], |
| 12 | + ["wp", "wp", "wp", "wp", "wp", "wp", "wp", "wp"], |
| 13 | + ["wR", "wN", "wB", "wQ", "wK", "wB", "wN", "wR"]] |
| 14 | + self.moveFunctions = {'p': self.getPawnMoves, 'R': self.getRookMoves, 'N': self.getKnightMoves, |
| 15 | + 'B': self.getBishopMoves, 'Q': self.getQueenMoves, 'K': self.getKingMoves} |
| 16 | + self.whiteToMove = True, |
| 17 | + self.moveLog = [] |
| 18 | + self.whiteKingLocation = (7, 4) |
| 19 | + self.blackKingLocation = (0, 4) |
| 20 | + self.checkMate = False |
| 21 | + self.staleMate = False |
| 22 | + |
| 23 | + def makeMove(self, move): |
| 24 | + self.board[move.startRow][move.startCol] = "--" |
| 25 | + self.board[move.endRow][move.endCol] = move.pieceMoved |
| 26 | + self.moveLog.append(move) |
| 27 | + self.whiteToMove = not self.whiteToMove |
| 28 | + if move.pieceMoved == "wK": |
| 29 | + self.whiteKingLocation = (move.endRow, move.endCol) |
| 30 | + elif move.pieceMoved == "bK": |
| 31 | + self.blackKingLocation = (move.endRow, move.endCol) |
| 32 | + |
| 33 | + if move.isPawnPromotion: |
| 34 | + self.board[move.endRow][move.endCol] = move.pieceMoved[0] + "Q" |
| 35 | + |
| 36 | + |
| 37 | + def undoMove(self): |
| 38 | + if len(self.moveLog) != 0: |
| 39 | + move = self.moveLog.pop() |
| 40 | + self.board[move.startRow][move.startCol] = move.pieceMoved |
| 41 | + self.board[move.endRow][move.endCol] = move.pieceCaptured |
| 42 | + self.whiteToMove = not self.whiteToMove |
| 43 | + if move.pieceMoved == "wK": |
| 44 | + self.whiteKingLocation = (move.startRow, move.startCol) |
| 45 | + if move.pieceMoved == "bK": |
| 46 | + self.blackKingLocation = (move.startRow, move.startCol) |
| 47 | + """ |
| 48 | + All move considering checks |
| 49 | + """ |
| 50 | + def getValidMoves(self): |
| 51 | + moves = self.getAllPossibleMoves() |
| 52 | + for i in range(len(moves)-1, -1, -1): |
| 53 | + self.makeMove(moves[i]) |
| 54 | + self.whiteToMove = not self.whiteToMove |
| 55 | + if self.inCheck(): |
| 56 | + moves.remove(moves[i]) |
| 57 | + self.whiteToMove = not self.whiteToMove |
| 58 | + self.undoMove() |
| 59 | + if len(moves) == 0: |
| 60 | + if self.inCheck(): |
| 61 | + self.checkMate = True |
| 62 | + else: |
| 63 | + self.staleMate = True |
| 64 | + else: |
| 65 | + self.checkMate = False |
| 66 | + self.staleMate = False |
| 67 | + |
| 68 | + return moves |
| 69 | + |
| 70 | + def inCheck(self): |
| 71 | + if self.whiteToMove: |
| 72 | + return self.squareUnderAttack(self.whiteKingLocation[0], self.whiteKingLocation[1]) |
| 73 | + else: |
| 74 | + return self.squareUnderAttack(self.blackKingLocation[0], self.blackKingLocation[1]) |
| 75 | + |
| 76 | + def squareUnderAttack(self, r, c): |
| 77 | + self.whiteToMove = not self.whiteToMove |
| 78 | + oppMoves = self.getAllPossibleMoves() |
| 79 | + self.whiteToMove = not self.whiteToMove |
| 80 | + for move in oppMoves: |
| 81 | + if move.endRow == r and move.endCol == c: |
| 82 | + return True |
| 83 | + return False |
| 84 | + |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | + """ |
| 89 | + All move without considering checks |
| 90 | + """ |
| 91 | + def getAllPossibleMoves(self): |
| 92 | + moves = [] |
| 93 | + for r in range(len(self.board)): |
| 94 | + for c in range(len(self.board[r])): |
| 95 | + turn = self.board[r][c][0] # b or w based on turn |
| 96 | + if(turn == 'w' and self.whiteToMove) or (turn == 'b' and not self.whiteToMove): |
| 97 | + piece = self.board[r][c][1] |
| 98 | + self.moveFunctions[piece](r,c, moves) |
| 99 | + return moves |
| 100 | + |
| 101 | + |
| 102 | + def getPawnMoves(self, r, c, moves): |
| 103 | + if self.whiteToMove: |
| 104 | + if self.board[r-1][c] == "--": |
| 105 | + moves.append(Move((r, c),(r-1, c), self.board)) |
| 106 | + if r == 6 and self.board[r-2][c] == "--": |
| 107 | + moves.append(Move((r, c),(r-2, c), self.board)) |
| 108 | + if c-1 >= 0: |
| 109 | + if self.board[r-1][c-1][0] == 'b': |
| 110 | + moves.append(Move((r, c),(r-1, c-1), self.board)) |
| 111 | + if c+1 <= 7: |
| 112 | + if self.board[r-1][c+1][0] == 'b': |
| 113 | + moves.append(Move((r, c),(r-1, c+1), self.board)) |
| 114 | + |
| 115 | + else: |
| 116 | + if self.board[r+1][c] == "--": |
| 117 | + moves.append(Move((r, c),(r+1, c), self.board)) |
| 118 | + if r == 1 and self.board[r+2][c] == "--": |
| 119 | + moves.append(Move((r, c),(r+2, c), self.board)) |
| 120 | + if c-1 >= 0: |
| 121 | + if self.board[r+1][c-1][0] == 'w': |
| 122 | + moves.append(Move((r, c),(r+1, c-1), self.board)) |
| 123 | + if c+1 <= 7: |
| 124 | + if self.board[r+1][c+1][0] == 'w': |
| 125 | + moves.append(Move((r, c),(r+1, c+1), self.board)) |
| 126 | + |
| 127 | + def getRookMoves(self, r, c, moves): |
| 128 | + directions = ((-1, 0), (0, -1), (1, 0), (0, 1)) |
| 129 | + enemyColor = "b" if self.whiteToMove else "w" |
| 130 | + for d in directions: |
| 131 | + for i in range(1, 8): |
| 132 | + endRow = r + d[0] * i |
| 133 | + endCol = c + d[1] * i |
| 134 | + if 0 <= endRow < 8 and 0 <= endCol < 8: |
| 135 | + endPiece = self.board[endRow][endCol] |
| 136 | + if endPiece == "--": |
| 137 | + moves.append(Move((r,c), (endRow, endCol), self.board)) |
| 138 | + elif endPiece[0] == enemyColor: |
| 139 | + moves.append(Move((r,c), (endRow, endCol), self.board)) |
| 140 | + break |
| 141 | + else: |
| 142 | + break |
| 143 | + else: |
| 144 | + break |
| 145 | + |
| 146 | + def getKnightMoves(self, r,c,moves): |
| 147 | + knightMoves = ((-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2,1)) |
| 148 | + allyColor = "w" if self.whiteToMove else "b" |
| 149 | + for m in knightMoves: |
| 150 | + endRow = r + m[0] |
| 151 | + endCol = c + m[1] |
| 152 | + if 0 <= endRow < 8 and 0 <= endCol < 8: |
| 153 | + endPiece = self.board[endRow][endCol] |
| 154 | + if endPiece[0] != allyColor: |
| 155 | + moves.append(Move((r,c), (endRow, endCol), self.board)) |
| 156 | + |
| 157 | + def getBishopMoves(self, r,c,moves): |
| 158 | + directions = ((-1, -1), (-1, 1), (1, -1), (1, 1)) |
| 159 | + enemyColor = "b" if self.whiteToMove else "w" |
| 160 | + for d in directions: |
| 161 | + for i in range(1, 8): |
| 162 | + endRow = r + d[0] * i |
| 163 | + endCol = c + d[1] * i |
| 164 | + if 0 <= endRow < 8 and 0 <= endCol < 8: |
| 165 | + endPiece = self.board[endRow][endCol] |
| 166 | + if endPiece == "--": |
| 167 | + moves.append(Move((r,c), (endRow, endCol), self.board)) |
| 168 | + elif endPiece[0] == enemyColor: |
| 169 | + moves.append(Move((r,c), (endRow, endCol), self.board)) |
| 170 | + break |
| 171 | + else: |
| 172 | + break |
| 173 | + else: |
| 174 | + break |
| 175 | + |
| 176 | + def getQueenMoves(self, r,c,moves): |
| 177 | + self.getRookMoves(r, c, moves) |
| 178 | + self.getBishopMoves(r, c, moves) |
| 179 | + |
| 180 | + def getKingMoves(self, r,c,moves): |
| 181 | + kingMoves = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1,1) ) |
| 182 | + allyColor = "w" if self.whiteToMove else "b" |
| 183 | + for i in range(8): |
| 184 | + endRow = r + kingMoves[i][0] |
| 185 | + endCol = c + kingMoves[i][1] |
| 186 | + if 0 <= endRow < 8 and 0 <= endCol < 8: |
| 187 | + endPiece = self.board[endRow][endCol] |
| 188 | + if endPiece[0] != allyColor: |
| 189 | + moves.append(Move((r,c), (endRow, endCol), self.board)) |
| 190 | +class Move(): |
| 191 | + |
| 192 | + ranksToRow = {"1": 7, "2": 6, "3": 5, "4": 4, |
| 193 | + "5": 3, "6": 2, "7": 1, "8": 0} |
| 194 | + rowsToRanks = {v: k for k, v in ranksToRow.items()} |
| 195 | + filesToCols = {"a": 0, "b": 1, "c": 2, "d": 3, |
| 196 | + "e": 4, "f": 5, "g": 6, "h": 7} |
| 197 | + colsToFiles = {v: k for k, v in filesToCols.items()} |
| 198 | + |
| 199 | + def __init__(self, startSq, endSq, board): |
| 200 | + self.startRow = startSq[0] |
| 201 | + self.startCol = startSq[1] |
| 202 | + self.endRow = endSq[0] |
| 203 | + self.endCol = endSq[1] |
| 204 | + self.pieceMoved = board[self.startRow][self.startCol] |
| 205 | + self.pieceCaptured = board[self.endRow][self.endCol] |
| 206 | + self.isPawnPromotion = False |
| 207 | + if (self.pieceMoved == 'wp' and self.endRow == 0) or (self.pieceMoved == 'bp' and self.endRow == 7): |
| 208 | + self.isPawnPromotion = True |
| 209 | + self.moveID = self.startRow * 1000 + self.startCol * 100 + self.endRow * 10 + self.endCol |
| 210 | + |
| 211 | + def __eq__(self, other): |
| 212 | + if isinstance(other, Move): |
| 213 | + return self.moveID == other.moveID |
| 214 | + return False |
| 215 | + |
| 216 | + |
| 217 | + def getChessNotation(self): |
| 218 | + return self.getRankFile(self.startRow, self.startCol) + self.getRankFile(self.endRow, self.endCol) |
| 219 | + |
| 220 | + def getRankFile(self, r, c): |
| 221 | + return self.colsToFiles[c] + self.rowsToRanks[r] |
| 222 | + |
0 commit comments