import pygame from copy import deepcopy from .constants import BLACK, ROWS, GREEN, SQUARE_SIZE, COLS, WHITE from .piece import Piece class Board: def __init__(self): self.board = [] self.greenLeft = self.whiteLeft = 12 self.greenKings = self.whiteKings = 0 self.green = (144, 184, 59) self._createBoard() def _drawSquares(self, win): win.fill(BLACK) for row in range(ROWS): for col in range(row % 2, ROWS, 2): pygame.draw.rect(win, self.green, (row * SQUARE_SIZE, col * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE)) def _createBoard(self): for row in range(ROWS): self.board.append([]) for col in range(COLS): if col % 2 == ((row + 1) % 2): if row < 3: self.board[row].append(Piece(row, col, WHITE)) continue if row > 4: self.board[row].append(Piece(row, col, GREEN)) continue self.board[row].append(0) continue self.board[row].append(0) def draw(self, win): self._drawSquares(win) for row in range(ROWS): for col in range(COLS): piece = self.board[row][col] if piece != 0: piece.draw(win) def move(self, piece, row, col): self.board[piece.row][piece.col], self.board[row][col] = self.board[row][col], self.board[piece.row][piece.col] piece.move(row, col) if row == ROWS - 1 or row == 0: piece.makeKing() if piece.colour == WHITE: self.whiteKings += 1 if piece.colour == GREEN: self.greenKings += 1 def remove(self, skipped): for piece in skipped: self.board[piece.row][piece.col] = 0 if piece != 0: if piece.colour == GREEN: self.greenLeft -= 1 return self.whiteLeft -= 1 def getAllMoves(self, colour): moves = [] for piece in self.getAllPieces(colour): validMoves = self.getValidMoves(piece) for move, skip in validMoves.items(): tempBoard = deepcopy(self) tempPiece = tempBoard.getPiece(piece.row, piece.col) newBoard = self._simulateMove(tempPiece, move, tempBoard, skip) moves.append(newBoard) return moves def _simulateMove(self, piece, move, board, skip): board.move(piece, move[0], move[1]) if skip: board.remove(skip) return board def getPiece(self, row, col): return self.board[row][col] def winner(self): if self.greenLeft <= 0: return WHITE if self.whiteLeft <= 0: return GREEN return None def getValidMoves(self, piece): moves = {} forcedCapture = {} left = piece.col - 1 right = piece.col + 1 row = piece.row if piece.colour == GREEN or piece.king: moves.update(self._traverseLeft(row - 1, max(row - 3, -1), -1, piece.colour, left)) moves.update(self._traverseRight(row - 1, max(row - 3, -1), -1, piece.colour, right)) if piece.colour == WHITE or piece.king: moves.update(self._traverseLeft(row + 1, min(row + 3, ROWS), 1, piece.colour, left)) moves.update(self._traverseRight(row + 1, min(row + 3, ROWS), 1, piece.colour, right)) if len(moves.values()) <= 1: return moves movesValues = list(moves.values()) movesKeys = list(moves.keys()) forced = {} for i in range(len(movesKeys)): if not movesValues[i]: forced[movesKeys[i]] = moves[movesKeys[i]] if len(forced) != len(moves): forced.clear() for i in range(len(movesKeys)): if movesValues[i]: forced[movesKeys[i]] = moves[movesKeys[i]] if len(forced) != len(moves): for i in range(len(movesKeys)): if movesValues[i]: forcedCapture[movesKeys[i]] = moves[movesKeys[i]] else: forcedCapture = forced else: forcedCapture = forced return forcedCapture def scoreOfTheBoard(self): return self.whiteLeft - self.greenLeft def getAllPieces(self, colour): pieces = [] for row in self.board: for piece in row: if piece != 0 and piece.colour == colour: pieces.append(piece) return pieces def _traverseLeft(self, start, stop, step, colour, left, skipped=[]): moves = {} last = [] for row in range(start, stop, step): if left < 0: break mvs = self._traverse(row, left, skipped, moves, step, last, colour) if mvs is None: break elif isinstance(mvs, list): last = mvs else: moves.update(mvs) left -= 1 return moves def _traverseRight(self, start, stop, step, colour, right, skipped=[]): moves = {} last = [] for row in range(start, stop, step): if right >= COLS: break mvs = self._traverse(row, right, skipped, moves, step, last, colour) if mvs is None: break elif isinstance(mvs, list): last = mvs else: moves.update(mvs) right += 1 return moves def _traverse(self, row, col, skipped, moves, step, last, colour): current = self.board[row][col] if current == 0: if skipped and not last: return None elif skipped: moves[(row, col)] = last + skipped else: moves[(row, col)] = last if last: if step == -1: rowCalc = max(row - 3, 0) else: rowCalc = min(row + 3, ROWS) moves.update(self._traverseLeft(row + step, rowCalc, step, colour, col - 1, skipped=last)) moves.update(self._traverseRight(row + step, rowCalc, step, colour, col + 1, skipped=last)) return None elif current.colour == colour: return None else: last = [current] return last def step(self, move, colour): start, end = self._decode(move) start[0] = start[0] - 1 start[1] = start[1] - 1 end[0] = end[0] - 1 end[1] = end[1] - 1 reward = 0 done = False piece = self.getPiece(start[0], start[1]) if piece == 0: newStart = end end = start start = newStart piece = self.getPiece(start[0], start[1]) moves = self.getValidMoves(piece) for move, skip in moves.items(): if tuple(end) == move: self._simulateMove(piece, move, self, skip) if len(skip) == 1: reward = 2 break if len(skip) > 1: reward = 3 + len(skip) * 0.2 break reward = -0.5 break if self.winner() == colour: done = True reward = 10 return reward, self, done def _decode(self, move): # Split digits back out str_code = str(move) print(str_code) start_row = int(str_code[0]) start_col = int(str_code[1]) end_row = int(str_code[2]) end_col = int(str_code[3]) # Reconstruct positions start = [start_row, start_col] end = [end_row, end_col] return start, end # def reset(self): # self.board = [] # self.whiteLeft = self.greenLeft = 12 # self.whiteKings = self.greenKings = 0 # self._createBoard() # return self.board