Skip to content

Instantly share code, notes, and snippets.

@particledecay
Last active May 5, 2016 14:33
Show Gist options
  • Select an option

  • Save particledecay/6001d7ded8af9c336a769bc6f638dc96 to your computer and use it in GitHub Desktop.

Select an option

Save particledecay/6001d7ded8af9c336a769bc6f638dc96 to your computer and use it in GitHub Desktop.
Very simple (and incomplete) implementation of Go in Python
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