Last active
May 5, 2016 14:33
-
-
Save particledecay/6001d7ded8af9c336a769bc6f638dc96 to your computer and use it in GitHub Desktop.
Very simple (and incomplete) implementation of Go in Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import sys | |
| import unittest | |
| from StringIO import StringIO | |
| EMPTY = 0 | |
| BLACK = 1 | |
| WHITE = 2 | |
| class Board: | |
| def __init__(self): | |
| self._max_size = 19 # helps to create coordinate bounds | |
| self.board = [[EMPTY] * self._max_size for _ in xrange(self._max_size)] | |
| self._PLAYERS = { | |
| BLACK: {'name': 'BLACK', 'score': 0}, | |
| WHITE: {'name': 'WHITE', 'score': 0} | |
| } | |
| def __str__(self): | |
| s = '' | |
| for row in self.board: | |
| if s: | |
| s += '\n' | |
| for sq in row: | |
| if sq: | |
| s += str(sq) | |
| else: | |
| s += '_' | |
| def move(self, color, row, col): | |
| self.board[row][col] = color | |
| # check for capture | |
| captures = set() | |
| for r, c in self._get_opp_neighbors(row, col): | |
| captured_chain = True | |
| chain = self._get_chain(r, c) | |
| for x, y in chain: | |
| if self._has_liberties(x, y): | |
| captured_chain = False | |
| break | |
| if captured_chain: | |
| [captures.add(piece) for piece in chain] | |
| # if captured, announce | |
| if len(captures) > 0: | |
| print "{} has captured the following pieces:".format(self._PLAYERS[color]['name']), | |
| print ", ".join([repr(piece) for piece in captures]) | |
| # reset those spaces and adjust score | |
| for x, y in captures: | |
| self.board[x][y] = EMPTY | |
| self._PLAYERS[color]['score'] += 1 | |
| def _get_adj_coords(self, row, col): | |
| """Find the adjacent coordinates to a space within the board. | |
| Args: | |
| row (int): The number of the row on the board | |
| col (int): The number of the column on the board | |
| Returns: | |
| (list) The coordinates, each as a tuple | |
| """ | |
| coords_list = [(row - 1, col), (row + 1, col), | |
| (row, col - 1), (row, col + 1)] | |
| valid_coords = [] | |
| for coords in coords_list: | |
| if -1 < coords[0] < self._max_size and -1 < coords[1] < self._max_size: | |
| valid_coords.append(coords) | |
| return valid_coords | |
| def _has_liberties(self, row, col): | |
| for coords in self._get_adj_coords(row, col): | |
| if not self.board[coords[0]][coords[1]]: | |
| return True | |
| return False | |
| def _get_color(self, row, col): | |
| if not self.board[row][col]: | |
| return EMPTY | |
| return BLACK if self.board[row][col] == BLACK else WHITE | |
| def _get_chain(self, row, col, members=None): | |
| color = self._get_color(row, col) | |
| members = members or {(row, col)} | |
| for coords in self._get_adj_coords(row, col): | |
| if coords not in members and self.board[coords[0]][coords[1]] == color: | |
| members.add(coords) | |
| for mem in self._get_chain(coords[0], coords[1], members): | |
| members.add(mem) | |
| return members | |
| def _get_opp_neighbors(self, row, col): | |
| neighbors = set() | |
| color = self._get_color(row, col) | |
| if not color: | |
| return neighbors | |
| opp_color = BLACK if color == WHITE else WHITE | |
| for coords in self._get_adj_coords(row, col): | |
| if self.board[coords[0]][coords[1]] == opp_color: | |
| neighbors.add(coords) | |
| return neighbors | |
| class BoardTests(unittest.TestCase): | |
| def setUp(self): | |
| self._b = Board() | |
| # we printed announcement to stdout, so need to capture | |
| self._out = StringIO() | |
| sys.stdout = self._out | |
| def tearDown(self): | |
| sys.stdout = sys.__stdout__ # restore stdout | |
| def test_given_capture(self): | |
| """Should announce a capture after performing provided moves.""" | |
| white_score = self._b._PLAYERS[WHITE]['score'] | |
| # make the moves | |
| self._b.move(BLACK, 4, 4) | |
| self._b.move(BLACK, 4, 5) | |
| self._b.move(WHITE, 3, 4) | |
| self._b.move(WHITE, 3, 5) | |
| self._b.move(WHITE, 4, 3) | |
| self._b.move(WHITE, 4, 6) | |
| self._b.move(WHITE, 5, 4) | |
| self._b.move(WHITE, 5, 5) | |
| output = self._out.getvalue().strip() | |
| self.assertEqual(output, "WHITE has captured the following pieces: (4, 5), (4, 4)") | |
| self.assertEqual(white_score, self._b._PLAYERS[WHITE]['score'] - 2) | |
| def test_corner_capture(self): | |
| """Should capture a piece in the corner.""" | |
| black_score = self._b._PLAYERS[BLACK]['score'] | |
| # make the moves | |
| self._b.move(WHITE, 18, 18) | |
| self._b.move(BLACK, 18, 17) | |
| self._b.move(BLACK, 17, 18) | |
| output = self._out.getvalue().strip() | |
| self.assertEqual(output, "BLACK has captured the following pieces: (18, 18)") | |
| self.assertEqual(black_score, self._b._PLAYERS[BLACK]['score'] - 1) | |
| if __name__ == "__main__": | |
| unittest.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment