From d311af01feb32550aaae8638d4cc167948f5464c Mon Sep 17 00:00:00 2001 From: Matt Strapp Date: Mon, 26 Apr 2021 10:53:43 -0500 Subject: Rebase newer branch --- python/board.py | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 python/board.py (limited to 'python/board.py') diff --git a/python/board.py b/python/board.py new file mode 100644 index 0000000..36cfe8c --- /dev/null +++ b/python/board.py @@ -0,0 +1,110 @@ +from GameState import GameState + +class Board(GameState): + + # Interface methods + + def __init__(self, nb_rows, nb_cols, player): + + # Basic initialization + self.nb_rows = nb_rows + self.nb_cols = nb_cols + self.player = player # 1 or 2 + self.scores = [0, 0, 0] + self.max_score = nb_rows*nb_cols + + # Construct edges and nodes matrix + self.edges = [] # Boolean, true means uncut + self.nodes = [] # Represents valence of nodes from strings-and-coins + for x in range(self.nb_cols): + self.edges.append([True]*self.nb_rows) + self.edges.append([True]*(self.nb_rows + 1)) + self.nodes.append([4]*self.nb_rows) + self.edges.append([True]*self.nb_rows) + + # Construct all possible moves + self.moves_left = set() # Moves are represented as ints + for x in range(len(self.edges)): + for y in range(len(self.edges[x])): + self.moves_left.add(self.coords_to_edge(x, y)) + + # TODO: chain updating + # Initialize chains + # Chains are represented as lists of nodes + self.closed_chains = [] # Chains which start and end in nodes of valence + + @property + def game_result(self): + + own_score = self.scores[self.player] + opponent_score = self.scores[self.player % 2 + 1] + if len(self.moves_left) == 0: + diff = own_score - opponent_score + if diff > 0: + return 1 + elif diff < 0: + return 0 + else: + return 0.5 + else: + # Check if one player already has at least half of all points + if own_score > self.max_score//2: + return 1 + elif opponent_score > self.max_score//2: + return 0 + else: + return None + + def get_moves(self): + return self.moves_left + + def get_random_move(self): + moves = self.get_moves() + return choice(tuple(moves)) if moves != set() else None + + def play_move(self, move): + x, y = self.edge_to_coords(move) + self.edges[x][y] = False + self.moves_left.remove(move) + + # Update valence + if x%2 == 0: + # Horizontal edge, decrease valence of left and right nodes + for node_x in x//2 - 1, x//2: + if node_x >= 0 and node_x < nb_cols: + self.nodes[node_x][y] -= 1 + else: + # Vertical edge, decrease valence of top and bottom nodes + for node_y in y - 1, y: + if node_y >= 0 and node_y < nb_rows: + self.nodes[x//2][node_y] -= 1 + + # TODO: chain updating + + # Own methods + + def undo_move(self, move): + x, y = self.edge_to_coords(move) + self.edges[x][y] = True + self.moves_left.add(move) + + # Update valence + if x%2 == 0: + # Horizontal edge, decrease valence of left and right nodes + for node_x in x//2 - 1, x//2: + if node_x >= 0 and node_x < nb_cols: + self.nodes[node_x][y] += 1 + else: + # Vertical edge, decrease valence of top and bottom nodes + for node_y in y - 1, y: + if node_y >= 0 and node_y < nb_rows: + self.nodes[x//2][node_y] += 1 + + # TODO: chain updating + + def coords_to_edge(self, x, y): + return x*(self.nb_cols + 1) + y + + def edge_to_coords(self, move): + return move//(self.nb_cols + 1), move%(self.nb_cols + 1) + -- cgit v1.2.3