diff --git a/.idea/other.xml b/.idea/other.xml new file mode 100644 index 0000000..a708ec7 --- /dev/null +++ b/.idea/other.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/changeInRewards-3.txt b/changeInRewards-3.txt new file mode 100644 index 0000000..47ba1a2 --- /dev/null +++ b/changeInRewards-3.txt @@ -0,0 +1,100 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/changeInRewards-5.txt b/changeInRewards-5.txt new file mode 100644 index 0000000..47ba1a2 --- /dev/null +++ b/changeInRewards-5.txt @@ -0,0 +1,100 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/main.py b/main.py index a793849..7df3bca 100644 --- a/main.py +++ b/main.py @@ -14,21 +14,45 @@ WIN = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Draughts") -def getRowColFromMouse(pos): +def getRowColFromMouse(pos: dict) -> tuple: + """ + Gets the row and column from the mouse position + :param pos: X and Y position of the mouse + :return: Row and column + """ x, y = pos row = y // SQUARE_SIZE col = x // SQUARE_SIZE return row, col -def drawText(text, font, color, surface, x, y): - textobj = font.render(text, 1, color) +def drawText(text: str, font: pygame.font.SysFont, colour: tuple, surface: pygame.display, x: float, y: int) -> None: + """ + Draws text on the screen + :param text: Text to draw + :param font: System font + :param colour: Colour of the text + :param surface: The display surface + :param x: X position of the text + :param y: Y position of the text + :return None + """ + textobj = font.render(text, 1, colour) textrect = textobj.get_rect() textrect.topleft = (x, y) surface.blit(textobj, textrect) -def drawMultiLineText(surface, text, pos, font, color=pygame.Color('black')): +def drawMultiLineText(surface: pygame.display, text: str, pos: dict, font: pygame.font.SysFont, colour: tuple = pygame.Color('black')) -> None: + """ + Draws multiline text on the screen + :param surface: the display surface + :param text: text to draw + :param pos: X and Y position of the text + :param font: System font + :param colour: colour of the text + :return None + """ words = [word.split(' ') for word in text.splitlines()] # 2D array where each row is a list of words. space = font.size(' ')[0] # The width of a space. max_width, max_height = surface.get_size() @@ -36,7 +60,7 @@ def drawMultiLineText(surface, text, pos, font, color=pygame.Color('black')): word_height = None for line in words: for word in line: - word_surface = font.render(word, 0, color) + word_surface = font.render(word, 0, colour) word_width, word_height = word_surface.get_size() if x + word_width >= max_width: x = pos[0] # Reset the x. @@ -47,7 +71,12 @@ def drawMultiLineText(surface, text, pos, font, color=pygame.Color('black')): y += word_height # Start on new row. -def main(difficulty=0): +def main(difficulty: int = 0) -> None: + """ + Main function, that shows the menu before running the game + :param difficulty: difficulty of minimax + :return: None + """ pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) menuClock = pygame.time.Clock() @@ -114,7 +143,11 @@ def main(difficulty=0): game(difficulty) -def rulesGUI(): +def rulesGUI() -> None: + """ + Shows the rules of the game + :return: None + """ screen = pygame.display.set_mode((WIDTH, HEIGHT)) menuClock = pygame.time.Clock() click = False @@ -174,17 +207,21 @@ multi-jump until the next move.""", (50, 50), font) menuClock.tick(60) -def game(difficulty): +def game(difficulty: int) -> None: + """ + Runs the game with the given difficulty. Used for training and testing the RL algorithm + :param difficulty: The difficulty of the minimax algorithm + """ run = True clock = pygame.time.Clock() gameManager = GameManager(WIN, GREEN) rl = ReinforcementLearning(gameManager.board.getAllMoves(WHITE), gameManager.board, WHITE, gameManager) - model = rl.buildMainModel() - model.load_weights("./modelWeights/model_final.h5") + # model = rl.buildMainModel() + rl.model.load_weights("./modelWeights/model_final.h5") mm = MiniMax() totalReward = [] winners = [] - for i in range(100): + for i in range(50): score = 0 for j in range(200): print(j) @@ -194,22 +231,12 @@ def game(difficulty): # mm = MiniMax() # value, newBoard = mm.AI(difficulty, WHITE, gameManager) # gameManager.aiMove(newBoard) - # reward, newBoard = rl.AI(gameManager.board) - actionSpace = rl.encodeMoves(WHITE, gameManager.board) - if len(actionSpace) == 0: + # reward, newBoard = rl.AITrain(gameManager.board) + newBoard = rl.AITest(gameManager.board) + + if newBoard is None: print("Cannot make move") continue - totalMoves = len(actionSpace) - # moves = np.squeeze(moves) - moves = np.pad(actionSpace, (0, rl.maxSize - totalMoves), 'constant', constant_values=(1, 1)) - act_values = model.predict(rl.normalise(moves)) - val = np.argmax(act_values[0]) - val = val if val < totalMoves else totalMoves - 1 - reward, newBoard, done = gameManager.board.step(actionSpace[val], WHITE) - - # if newBoard is None: - # print("Cannot make move") - # continue gameManager.aiMove(newBoard) gameManager.update() @@ -223,8 +250,8 @@ def game(difficulty): if gameManager.winner() is not None: print("Green" if gameManager.winner() == GREEN else "White", " wins") - with open("winners.txt", "a+") as f: - f.write(str(gameManager.winner()) + "\n") + # with open(f"winners-{difficulty}.txt", "a+") as f: + # f.write(str(gameManager.winner()) + "\n") winners.append(gameManager.winner()) break @@ -241,34 +268,55 @@ def game(difficulty): pygame.display.update() if gameManager.winner() is None: - with open("winners.txt", "a+") as f: - f.write(str(0) + "\n") + # with open(f"winners-{difficulty}.txt", "a+") as f: + # f.write(str(0) + "\n") winners.append(0) gameManager.reset() rl.resetScore() print("Game: ", i, " Reward: ", score) - with open("rewards.txt", "a+") as f: - f.write(str(score) + "\n") + # with open(f"rewards-{difficulty}.txt", "a+") as f: + # f.write(str(score) + "\n") totalReward.append(score) # save model weights every 25 games - if i % 250 == 0 and i != 0: - rl.model.save("./modelWeights/model_" + str(i) + ".h5") + # if i % 250 == 0 and i != 0: + # rl.model.save("./modelWeights/model_" + str(i) + ".h5") # pygame.quit() - rl.model.save("./modelWeights/model_final.h5") + # rl.model.save("./modelWeights/model_final.h5") + change_in_rewards = [0] # Initialize with 0 for the first episode + for i in range(1, len(totalReward)): + change_in_reward = totalReward[i] - totalReward[i - 1] + change_in_rewards.append(change_in_reward) - plt.plot([i for i in range(len(totalReward))], totalReward) - plt.xlabel("Games") - plt.ylabel("Reward") - plt.show() + # with open(f"changeInRewards-{difficulty}.txt", "a+") as f: + # for i in change_in_rewards: + # f.write(str(i) + "\n") + + # episodes = list(range(1, len(totalReward) + 1)) + # + # plt.plot(episodes, change_in_rewards) + # plt.xlabel('Training Games') + # plt.ylabel('Change in Game Reward') + # plt.title('Change in Game Reward vs. Training Games') + # plt.grid(True) + # plt.show() + # + # plt.plot([i for i in range(len(totalReward))], totalReward) + # plt.xlabel("Games") + # plt.ylabel("Reward") + # plt.show() fig, ax = plt.subplots() bar = ax.bar(["Draw", "White", "Green"], [winners.count(0), winners.count(WHITE), winners.count(GREEN)]) ax.set(xlabel='Winner', ylabel='Frequency', ylim=[0, 500]) - ax.set_title("Winners") + ax.set_title(f"Winners for difficulty — {difficulty}") ax.bar_label(bar) plt.show() +# difficulties = [3, 5, 7, 9] +# +# for diff in difficulties: +# main(diff) main(3) diff --git a/minimax/minimaxAlgo.py b/minimax/minimaxAlgo.py index d4816d4..d6d2af0 100644 --- a/minimax/minimaxAlgo.py +++ b/minimax/minimaxAlgo.py @@ -2,11 +2,19 @@ import random from math import inf from utilities.constants import GREEN, WHITE +from utilities.gameManager import GameManager class MiniMax: - def AI(self, depth, maxPlayer, gameManager): + def AI(self, depth: int, maxPlayer: int, gameManager: GameManager) -> tuple: + """ + The minimax algorithm + :param depth: How deep the algorithm should go + :param maxPlayer: The current player + :param gameManager: The game manager + :return: the best evaluation and board + """ if depth == 0 or gameManager.board.winner() is not None: return gameManager.board.scoreOfTheBoard(), gameManager.board diff --git a/modelWeights/model_250.h5 b/modelWeights/model_250.h5 index 0610336..dc44e7a 100644 Binary files a/modelWeights/model_250.h5 and b/modelWeights/model_250.h5 differ diff --git a/modelWeights/model_final.h5 b/modelWeights/model_final.h5 index 25c145e..f7dfd74 100644 Binary files a/modelWeights/model_final.h5 and b/modelWeights/model_final.h5 differ diff --git a/reinforcementLearning/ReinforcementLearning.py b/reinforcementLearning/ReinforcementLearning.py index 1e8f57d..1addec2 100644 --- a/reinforcementLearning/ReinforcementLearning.py +++ b/reinforcementLearning/ReinforcementLearning.py @@ -22,8 +22,8 @@ class ReinforcementLearning(): def __init__(self, actionSpace: list, board: Board, colour: int, gameManager: GameManager) -> None: """ Constructor for the ReinforcementLearning class - :param actionSpace: the number of possible actions - :param board: the game board + :param actionSpace: The number of possible actions + :param board: The game board """ self.gameManager = gameManager self.actionSpace = actionSpace @@ -33,7 +33,7 @@ class ReinforcementLearning(): self.score = 0 self.epsilon = 1 self.gamma = .95 - self.batchSize = 256 + self.batchSize = 512 self.maxSize = 32 self.epsilonMin = .01 self.epsilonDecay = .995 @@ -42,10 +42,10 @@ class ReinforcementLearning(): self.model = self.buildMainModel() print(self.model.summary()) - def AI(self, board: Board) -> tuple: + def AITrain(self, board: Board) -> tuple: """ Learns to play the draughts game - :return: the loss + :return: The loss """ self.board = board self.state = self._convertState(self.board.board) @@ -62,10 +62,29 @@ class ReinforcementLearning(): return self.score, nextState + def AITest(self, board: Board) -> Board: + """ + Runs the AI + :param board: The board + :return: The new board + """ + actionSpace = self.encodeMoves(WHITE, board) + if len(actionSpace) == 0: + print("Cannot make move") + return None + totalMoves = len(actionSpace) + # moves = np.squeeze(moves) + moves = np.pad(actionSpace, (0, self.maxSize - totalMoves), 'constant', constant_values=(1, 1)) + act_values = self.model.predict(self.normalise(moves)) + val = np.argmax(act_values[0]) + val = val if val < totalMoves else totalMoves - 1 + reward, newBoard, done = board.step(actionSpace[val], WHITE) + return newBoard + def buildMainModel(self) -> Sequential: """ Build the model for the AI - :return: the model + :return: The model """ # Board model modelLayers = [ @@ -93,7 +112,7 @@ class ReinforcementLearning(): def _replay(self) -> None: """ trains the model - :return: None (void) + :return: None """ if len(self.memory) < self.batchSize: # Not enough data to replay and test the model @@ -132,19 +151,19 @@ class ReinforcementLearning(): def _remember(self, state: np.array, action: int, reward: float, nextState: np.array, done: bool) -> None: """ Remembers what it has learnt - :param state: the current state - :param action: the action taken - :param reward: the reward for the action - :param nextState: the next state - :param done: whether the game is finished - :return: None (void) + :param state: The current state + :param action: The action taken + :param reward: The reward for the action + :param nextState: The next state + :param done: Whether the game is finished + :return: None """ self.memory.append((state, action, reward, nextState, done)) def _act(self) -> Any: """ Chooses an action based on the available moves - :return: the action + :return: The action """ if np.random.rand() <= self.epsilon: # choose a random action from the action spaces list @@ -159,12 +178,16 @@ class ReinforcementLearning(): return self.actionSpace[0] encodedMoves = np.squeeze(self.actionSpace) encodedMoves = np.pad(encodedMoves, (0, self.maxSize - len(encodedMoves)), 'constant', constant_values=(1, 1)) - act_values = self.model.predict(self.normalise(encodedMoves)) - val = np.argmax(act_values[0]) + actValues = self.model.predict(self.normalise(encodedMoves)) + val = np.argmax(actValues[0]) val = val if val < len(self.actionSpace) else len(self.actionSpace) - 1 return self.actionSpace[val] - def resetScore(self): + def resetScore(self) -> None: + """ + Resets the score + :return: None + """ self.score = 0 def _convertState(self, board: list) -> list: @@ -195,9 +218,9 @@ class ReinforcementLearning(): def _encode(self, start: tuple, end: tuple) -> int: """ Encodes the move into an integer - :param start: tuple of start position - :param end: tuple of end position - :return: encoded move + :param start: Tuple of start position + :param end: Tuple of end position + :return: Encoded move """ start_row = start[0] start_col = end[0] @@ -209,6 +232,10 @@ class ReinforcementLearning(): return int(str(start_row) + str(start_col) + str(end_row) + str(end_col)) def _maxNextQ(self) -> float: + """ + Calculates the max Q value for the next state + :return: the max Q value + """ colour = WHITE if self.colour == GREEN else GREEN encodedMoves = self.encodeMoves(colour, self.board) if len(encodedMoves) == 0: @@ -220,9 +247,9 @@ class ReinforcementLearning(): def encodeMoves(self, colour: int, board: Board) -> list: """ Encodes the moves into a list encoded moves - :param colour: colour of the player - :param board: the board - :return: list of encoded moves + :param colour: Colour of the player + :param board: The board + :return: list Of encoded moves """ encodedMoves = [] moves = board.getAllMoves(colour) @@ -231,15 +258,23 @@ class ReinforcementLearning(): encodedMoves.append(self._encode(where[0]+1, where[1]+1)) return encodedMoves - def _boardDiff(self, board, move): + def _boardDiff(self, board: Board, move: Board) -> np.array: + """ + Finds the difference between the two boards + :param board: The current board + :param move: The new board + :return: the difference between the two boards + """ cnvState = np.array(self._convertState(board.board)) cnvMove = np.array(self._convertState(move.board)) diff = np.subtract(cnvMove, cnvState) diff = np.nonzero(diff) return diff - def normalise(self, data): + def normalise(self, data: np.array) -> np.array: """ Normalise the data + :param data: the data to normalise + :return: normalised data """ return data / 10000 \ No newline at end of file diff --git a/results.py b/results.py index 3573d0a..7d0b17d 100644 --- a/results.py +++ b/results.py @@ -1,27 +1,80 @@ import matplotlib.pyplot as plt - +import numpy as np from utilities.constants import GREEN, WHITE # winners = [] -with open("winners.txt") as f: +with open("winners-5.txt", "r") as f: winners = f.readlines() winners = [int(x.strip()) for x in winners] +# lavg = [] +# for i in range(0, len(winners), 25): +# lavg.append(winners[i:i+25].count(2) / 25) +# +# x = np.arange(0, len(lavg)) +# y = np.array(lavg) * 100 +# +# a, b = np.polyfit(x, y, 1) +# +# fig, ax = plt.subplots(figsize=(10, 5)) +# ax.plot(y) +# ax.set_xticks(np.arange(0, len(lavg), 2)) +# ax.minorticks_on() +# ax.plot(x, a*x+b, color='red', linestyle='--', linewidth=2) +# ax.set_ylim([0, 100]) +# ax.set_title("Winners Average") +# ax.grid(which='major', linestyle='-', linewidth='0.5', color='black') +# ax.grid(which='minor', linestyle=':', linewidth='0.5') +# ax.set_xlabel("Average Set") +# ax.set_ylabel("Percentage of Wins") +# ax.tick_params(which="minor", bottom=False, left=False) +# plt.show() fig, ax = plt.subplots() bar = ax.bar(["Draw", "White", "Green"], [winners.count(0), winners.count(WHITE), winners.count(GREEN)]) -ax.set(xlabel='Winner', ylabel='Frequency', ylim=[0, 500]) -ax.set_title("Winners") +ax.set(xlabel='Winner', ylabel='Frequency', ylim=[0, 100]) +ax.set_title("Winners at Depth 5") +ax.grid(which='major', linestyle='-', linewidth='0.5', color='grey', axis='y') ax.bar_label(bar) plt.show() +# with open("trainedRewards.txt", "r") as f: +# totalReward = f.readlines() +# +# totalReward = [float(x.strip()) for x in totalReward] +# filteredReward = list(filter(lambda x: x > -1500, totalReward)) -with open("rewardsA.txt") as f: - totalReward = f.readlines() +# change_in_rewards = [0] # Initialize with 0 for the first episode +# for i in range(1, len(totalReward)): +# change_in_reward = totalReward[i] - totalReward[i - 1] +# change_in_rewards.append(change_in_reward) +# +# games = list(range(1, len(totalReward) + 1)) - -plt.plot([i for i in range(len(totalReward))], totalReward) -plt.xlabel("Games") -plt.ylabel("Reward") -plt.show() \ No newline at end of file +# plt.plot(games, change_in_rewards) +# plt.xlabel('Training Games') +# plt.ylabel('Change in Game Reward') +# plt.title('Change in Game Reward vs. Training Games') +# plt.grid(True) +# plt.show() +# major_ticks = np.arange(0, 101, 20) +# minor_ticks = np.arange(0, 101, 5) +# +# plt.plot([i for i in range(len(totalReward))], totalReward) +# plt.title("Rewards to Games") +# plt.xlabel("Games") +# plt.ylabel("Reward") +# plt.xticks(major_ticks) +# plt.xticks(minor_ticks, minor=True) +# plt.yticks(major_ticks) +# plt.yticks(minor_ticks, minor=True) +# plt.grid(which='both') +# plt.show() +# +# plt.plot([i for i in range(len(filteredReward))], filteredReward) +# plt.title("Filtered Rewards to Games") +# plt.xlabel("Games") +# plt.ylabel("Reward") +# plt.grid(which='both') +# plt.show() diff --git a/rewards-5.txt b/rewards-5.txt new file mode 100644 index 0000000..5688a80 --- /dev/null +++ b/rewards-5.txt @@ -0,0 +1,56 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/rewardsA.txt b/rewardsA.txt deleted file mode 100644 index 1b6ed1e..0000000 --- a/rewardsA.txt +++ /dev/null @@ -1,511 +0,0 @@ -300.5 -132.5 --20.89999999999999 -160.90000000000003 -83.0 --1619.300000000002 -203.0000000000002 -180.3 --76.10000000000002 -207.60000000000008 -234.6000000000001 -95.89999999999996 -198.10000000000005 --57.29999999999997 --121.5 -27.0 -133.49999999999997 --47.5 --3638.4999999999956 -265.5 -289.5 -259.9000000000001 --7972.5 -230.5 -220.5 -160.0 -135.0 -330.5 -282.5 -320.5 -195.5 -149.0 -207.5 -246.5 -166.5 -234.0 -262.5 -240.0 -199.0 -150.0 -274.0 -175.5 -200.5 -113.0 -206.5 --323.0 -116.5 -270.0 -60.0 -203.0 -78.0 -275.0 --262.5 -311.5 --18.0 --362.0 -188.0 --4712.5 -179.5 --75.0 --2201.5 --276.0 -95.5 -20.0 -237.5 -244.0 -160.0 --1834.5 --54.5 -102.5 --5285.0 -150.5 -137.5 --32.0 -208.0 -168.0 -192.5 -205.5 -273.0 -335.0 -150.5 --2837.0 -205.5 --182.5 -138.0 -22.5 -316.5 -170.0 -72.5 -149.0 -137.5 -110.5 -137.5 -25.5 -112.5 -96.5 --1635.0 --203.0 --239.5 -240.0 -203.0 -112.5 -115.5 -309.0 -227.5 --5185.0 --48.0 -108.0 -154.0 -300.0 -73.0 -194.5 -163.0 -190.0 -106.5 -123.0 -260.0 -192.5 -250.0 -248.0 -133.0 -195.0 --4912.5 -124.0 --53.0 -138.0 -185.5 --40.0 --116.5 -256.00000000000017 -97.5 -77.5 -197.5 -94.5 -135.5 --99.5 -237.5 -127.5 --420.0 -170.0 -100.0 -150.5 --145.0 --65.0 -136.5 -188.5 --150.0 --275.0 --6480.0 -188.0 -217.5 -121.5 -213.0 -15.5 --140.0 -195.5 -130.5 -38.5 -85.5 --5195.0 -207.5 -155.0 -151.5 -132.5 -314.0 -197.5 -149.0 -107.5 -214.0 -205.5 --5377.5 --1379.5 -87.0 -165.0 --92.5 -281.5 -238.0 -162.5 -158.0 -200.5 --5247.5 --1065.0 -383.0 -164.0 --202.0 -137.5 -3.0 -125.0 -189.0 -189.0 -118.0 -147.5 --5992.5 -137.5 -248.0 -95.0 -147.5 -16.5 -200.0 -245.5 --73.0 -172.5 -219.0 --80.0 --40.0 -131.5 -110.0 -45.0 -174.0 -211.5 --22.0 -128.0 --5545.0 -117.5 -194.0 -148.0 -350.5 --399.5 -219.0 -177.5 -105.0 -142.5 -215.0 -127.5 --942.0 -116.5 --5062.5 -219.0 -135.0 -234.0 --1395.0 --47.5 -273.0 -225.0 -207.0 -180.5 -140.0 -205.5 -165.0 -202.5 --401.5 --1605.0 -137.5 -119.0 -342.5 -178.0 -122.5 --92.0 --6.5 -55.5 -223.0 --1506.0 -231.5 -225.5 -319.5 --52.5 -101.5 -222.5 -176.5 -165.5 --50.5 -164.0 -250.0 -170.5 -172.5 -202.5 -268.0 -177.5 -129.0 --13.5 --149.5 -221.5 --5887.5 --367.5 -120.5 -245.5 -176.5 -193.0 -274.0 --877.5 -192.5 --114.0 -173.0 -285.0 -59.5 -227.5 -238.0 --327.5 -121.0 -192.5 -122.5 --5857.5 -140.0 -47.0 -244.0 -352.5 -151.5 -209.0 -140.0 -248.0 -147.5 --17.5 --55.5 -188.0 -351.5 -205.5 -227.5 -75.5 -275.5 -244.0 --6337.5 -206.5 -120.0 -120.5 -62.5 --110.0 -22.5 -362.5 -197.5 --151.5 --5575.0 --2010.5 --5147.5 --405.5 -222.0 -173.0 -193.0 -380.5 -268.0 -152.5 -211.5 --497.0 -257.5 --76.0 -178.0 --49.5 --101.0 -255.5 -225.0 -337.5 -251.5 -174.5 --5635.0 -94.0 -115.0 --6140.0 --6875.0 -193.0 --1403.5 -21.5 -135.5 --5210.0 --6030.0 -93.0 -401.5 -341.5 --175.0 -151.5 --49.0 --5655.0 -277.5 --6127.5 -90.0 -145.0 -173.0 --47.0 -143.0 -225.5 -180.0 -296.5 -64.0 -175.0 -122.5 -145.0 --2247.5 -195.0 --294.5 -188.0 -170.5 --1730.0 -217.5 --206.5 --6455.0 -166.5 -205.5 -122.5 -269.0 --5850.0 -29.0 --110.0 -129.0 -197.5 --5835.0 -105.5 -163.0 -93.0 -198.0 -192.5 --544.5 -110.5 -133.0 -145.0 -85.0 -40.5 --295.0 -275.0 --273.5 --275.0 --151.0 -253.0 -70.5 -213.0 --1262.5 --166.0 --694.5 -137.5 -139.0 -265.0 -115.5 -140.5 --9.0 -217.5 -135.0 -188.0 -103.0 -312.5 -363.0 -107.5 -120.5 -10.5 --5020.0 -220.0 -245.0 -192.5 -48.0 -95.5 --117.0 -245.5 -262.5 -115.0 -155.0 -47.5 -177.40000000000003 -354.0 --2835.0 --155.0 -194.0 -138.0 -241.5 -180.5 --332.5 --5125.0 --5075.0 -163.0 -79.0 -180.5 -185.5 -103.0 --460.0 -270.5 -235.5 -163.0 -315.0 -255.0 -113.0 -175.0 -50.0 -110.0 -323.0 -317.5 --64.0 -263.0 -242.5 -147.5 -208.0 --62.0 -31.5 --5622.5 -128.0 -321.5 -163.0 -255.5 -109.0 --5800.0 --5177.5 -188.0 -220.5 -237.5 --27.5 -238.0 -270.5 -209.0 -200.0 -127.5 -90.0 -210.0 --117.5 -237.5 -225.0 -280.0 -216.20000000000005 --189.5 -5.0 --86.80000000000005 --266.19999999999993 -11.0 -5.5 -21.5 -27.0 --72.5 -9.9 \ No newline at end of file diff --git a/rewardsBefore.txt b/rewardsBefore.txt deleted file mode 100644 index 55d5aaf..0000000 --- a/rewardsBefore.txt +++ /dev/null @@ -1,500 +0,0 @@ -18.5 -18.8 -275.6 --1.5 --149.0 -71.70000000000027 --1462.0 -266.3000000000002 -154.40000000000003 -229.19999999999996 --947.9000000000011 -186.60000000000005 --181.09999999999985 -94.89999999999993 -120.39999999999995 --242.09999999999994 --4030.0 -57.100000000000264 -107.10000000000001 -216.5 --187.5 -167.90000000000003 -181.40000000000003 --62.5 -105.5 -132.5 --115.0 --5192.5 -100.5 -295.5 --335.5 -245.0 -178.0 -295.0 -203.0 -209.0 -135.0 -239.0 -302.5 -135.5 -260.0 -12.0 -252.5 -273.0 -154.0 -130.5 -195.5 --1349.5 -133.0 -187.5 -227.0 --783.5 -223.0 --372.5 -188.0 -175.5 -210.0 --5047.5 --53.0 -191.5 -156.5 -134.0 -210.0 -206.5 -177.5 -302.5 --5577.5 -109.0 -210.0 -319.0 -200.0 -232.5 --275.0 --5812.5 -297.5 -127.5 -178.0 -320.0 -165.5 --87.5 -175.5 -60.0 -113.0 -342.5 --185.5 --50.0 -261.5 -265.5 -106.5 -240.0 -268.0 --290.0 -140.0 -164.0 -63.0 -84.0 -166.5 -144.0 -237.5 -98.0 -103.5 -115.5 -163.0 -301.5 -99.0 -212.5 -122.5 -155.0 -298.0 -160.0 -111.5 -248.0 -150.5 -180.5 -141.5 --75.0 -225.5 -107.5 -220.5 -160.5 --5420.0 --99.5 -155.5 -250.0 --155.5 --321.5 -188.0 -135.5 -143.0 -322.5 -170.5 -125.5 -202.5 -140.5 --393.5 -105.0 -163.0 -134.0 -157.5 -158.0 -185.5 --5630.0 -125.5 -190.5 -202.5 -279.0 -152.5 -223.0 -155.0 -198.0 -174.0 --321.0 -310.5 -110.5 -191.5 --664.5 -151.5 -178.0 -235.5 -202.5 -214.0 --23.0 --155.0 -267.5 -199.0 -93.0 -225.0 --5925.0 -145.0 -120.0 -283.0 -37.5 -80.0 -350.0 -148.0 --60.5 -177.5 --82.5 --647.5 -167.5 -121.5 -216.5 -291.5 -290.0 -133.0 --25.5 -210.5 --970.0 -288.0 -288.0 -162.5 --932.5 -9.0 --37.0 -0.0 -310.0 --97.0 --49.0 -75.0 -4.5 --32.5 --66.5 --108.5 -147.5 -200.5 -262.5 -127.5 --1756.0 --7.0 -14.0 -160.0 -148.0 -284.0 -182.5 -221.5 -227.5 -132.5 --5637.5 --4980.0 -290.5 --423.5 -240.0 --557.5 --130.0 --339.5 -310.0 -137.5 -105.5 -157.5 --6457.5 -230.5 -103.0 --5075.0 -133.5 -189.0 -222.5 -157.5 -113.0 --635.0 -8.0 -112.5 --17.0 -197.0 -110.0 -247.5 -191.5 -180.0 --2.5 -233.0 -137.5 -129.0 -168.0 -158.0 -252.5 --456.0 -113.0 -280.0 -159.0 --5617.5 -288.0 -141.5 -95.5 -195.5 -177.5 -97.5 -165.0 -109.0 -149.0 -124.0 -245.5 -78.0 -158.0 -147.5 --99.5 -209.0 -238.0 -95.0 --27.5 -185.0 -100.5 -228.0 --1695.0 -265.0 -288.0 --164.5 -117.5 -160.0 --2533.5 --755.0 --212.0 -270.0 --455.0 --325.0 --212.0 -97.5 -100.0 -170.0 -95.0 -133.0 -305.5 --47.5 -128.0 -148.0 --5637.5 -267.5 -279.0 -170.5 -35.0 -143.0 -131.5 -230.0 --102.0 -120.5 -100.5 -240.0 -225.0 --862.5 -94.5 -150.5 -55.5 -176.5 --17.0 -275.0 --15.0 -170.5 --1231.0 -165.0 --73.5 -245.0 -118.0 -129.0 -236.5 --372.5 --25.0 -142.5 --195.0 -210.0 -8.0 -113.0 -260.0 -23.0 -132.5 -110.5 -151.5 -140.5 -247.5 -188.0 -229.0 -362.5 -249.0 --6527.5 --115.0 -115.5 --5650.0 -149.0 -243.70000000000013 --837.0 -185.5 -218.0 -28.5 -250.0 -197.5 -218.0 -47.5 -177.5 --3872.0 -155.0 --142.0 --20.0 -107.5 --4294.5 -338.0 -160.0 -123.0 --72.0 -158.0 -125.5 --5392.5 -90.0 -240.0 --52.5 -95.5 --5055.0 -283.0 -130.5 -240.5 -128.0 -375.0 -250.5 -208.0 --97.0 --2302.0 -189.0 --6160.0 -110.0 --65.5 -208.0 -230.5 -328.0 -167.5 --75.5 --5710.0 -204.0 -110.0 -66.5 -208.0 -160.0 --283.0 -125.0 -293.0 -140.0 -162.5 --5.0 -140.0 -272.5 -231.5 --1350.0 --124.5 -270.0 -189.0 -234.0 -385.5 -303.09999999999957 -168.0 -187.5 -133.0 -308.0 -234.0 -140.0 -17.5 -160.0 -80.0 -188.0 -159.0 --76.5 --52.0 -225.5 -160.0 -22.5 --312.0 -174.0 -182.5 --5587.5 -157.5 -260.5 -188.5 -252.5 --5012.5 -162.0 -220.5 -408.0 -310.5 -128.0 -108.0 --321.0 -130.0 --382.0 --6447.5 -154.0 --67.5 -245.0 -277.5 --5155.0 -210.5 --300.0 -148.0 -153.0 --191.0 -95.5 -20.0 -145.5 -197.5 --210.0 -215.0 --50.0 -177.5 -298.0 --328.5 --61.0 -204.0 -138.0 -130.0 --242.5 -248.0 --5020.0 --6022.5 --4588.5 -132.5 -182.5 --117.5 --190.0 -222.5 --5312.5 --5290.0 -95.5 --177.5 -230.5 -135.0 -157.5 -221.40000000000006 diff --git a/trainedRewards.txt b/trainedRewards.txt new file mode 100644 index 0000000..9a20a5d --- /dev/null +++ b/trainedRewards.txt @@ -0,0 +1,500 @@ +180.5 +115.19999999999999 +-155.39999999999998 +-5169.4000000000015 +100.0 +-3354.2999999999956 +123.79999999999998 +-1738.0 +261.40000000000015 +120.89999999999999 +147.80000000000004 +108.0 +113.50000000000001 +110.5000000000002 +-1048.3000000000006 +75.8 +232.70000000000016 +89.10000000000001 +279.9000000000002 +165.40000000000003 +85.4 +34.20000000000016 +266.20000000000016 +101.69999999999999 +283.0 +-264.5 +225.0 +328.0 +215.5 +150.0 +-217.5 +-2920.0 +82.5 +-208.5 +150.5 +196.5 +223.0 +265.5 +-282.5 +175.5 +206.5 +221.5 +127.5 +-6337.5 +147.5 +231.5 +137.5 +-180.5 +108.0 +-339.5 +190.0 +-69.0 +52.5 +58.0 +-5575.0 +-159.5 +197.5 +177.5 +-5547.5 +-65.5 +136.5 +292.5 +-169.5 +185.0 +115.5 +198.0 +30.0 +162.5 +95.5 +170.0 +113.0 +-1405.0 +-27.0 +-4832.199999999999 +147.5 +228.0 +59.0 +262.5 +-220.0 +150.5 +177.5 +140.0 +123.0 +119.0 +137.5 +134.0 +175.5 +-5598.5 +46.5 +135.0 +205.0 +186.5 +177.5 +120.1 +332.5 +162.5 +122.5 +262.5 +-70.0 +159.0 +138.0 +240.5 +215.0 +147.5 +-118.0 +260.5 +199.0 +130.0 +265.0 +142.5 +230.0 +135.0 +197.5 +-179.5 +198.0 +288.0 +200.5 +-222.5 +165.5 +139.0 +228.0 +211.5 +197.5 +102.5 +233.0 +95.5 +-129.0 +187.5 +158.0 +295.0 +240.5 +-222.5 +-1841.5 +198.0 +113.0 +305.0 +-482.5 +125.5 +215.0 +110.0 +-180.0 +170.0 +-62.5 +215.5 +132.5 +187.5 +135.0 +-65.0 +138.0 +-1972.0 +240.5 +-237.5 +610.0 +267.5 +52.5 +-211.5 +217.5 +88.0 +305.5 +165.5 +115.0 +182.5 +-69.5 +333.0 +363.0 +112.5 +-15.5 +150.5 +118.0 +-52.5 +318.0 +174.0 +198.0 +-5705.0 +160.5 +155.0 +125.0 +165.0 +259.0 +165.5 +155.0 +-236.0 +220.5 +-15.5 +117.5 +367.5 +237.5 +255.0 +85.0 +-5342.5 +141.5 +-3582.5 +-600.0 +915.5 +179.0 +190.0 +-47.5 +275.5 +-5.0 +195.0 +128.0 +146.5 +750.5 +153.0 +-5157.5 +-279.5 +219.0 +154.0 +153.0 +-234.5 +248.0 +182.5 +122.5 +155.5 +1078.0 +102.5 +358.0 +152.5 +261.5 +239.0 +128.0 +111.5 +93.0 +310.5 +-87.0 +158.0 +113.0 +165.5 +120.0 +256.5 +90.5 +245.0 +159.0 +160.0 +-5272.0 +-88.5 +159.0 +169.0 +147.5 +-1149.5 +-372.0 +-270.0 +95.0 +142.5 +212.5 +154.0 +425.0 +153.0 +213.0 +280.5 +-80.5 +-45.90000000000003 +-2250.5 +123.50000000000003 +149.40000000000006 +219.0 +108.0 +180.0 +271.19999999999993 +202.5 +121.8000000000001 +47.599999999999966 +-35.0 +281.5 +307.5 +99.80000000000001 +154.0 +166.30000000000004 +271.5 +205.5 +145.5 +265.0 +113.0 +144.0 +88.0 +-204.5 +204.0 +215.0 +177.5 +168.0 +263.0 +66.5 +258.0 +-5477.5 +94.5 +-139.0 +190.5 +160.0 +-35.5 +149.0 +100.5 +130.0 +-40.0 +175.0 +132.5 +107.5 +143.0 +-5097.5 +97.5 +-1880.0 +-15.0 +213.0 +-601.0 +282.5 +276.5 +113.0 +106.5 +-1011.5 +128.0 +150.0 +145.5 +233.0 +209.0 +136.5 +240.0 +7.5 +-1535.0 +238.0 +185.0 +157.5 +-1660.0 +-15.5 +-145.0 +178.0 +-4997.5 +182.5 +197.5 +355.5 +130.0 +232.5 +-5420.0 +190.0 +128.0 +115.0 +2.5 +149.0 +220.0 +-87.0 +-447.5 +-4122.5 +-67.5 +-425.0 +283.0 +925.0 +49.5 +-15.0 +233.0 +215.5 +234.0 +154.0 +141.5 +226.5 +220.0 +110.5 +270.0 +253.0 +-1944.0 +215.0 +250.5 +155.0 +260.5 +185.0 +261.5 +232.5 +177.5 +-97.5 +-196.0 +230.0 +205.5 +-367.0 +265.5 +180.0 +135.5 +139.0 +103.0 +314.0 +192.5 +179.0 +97.5 +52.5 +135.0 +184.0 +-305.0 +147.5 +206.5 +157.5 +243.0 +-6125.0 +257.5 +125.60000000000002 +190.0 +-6225.0 +96.5 +350.0 +193.0 +185.5 +206.5 +223.0 +-225.0 +117.5 +170.0 +223.0 +175.5 +210.0 +-222.0 +148.60000000000002 +-133.0 +-193.5 +152.5 +-152.0 +-6245.0 +-2.0 +50.5 +-140.5 +185.5 +125.5 +208.0 +-200.0 +202.5 +112.5 +119.0 +210.5 +-1199.5 +-2.5 +102.5 +0.5 +275.5 +135.5 +-32.5 +235.5 +-617.0 +110.0 +222.5 +-372.0 +-53.0 +306.5 +117.5 +-5095.0 +223.0 +-257.0 +-5760.0 +11.5 +182.5 +160.0 +325.5 +151.5 +-327.5 +-5655.0 +62.5 +-5550.0 +195.0 +92.5 +-5290.0 +215.0 +59.0 +179.0 +188.0 +-2103.5 +253.0 +118.0 +335.0 +85.0 +207.5 +229.0 +152.5 +-188.5 +-177.5 +274.0 +220.0 +-5169.5 +128.0 +-1260.0 +140.0 +147.5 +140.0 +-505.0 +155.0 +225.5 +188.0 +131.5 +1111.5 +180.0 +-4897.5 +-687.5 +125.0 +180.0 +111.5 +-5582.5 +232.5 +153.0 +-130.5 +102.5 +189.0 +157.5 +-5685.0 +325.0 +-6870.0 +-520.5 +-3027.0 +32.5 diff --git a/winners.txt b/trainedWinners.txt similarity index 81% rename from winners.txt rename to trainedWinners.txt index c490a2c..8105b8b 100644 --- a/winners.txt +++ b/trainedWinners.txt @@ -1,136 +1,8 @@ 2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -1 -1 -2 -1 -1 -2 -2 -2 0 2 2 2 -2 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -1 -2 -2 -2 -2 -2 -2 -2 -2 -0 -2 -2 -2 -0 -1 -1 -2 -2 -2 -2 -2 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -1 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -1 -1 -2 -2 -2 -2 -2 -2 -2 -0 -1 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -1 -2 -2 -1 -1 -2 -2 -2 -2 1 2 2 @@ -143,10 +15,6 @@ 2 2 2 -0 -2 -2 -0 2 2 2 @@ -155,9 +23,12 @@ 2 2 2 -1 2 -0 +2 +2 +2 +2 +2 2 2 2 @@ -170,74 +41,20 @@ 2 0 2 -1 -2 -2 -2 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 2 2 1 2 2 +2 1 -1 -2 -2 -2 -2 -2 2 2 0 2 2 2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 0 -2 -2 -2 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 1 2 2 @@ -245,153 +62,12 @@ 2 2 2 -2 1 2 2 2 2 2 -0 -2 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -1 -2 -2 -1 -2 -2 -2 -0 -2 -2 -0 -2 -1 -2 -2 -2 -2 -2 -2 -2 -1 -1 -2 -2 -2 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -1 -0 -1 -0 -1 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -0 -0 -2 -2 -0 -0 -2 -2 -2 -2 -0 -0 -2 -2 -2 -2 -2 -1 -0 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -0 -2 -2 -2 -2 -2 -1 -0 -2 -2 -2 -2 -0 -2 -2 -2 -2 -0 -2 2 2 2 @@ -424,33 +100,11 @@ 2 2 2 +1 2 2 2 2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -0 -0 2 2 2 @@ -473,22 +127,53 @@ 2 2 2 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 2 2 -0 2 2 2 2 2 0 -0 +2 +1 +1 +2 +2 +2 +2 +2 +2 +2 2 2 2 1 2 2 +1 +2 +2 +2 +0 +2 +2 +2 +2 2 2 2 @@ -500,6 +185,72 @@ 2 2 2 +0 +2 +2 +2 +0 +2 +2 +1 +2 +2 +2 +2 +2 +0 +2 +0 +2 +2 +2 +2 +2 +2 +2 +2 +2 +0 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +0 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +22 +2 +2 +1 +2 1 2 2 @@ -507,7 +258,13 @@ 2 2 2 -0 +2 +2 +2 +1 +2 +2 +2 2 2 2 @@ -526,6 +283,142 @@ 2 2 0 +1 +1 +2 +2 +1 +2 +2 +2 +1 +2 +2 +2 +2 +0 +2 +2 +2 +2 +1 +2 +2 +2 +2 +1 +2 +2 +2 +2 +2 +2 +2 +2 +1 +2 +2 +2 +1 +1 +2 +2 +0 +2 +2 +2 +2 +2 +0 +2 +2 +2 +1 +2 +2 +1 +2 +2 +2 +1 +2 +0 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +0 +2 +2 +2 +0 +2 +2 +2 +2 +2 +2 +2 +2 +3 +2 +2 +2 +2 +2 +1 +2 +2 +2 +0 +2 +2 +1 +2 +2 +2 +2 +2 +2 2 2 2 @@ -543,6 +436,7 @@ 1 2 2 +0 2 2 0 @@ -551,6 +445,12 @@ 2 2 2 +2 +0 +2 +0 +2 +2 0 2 2 @@ -578,18 +478,6 @@ 2 2 2 -2 -2 -0 -2 -2 -2 -2 -2 -2 -2 -2 -2 0 2 0 @@ -597,14 +485,16 @@ 2 2 2 +0 2 2 -2 -2 -2 -2 -2 -2 -2 +1 +2 +0 +2 +0 +2 +0 +1 2 2 diff --git a/utilities/Board.py b/utilities/Board.py index d01954b..ebd53c5 100644 --- a/utilities/Board.py +++ b/utilities/Board.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pygame from copy import deepcopy from .constants import BLACK, ROWS, GREEN, SQUARE_SIZE, COLS, WHITE @@ -5,20 +7,32 @@ from .piece import Piece class Board: - def __init__(self): + def __init__(self) -> None: + """ + Constructor for the Board class + :return: None + """ self.board = [] self.greenLeft = self.whiteLeft = 12 self.greenKings = self.whiteKings = 0 self.green = (144, 184, 59) self._createBoard() - def _drawSquares(self, win): + def _drawSquares(self, win: pygame.display) -> None: + """ + Draws the squares on the board + :param win: The window + """ 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): + def _createBoard(self) -> None: + """ + Creates a board representation of the game + :return: None + """ for row in range(ROWS): self.board.append([]) for col in range(COLS): @@ -36,7 +50,12 @@ class Board: self.board[row].append(0) - def draw(self, win): + def draw(self, win: pygame.display) -> None: + """ + Draws the pieces on the board + :param win: The window + :return: None + """ self._drawSquares(win) for row in range(ROWS): for col in range(COLS): @@ -44,7 +63,14 @@ class Board: if piece != 0: piece.draw(win) - def move(self, piece, row, col): + def move(self, piece: Piece, row: int, col: int) -> None: + """ + Moves a piece and make it a king if it reaches the end of the board + :param piece: Piece to move + :param row: Row to move to + :param col: Column to move to + :return: None + """ self.board[piece.row][piece.col], self.board[row][col] = self.board[row][col], self.board[piece.row][piece.col] piece.move(row, col) @@ -57,7 +83,11 @@ class Board: if piece.colour == GREEN: self.greenKings += 1 - def remove(self, skipped): + def remove(self, skipped: tuple) -> None: + """ + Removes a piece from the board + :param skipped: A tuple of the piece to remove + """ for piece in skipped: self.board[piece.row][piece.col] = 0 if piece != 0: @@ -66,7 +96,12 @@ class Board: continue self.whiteLeft -= 1 - def getAllMoves(self, colour): + def getAllMoves(self, colour: int) -> list: + """ + Gets all the possible moves for a player + :param colour: colour of the player + :return: + """ moves = [] possibleMoves = [] possiblePieces = [] @@ -103,14 +138,28 @@ class Board: return moves - def _simulateMove(self, piece, move, board, skip): + def _simulateMove(self, piece: Piece, move: list, board: Board, skip: tuple) -> Board: + """ + Simulates a move on the board + :param piece: Piece to move + :param move: Move to make + :param board: Board to make the move on + :param skip: Tuple of pieces to skip + :return: Board after the move + """ board.move(piece, move[0], move[1]) if skip: board.remove(skip) return board - def getPiece(self, row, col): + def getPiece(self, row: int, col: int) -> Piece: + """ + Gets a piece from the board + :param row: Row of the piece + :param col: Column of the piece + :return: Piece + """ return self.board[row][col] def winner(self): @@ -122,7 +171,12 @@ class Board: return None - def getValidMoves(self, piece): + def getValidMoves(self, piece: Piece) -> dict: + """ + Gets all the valid moves for a piece + :param piece: Piece to get the moves for + :return: dictionary of moves + """ moves = {} forcedCapture = {} left = piece.col - 1 @@ -162,10 +216,19 @@ class Board: return forcedCapture - def scoreOfTheBoard(self): + def scoreOfTheBoard(self) -> int: + """ + Calculates the score of the board + :return: score of the board + """ return self.whiteLeft - self.greenLeft def getAllPieces(self, colour): + """ + Gets all the pieces of a player + :param colour: Piece colour + :return: Pieces of the player + """ pieces = [] for row in self.board: for piece in row: @@ -173,7 +236,17 @@ class Board: pieces.append(piece) return pieces - def _traverseLeft(self, start, stop, step, colour, left, skipped=[]): + def _traverseLeft(self, start: int, stop: int, step: int, colour: int, left: int, skipped: list = []) -> dict: + """ + Traverses the left side of the board + :param start: Start position + :param stop: Stop position + :param step: Step size + :param colour: colour of the player + :param left: Left position + :param skipped: List of pieces to skip + :return: dictionary of moves + """ moves = {} last = [] for row in range(start, stop, step): @@ -189,7 +262,17 @@ class Board: left -= 1 return moves - def _traverseRight(self, start, stop, step, colour, right, skipped=[]): + def _traverseRight(self, start: int, stop: int, step: int, colour: int, right: int, skipped: list = []) -> dict: + """ + Traverses the left side of the board + :param start: Start position + :param stop: Stop position + :param step: Step size + :param colour: colour of the player + :param right: Right position + :param skipped: List of pieces to skip + :return: dictionary of moves + """ moves = {} last = [] for row in range(start, stop, step): @@ -207,7 +290,18 @@ class Board: right += 1 return moves - def _traverse(self, row, col, skipped, moves, step, last, colour): + def _traverse(self, row: int, col: int, skipped: list, moves: dict, step: int, last: list, colour: int) -> list or None: + """ + Traverses the board + :param row: Row to traverse + :param col: Column to traverse + :param skipped: List of pieces to jump + :param moves: Dictionary of moves + :param step: Step size + :param last: List of last pieces + :param colour: Colour of the player + :return: list of last pieces or None + """ current = self.board[row][col] if current == 0: if skipped and not last: @@ -231,7 +325,13 @@ class Board: last = [current] return last - def step(self, move, colour): + def step(self, move: int, colour: int) -> None: + """ + Takes a move and executes it + :param move: The move to execute + :param colour: The colour of the player + :return: None + """ start, end = self._decode(move) start[0] = start[0] - 1 start[1] = start[1] - 1 @@ -264,7 +364,12 @@ class Board: return reward, self, done - def _decode(self, move): + def _decode(self, move: int) -> tuple: + """ + Decodes the move from a integer to a start and end tuple + :param move: The move to decode + :return: Start and end tuple + """ # Split digits back out str_code = str(move) # print(str_code) diff --git a/utilities/constants.py b/utilities/constants.py index 11bb3ce..be0f817 100644 --- a/utilities/constants.py +++ b/utilities/constants.py @@ -4,7 +4,7 @@ WIDTH, HEIGHT = 800, 800 ROWS, COLS = 8, 8 SQUARE_SIZE = WIDTH // COLS -# RGB color +# RGB colour GREEN = 1 WHITE = 2 diff --git a/utilities/gameManager.py b/utilities/gameManager.py index 5eabd1e..46289b7 100644 --- a/utilities/gameManager.py +++ b/utilities/gameManager.py @@ -1,29 +1,54 @@ +from __future__ import annotations + import pygame from utilities.Board import Board from utilities.constants import GREEN, WHITE, BLUE, SQUARE_SIZE class GameManager: - def __init__(self, win, colour): + def __init__(self, win: pygame.display, colour: int) -> None: + """ + Constructor for the GameManager class + :param win: The window + :param colour: The colour of the player + """ self._init(colour) self.win = win - def _init(self, colour): + def _init(self, colour: int) -> None: + """ + Initializes the game + :param colour: the colour of the player + """ self.selected = None self.board = Board() self.turn = colour self.validMoves = {} self.legCount = 0 - def update(self): + def update(self) -> None: + """ + Updates the GUI + return: None + """ self.board.draw(self.win) self.drawValidMoves(self.validMoves) pygame.display.update() - def reset(self): + def reset(self) -> None: + """ + Resets the game + :return: None + """ self._init(self.turn) - def select(self, row, col): + def select(self, row: int, col: int) -> bool: + """ + Selects a piece + :param row: Row of the piece + :param col: Column of the piece + :return: True + """ if self.selected: result = self._move(row, col) if not result: @@ -35,7 +60,13 @@ class GameManager: self.validMoves = self.board.getValidMoves(piece) return True - def _move(self, row, col): + def _move(self, row: int, col: int) -> bool: + """ + Moves a piece + :param row: Row of the piece + :param col: Column of the piece + :return: True if the move was successful, False otherwise + """ piece = self.board.getPiece(row, col) if self.selected and piece == 0 and (row, col) in self.validMoves: self.board.move(self.selected, row, col) @@ -62,18 +93,36 @@ class GameManager: return self.turn = GREEN - def drawValidMoves(self, moves): + def drawValidMoves(self, moves: list) -> None: + """ + Draws the valid moves + :param moves: list of valid moves + :return: None + """ for row, col in moves: pygame.draw.circle(self.win, BLUE, (col * SQUARE_SIZE + SQUARE_SIZE // 2, row * SQUARE_SIZE + SQUARE_SIZE // 2), 15) - def winner(self): + def winner(self) -> int or None: + """ + Gets the winner + :return: The winner + """ return self.board.winner() - def getBoard(self): + def getBoard(self) -> Board: + """ + Gets the board + :return: The board + """ return self.board - def aiMove(self, board): + def aiMove(self, board: Board) -> None: + """ + Makes a move for the AI + :param board: The new board + :return: None + """ if board is None: # colour = "green" if self.turn == GREEN else "white" # print("no move left for " + colour + " to make") diff --git a/utilities/piece.py b/utilities/piece.py index 9326024..4d033d0 100644 --- a/utilities/piece.py +++ b/utilities/piece.py @@ -4,7 +4,13 @@ from utilities.constants import SQUARE_SIZE, GREY, CROWN, GREEN class Piece: - def __init__(self, row, col, colour): + def __init__(self, row: int, col: int, colour: int) -> None: + """ + Initialises the piece class, which represents a piece on the board. Constructor for the piece class + :param row: Row of the piece + :param col: Column of the piece + :param colour: Colour of the piece + """ self.row = row self.col = col self.colour = colour @@ -17,24 +23,47 @@ class Piece: self.green = (144, 184, 59) self.white = (255, 255, 255) - def calcPosition(self): + def calcPosition(self) -> None: + """ + Calculates the position of the piece + :return: None + """ self.x = SQUARE_SIZE * self.col + SQUARE_SIZE // 2 self.y = SQUARE_SIZE * self.row + SQUARE_SIZE // 2 - def makeKing(self): + def makeKing(self) -> None: + """ + Makes the piece a king + :return: None + """ self.king = True - def draw(self, win): + def draw(self, win) -> None: + """ + Draws the piece + :param win: The window to draw the piece on + :return: None + """ radius = SQUARE_SIZE // 2 - self.padding pygame.draw.circle(win, GREY, (self.x, self.y), radius + self.border) pygame.draw.circle(win, self.green if self.colour == GREEN else self.white, (self.x, self.y), radius) if self.king: win.blit(CROWN, (self.x - CROWN.get_width() // 2, self.y - CROWN.get_height() // 2)) - def move(self, row, col): + def move(self, row: int, col: int) -> None: + """ + Moves the piece to a new position + :param row: Row to move to + :param col: Column to move to + :return: None + """ self.row = row self.col = col self.calcPosition() - def __repr__(self): + def __repr__(self) -> str: + """ + String representation of the piece + :return: String representation of the colour + """ return str(self.colour) diff --git a/winners-3.txt b/winners-3.txt new file mode 100644 index 0000000..c771e8b --- /dev/null +++ b/winners-3.txt @@ -0,0 +1,100 @@ +2 +2 +2 +2 +0 +2 +2 +2 +2 +2 +2 +0 +0 +2 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +0 +2 +2 +2 +2 +0 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +1 +0 +2 +2 +2 +2 +2 +2 +2 +2 +2 +1 +2 +1 +0 +2 +0 +0 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +1 +2 +2 +2 +0 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 diff --git a/winners-5.txt b/winners-5.txt new file mode 100644 index 0000000..94e3b68 --- /dev/null +++ b/winners-5.txt @@ -0,0 +1,100 @@ +2 +2 +1 +2 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +0 +2 +2 +2 +1 +2 +2 +0 +2 +2 +0 +2 +2 +0 +0 +2 +2 +2 +2 +2 +0 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +0 +2 +2 +2 +0 +2 +0 +2 +2 +2 +2 +1 +0 +2 +2 +2 +2 +2 +2 +1 +2 +2 +2 +2 +0 +2 +0 +2 +2 +2 +2 +2 +1 +2 +2 +1 +2 +2 +2 +2 +2 +2 +2 +2