def make_step(self): new_lattice = Lattice(self.size) for x in range(self.size): for y in range(self.size): if self._should_become_live(x, y): new_lattice.make_live(x, y) self._lattice = new_lattice
class Game: def __init__(self, size): self._lattice = Lattice(size) @staticmethod def from_string(str, dead_symbol=' ', live_symbol='x'): lattice = Lattice.from_string(str, dead_symbol, live_symbol) game = Game(lattice.size) game._lattice = lattice return game @property def size(self): return self._lattice.size def make_step(self): new_lattice = Lattice(self.size) for x in range(self.size): for y in range(self.size): if self._should_become_live(x, y): new_lattice.make_live(x, y) self._lattice = new_lattice def _should_become_live(self, x, y): num_of_live_neighbours = self._lattice.get_num_of_live_neighbours(x, y) if self._lattice.is_live(x, y) and num_of_live_neighbours < 2: return False elif self._lattice.is_live(x, y) and 2 <= num_of_live_neighbours <= 3: return True elif self._lattice.is_live(x, y) and num_of_live_neighbours > 3: return False elif self._lattice.is_dead(x, y) and num_of_live_neighbours == 3: return True return False def __eq__(self, other): return self._lattice == other._lattice def __ne__(self, other): return self._lattice != other._lattice def __repr__(self): return repr(self._lattice) def __getattr__(self, name): try: return getattr(self._lattice, name) except AttributeError as e: raise AttributeError(str(e).replace('Lattice', 'Game', 1)) from e
def test_creation_of_symmetrical_lattice_from_valid_string(self): lattice = Lattice.from_string("x x\n" " x \n" "x x\n") self.assertEqual(lattice.size, 3) self.assertTrue(lattice.is_live(0, 0)) self.assertTrue(lattice.is_dead(0, 1)) self.assertTrue(lattice.is_live(0, 2)) self.assertTrue(lattice.is_dead(1, 0)) self.assertTrue(lattice.is_live(1, 1)) self.assertTrue(lattice.is_dead(1, 2)) self.assertTrue(lattice.is_live(2, 0)) self.assertTrue(lattice.is_dead(2, 1)) self.assertTrue(lattice.is_live(2, 2))
def test_creation_fails_on_columns_count_mismatch(self): with self.assertRaises(InvalidSizeError) as cm: Lattice.from_string("x_x\n" "xxx\n" "xx\n", dead_symbol="_")
def test_creation_fails_when_string_is_empty(self): with self.assertRaises(InvalidSizeError) as cm: Lattice.from_string("")
def test_creation_fails_on_rows_count_mismatch(self): with self.assertRaises(InvalidSizeError) as cm: Lattice.from_string("x x\n")
def test_creation_of_lattice_from_game1_succeeds(self): lattice1 = Lattice.from_string(" \n" " \n" " xxx \n" " \n" " \n") self.assertEqual(lattice1.size, 5)
def test_creation_fails_when_string_contains_invalid_symbol(self): with self.assertRaises(InvalidSymbolError) as cm: Lattice.from_string("q\n") self.assertRegex(str(cm.exception), r"^.*q.*$") self.assertRegex(str(cm.exception), r"^.*0.*0.*$")
def from_string(str, dead_symbol=' ', live_symbol='x'): lattice = Lattice.from_string(str, dead_symbol, live_symbol) game = Game(lattice.size) game._lattice = lattice return game
def test_two_lattices_with_different_sizes_are_not_equal(self): lattice1 = Lattice.from_string("x x\n" "xxx\n" " x \n") lattice2 = Lattice.from_string("x \n" " x\n") self.assertNotEqual(lattice1, lattice2) self.assertFalse(lattice1 == lattice2)
class LatticeLivenessTests(unittest.TestCase): def setUp(self): self.lattice = Lattice(4) def test_cells_are_dead_by_default(self): for x in range(self.lattice.size): for y in range(self.lattice.size): self.assertTrue(self.lattice.is_dead(x, y), "x = {}, y = {}".format(x, y)) def test_cell_is_live_after_make_live(self): self.lattice.make_live(2, 3) self.assertTrue(self.lattice.is_live(2, 3)) def test_cell_is_dead_after_making_live_cell_dead(self): self.lattice.make_live(2, 3) self.lattice.make_dead(2, 3) self.assertTrue(self.lattice.is_dead(2, 3)) def test_dead_cell_becomes_live_after_toggle(self): self.lattice.make_dead(1, 2) self.lattice.toggle_liveness(1, 2) self.assertTrue(self.lattice.is_live(1, 2)) def test_live_cell_becomes_dead_after_toggle(self): self.lattice.make_live(1, 2) self.lattice.toggle_liveness(1, 2) self.assertTrue(self.lattice.is_dead(1, 2))
def test_repr_returns_correct_result(self): lattice = Lattice.from_string("x x\n" "xxx\n" " x \n") lattice_str = repr(lattice) self.assertEqual(lattice, Lattice.from_string(lattice_str))
def test_size_cannot_be_changed_after_creation(self): lattice = Lattice(4) with self.assertRaises(AttributeError): lattice.size = 5
def test_out_of_bounds_error_is_raised_on_invalid_position(self): lattice = Lattice.from_string("x") with self.assertRaises(OutOfBoundsError): lattice.get_num_of_live_neighbours(1, 1)
def test_no_neighbours(self): lattice = Lattice.from_string("x") self.assertEqual(lattice.get_num_of_live_neighbours(0, 0), 0)
def test_all_neighbours_are_live(self): lattice = Lattice.from_string("xxx\n" "xxx\n" "xxx\n") self.assertEqual(lattice.get_num_of_live_neighbours(1, 1), 8)
def test_no_live_neighbour(self): lattice = Lattice.from_string(" \n" " x \n" " \n") self.assertEqual(lattice.get_num_of_live_neighbours(1, 1), 0)
def setUp(self): self.lattice = Lattice(4)
def test_creation_of_asymmetrical_lattice_from_string(self): lattice = Lattice.from_string("xx\n" " \n") self.assertTrue(lattice.is_live(0, 0)) self.assertTrue(lattice.is_live(0, 1)) self.assertTrue(lattice.is_dead(1, 0)) self.assertTrue(lattice.is_dead(1, 1))
def __init__(self, size): self._lattice = Lattice(size)
def test_creation_of_single_cell_lattice_succeeds(self): lattice = Lattice.from_string("x") self.assertTrue(lattice.is_live(0, 0))
def test_creation_of_lattice_with_trailing_new_lines_succeeds(self): lattice1 = Lattice.from_string("x x\n" "\n" "\n") lattice2 = Lattice.from_string("x x\n" " \n" " \n") self.assertEqual(lattice1, lattice2)
def test_two_lattices_with_same_data_are_equal(self): lattice1 = Lattice.from_string("x x\n" "xxx\n" " x \n") lattice2 = Lattice.from_string("x x\n" "xxx\n" " x \n") self.assertEqual(lattice1, lattice2) self.assertFalse(lattice1 != lattice2)