From 8774432f5b7e87fc9647c97022d38673f66a8b2f Mon Sep 17 00:00:00 2001 From: Matt Strapp Date: Mon, 26 Apr 2021 14:44:57 -0500 Subject: Add debug configs, --- python/MCTS.py | 6 +- python/agent.py | 55 ------------ python/agent_AB.py | 57 ++++++++++++ python/agent_MCTS.py | 57 ++++++++++++ python/alphaBeta.py | 125 +++++++++++++++++++++------ python/dotsandboxes/dotsandboxesagent.py | 2 - python/dotsandboxes/static/dotsandboxes.html | 6 -- python/start.sh | 5 +- 8 files changed, 218 insertions(+), 95 deletions(-) delete mode 100644 python/agent.py create mode 100644 python/agent_AB.py create mode 100644 python/agent_MCTS.py (limited to 'python') diff --git a/python/MCTS.py b/python/MCTS.py index a65e2d4..6c71ba9 100644 --- a/python/MCTS.py +++ b/python/MCTS.py @@ -1,6 +1,6 @@ import math from copy import deepcopy -from time import clock +from time import perf_counter from random import choice from GameState import GameState @@ -135,8 +135,8 @@ class MCTSGameController(GameController): self.root_node = MCTSNode(state) iterations = 0 - start_time = clock() - while clock() < start_time + time_allowed: + start_time = perf_counter() + while perf_counter() < start_time + time_allowed: node = self.select() if node.pending_moves != set(): diff --git a/python/agent.py b/python/agent.py deleted file mode 100644 index 49bc1cc..0000000 --- a/python/agent.py +++ /dev/null @@ -1,55 +0,0 @@ -import dotsandboxes.dotsandboxesagent as dba - -import sys -import argparse -import logging -from GameState import GameState, DotsAndBoxesState -from MCTS import MCTSNode, MCTSGameController - - -logger = logging.getLogger(__name__) -games = {} -agentclass = None - - -class Agent(dba.DotsAndBoxesAgent): - def __init__(self, player, nb_rows, nb_cols, timelimit): - super(Agent, self).__init__(player, nb_rows, nb_cols, timelimit) - self.GameStateClass = DotsAndBoxesState - self.game_state = self.GameStateClass(nb_rows, nb_cols, player) - self.controller = MCTSGameController() - - def register_action(self, row, column, orientation, player): - super(Agent, self).register_action(row, column, orientation, player) - # adjust agent specific board representation - move = (row, column, orientation) - self.game_state.play_move(move) - - def next_action(self): - r, c, o = self.controller.get_next_move(self.game_state, time_allowed=self.timelimit) - return r, c, o - - def end_game(self): - super(Agent, self).end_game() - - -# Adapted from provided code -def main(argv=None): - global agentclass - parser = argparse.ArgumentParser(description='Start agent to play Dots and Boxes') - parser.add_argument('--verbose', '-v', action='count', default=0, help='Verbose output') - parser.add_argument('--quiet', '-q', action='count', default=0, help='Quiet output') - parser.add_argument('port', metavar='PORT', type=int, help='Port to use for server') - args = parser.parse_args(argv) - - logger.setLevel(max(logging.INFO - 10 * (args.verbose - args.quiet), logging.DEBUG)) - logger.addHandler(logging.StreamHandler(sys.stdout)) - - agentclass = Agent - dba.agentclass = Agent - dba.start_server(args.port) - - -if __name__ == "__main__": - sys.exit(main()) - diff --git a/python/agent_AB.py b/python/agent_AB.py new file mode 100644 index 0000000..4b1ace1 --- /dev/null +++ b/python/agent_AB.py @@ -0,0 +1,57 @@ +import dotsandboxes.dotsandboxesagent as dba + +import sys +import argparse +import logging +from GameState import GameState, DotsAndBoxesState +from MCTS import MCTSNode, MCTSGameController +import alphaBeta + + +logger = logging.getLogger(__name__) +games = {} +agentclass = dba + + +class Agent(dba.DotsAndBoxesAgent): + def __init__(self, player, nb_rows, nb_cols, timelimit): + super(Agent, self).__init__(player, nb_rows, nb_cols, timelimit) + self.GameStateClass = DotsAndBoxesState + self.game_state = self.GameStateClass(nb_rows, nb_cols, player) + # self.controller = controller + + def register_action(self, row, column, orientation, player): + super(Agent, self).register_action(row, column, orientation, player) + # adjust agent specific board representation + move = (row, column, orientation) + self.game_state.play_move(move) + + def next_action(self): + r, c, o = self.controller.get_next_move(self.game_state, time_allowed=self.timelimit) + return r, c, o + + def end_game(self): + super(Agent, self).end_game() + + +# Adapted from provided code +def main(argv=None): + global agentclass + parser = argparse.ArgumentParser(description='Start agent to play Dots and Boxes') + parser.add_argument('--verbose', '-v', action='count', default=0, help='Verbose output') + parser.add_argument('--quiet', '-q', action='count', default=0, help='Quiet output') + parser.add_argument('port', metavar='PORT', type=int, help='Port to use for server') + args = parser.parse_args(argv) + print(args) + + logger.setLevel(max(logging.INFO - 10 * (args.verbose - args.quiet), logging.DEBUG)) + logger.addHandler(logging.StreamHandler(sys.stdout)) + + agentclass = Agent + dba.agentclass = Agent + dba.start_server(args.port) + + +if __name__ == "__main__": + sys.exit(main()) + diff --git a/python/agent_MCTS.py b/python/agent_MCTS.py new file mode 100644 index 0000000..b0072cf --- /dev/null +++ b/python/agent_MCTS.py @@ -0,0 +1,57 @@ +import dotsandboxes.dotsandboxesagent as dba + +import sys +import argparse +import logging +from GameState import GameState, DotsAndBoxesState +from MCTS import MCTSNode, MCTSGameController +import alphaBeta + + +logger = logging.getLogger(__name__) +games = {} +agentclass = dba + + +class Agent(dba.DotsAndBoxesAgent): + def __init__(self, player, nb_rows, nb_cols, timelimit): + super(Agent, self).__init__(player, nb_rows, nb_cols, timelimit) + self.GameStateClass = DotsAndBoxesState + self.game_state = self.GameStateClass(nb_rows, nb_cols, player) + self.controller = MCTSGameController() + + def register_action(self, row, column, orientation, player): + super(Agent, self).register_action(row, column, orientation, player) + # adjust agent specific board representation + move = (row, column, orientation) + self.game_state.play_move(move) + + def next_action(self): + r, c, o = self.controller.get_next_move(self.game_state, time_allowed=self.timelimit) + return r, c, o + + def end_game(self): + super(Agent, self).end_game() + + +# Adapted from provided code +def main(argv=None): + global agentclass + parser = argparse.ArgumentParser(description='Start agent to play Dots and Boxes') + parser.add_argument('--verbose', '-v', action='count', default=0, help='Verbose output') + parser.add_argument('--quiet', '-q', action='count', default=0, help='Quiet output') + parser.add_argument('port', metavar='PORT', type=int, help='Port to use for server') + args = parser.parse_args(argv) + print(args) + + logger.setLevel(max(logging.INFO - 10 * (args.verbose - args.quiet), logging.DEBUG)) + logger.addHandler(logging.StreamHandler(sys.stdout)) + + agentclass = Agent + dba.agentclass = Agent + dba.start_server(args.port) + + +if __name__ == "__main__": + sys.exit(main()) + diff --git a/python/alphaBeta.py b/python/alphaBeta.py index 01f82cf..31fa578 100644 --- a/python/alphaBeta.py +++ b/python/alphaBeta.py @@ -1,30 +1,99 @@ def alpha_beta(node, alpha, beta): - - # Based on https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning#Pseudocode - # node needs to support three operations: isTerminal(), value(), getChildren(), maximizingPlayer() - - if node.isTerminal(): - return node.value() - - if node.maximizingPlayer(): - - v = float("-inf") - for child in node.getChildren(): - - v = max(v, alpha_beta(child, alpha, beta)) - alpha = max(alpha, v) - if beta <= alpha: - break - - else: - - v = float("inf") - for child in node.getChildren(): - - v = min(v, alpha_beta(child, alpha, beta)) - beta = min(beta, v) - if beta <= alpha: - break - - return v + + # Based on https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning#Pseudocode + # node needs to support three operations: isTerminal(), value(), getChildren(), maximizingPlayer() + + if node.isTerminal(): + return node.value() + + if node.maximizingPlayer(): + + v = float("-inf") + for child in node.getChildren(): + + v = max(v, alpha_beta(child, alpha, beta)) + alpha = max(alpha, v) + if beta <= alpha: + break + + else: + + v = float("inf") + for child in node.getChildren(): + + v = min(v, alpha_beta(child, alpha, beta)) + beta = min(beta, v) + if beta <= alpha: + break + + return v + + +# A class for defining algorithms used (minimax and alpha-beta pruning) +class AlphaBeta: + + def miniMax(State, Ply_num): # Function for the minimax algorithm + + for i in range(State.Current.dimY): + for j in range(State.Current.dimX): + if State.Current.Mat[i][j] == ' ' and (j, i) not in State.children: + State.Make(j, i, True) + if Ply_num < 2: + return (i, j) + + Minimum_Score = 1000 + i = 0 + + j = 0 + for k, z in State.children.items(): + Result = Algo.Maximum(z, Ply_num - 1, Minimum_Score) + if Minimum_Score > Result: + Minimum_Score = Result + i = k[0] + j = k[1] + + return (i, j) + + # Alpha-beta pruning function for taking care of Alpha values + def Maximum(State, Ply_num, Alpha): + if Ply_num == 0: + return State.CurrentScore + + for i in range(State.Current.dimY): + for j in range(State.Current.dimX): + if State.Current.Mat[i][j] == ' ' and (j, i) not in State.children: + State.Make(j, i, False) + + Maximum_Score = -1000 + i = 0 + j = 0 + for k, z in State.children.items(): + Result = Algo.Minimum(z, Ply_num - 1, Maximum_Score) + if Maximum_Score < Result: + Maximum_Score = Result + if Result > Alpha: + return Result + + return Maximum_Score + + def Minimum(State, Ply_num, Beta): # Alpha-beta pruning function for taking care of Beta values + if Ply_num == 0: + return State.CurrentScore + + for i in range(State.Current.dimY): + for j in range(State.Current.dimX): + if State.Current.Mat[i][j] == ' ' and (j, i) not in State.children: + State.Make(j, i, True) + + Minimum_Score = 1000 + i = 0 + j = 0 + for k, z in State.children.items(): + Result = Algo.Maximum(z, Ply_num - 1, Minimum_Score) + if Minimum_Score > Result: + Minimum_Score = Result + if Result < Beta: + return Result + + return Minimum_Score diff --git a/python/dotsandboxes/dotsandboxesagent.py b/python/dotsandboxes/dotsandboxesagent.py index c8bc05e..9fe6cb8 100644 --- a/python/dotsandboxes/dotsandboxesagent.py +++ b/python/dotsandboxes/dotsandboxesagent.py @@ -15,8 +15,6 @@ import asyncio import websockets import json from collections import defaultdict -import random - logger = logging.getLogger(__name__) games = {} diff --git a/python/dotsandboxes/static/dotsandboxes.html b/python/dotsandboxes/static/dotsandboxes.html index ecbcbb4..4e97508 100644 --- a/python/dotsandboxes/static/dotsandboxes.html +++ b/python/dotsandboxes/static/dotsandboxes.html @@ -2,9 +2,6 @@ - - - Dots and Boxes @@ -45,9 +42,6 @@ - diff --git a/python/start.sh b/python/start.sh index 6be69a2..455944d 100755 --- a/python/start.sh +++ b/python/start.sh @@ -1,7 +1,10 @@ +#/bin/bash (cd dotsandboxes; python3 dotsandboxesserver.py 8080) & python3 agent.py 10001 & python3 agent.py 10002 & -read -p "Press enter to close all programs." + +echo "Press enter to close all programs" +read TRASH; trap "exit" INT TERM trap "kill 0" EXIT -- cgit v1.2.3