aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--python/MCTS.py6
-rw-r--r--python/agent_AB.py57
-rw-r--r--python/agent_MCTS.py (renamed from python/agent.py)4
-rw-r--r--python/alphaBeta.py125
-rw-r--r--python/dotsandboxes/dotsandboxesagent.py2
-rw-r--r--python/dotsandboxes/static/dotsandboxes.html6
-rwxr-xr-xpython/start.sh5
7 files changed, 164 insertions, 41 deletions
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_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.py b/python/agent_MCTS.py
index 49bc1cc..b0072cf 100644
--- a/python/agent.py
+++ b/python/agent_MCTS.py
@@ -5,11 +5,12 @@ import argparse
import logging
from GameState import GameState, DotsAndBoxesState
from MCTS import MCTSNode, MCTSGameController
+import alphaBeta
logger = logging.getLogger(__name__)
games = {}
-agentclass = None
+agentclass = dba
class Agent(dba.DotsAndBoxesAgent):
@@ -41,6 +42,7 @@ def main(argv=None):
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))
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 @@
<html>
<html lang="en">
<meta charset="utf-8">
-<meta name="author" content="Wannes Meert">
-<meta name="description" content="Dots-and-Boxes game. Part of the Machine Learning: Project course at KU Leuven (Hendrik Blockeel, Wannes Meert).">
-<meta name="keywords" content="artificial intelligence,AI,machine learning,dots and boxes,KU Leuven">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Dots and Boxes</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
@@ -45,9 +42,6 @@
</div>
</div>
</div>
- <div class="footer">
- <small>&copy; <a href="https://dtai.cs.kuleuven.be">DTAI Research Group</a>, KU Leuven &mdash; <a href="https://github.com/wannesm/dotsandboxes">Source</a></small>
- </div>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="dotsandboxes.js"></script>
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