def testDescribeMove(self): domino1 = Domino(1, 2) dx, dy = 1, 0 expected_move = '12r' move = domino1.describe_move(dx, dy) self.assertEqual(expected_move, move)
def testEqualFlipped(self): domino1 = Domino(5, 3) domino2 = Domino(3, 5) eq_result = domino1 == domino2 neq_result = domino1 != domino2 self.assertTrue(eq_result) self.assertFalse(neq_result)
def testRotateFullCircle(self): domino1 = Domino(1, 5) domino1.rotate(180) domino1.rotate(180) self.assertEqual(0, domino1.degrees)
def testDescribeMoveUpReversed(self): domino1 = Domino(1, 2) domino1.rotate(90) dx, dy = 0, 1 expected_move = '21u' move = domino1.describe_move(dx, dy) self.assertEqual(expected_move, move)
def testHashFlipped(self): domino1 = Domino(5, 3) domino2 = Domino(3, 5) hash1 = hash(domino1) hash2 = hash(domino2) self.assertEqual(hash1, hash2)
def testIsMatch(self): domino1 = Domino(0, 1) self.assertFalse(domino1.isMatch(Domino(2, 2))) self.assertTrue(domino1.isMatch(Domino(0, 2))) self.assertTrue(domino1.isMatch(Domino(2, 1))) self.assertTrue(domino1.isMatch(Domino(2, 0))) self.assertTrue(domino1.isMatch(Domino(1, 2)))
def testDescribeMoveReversed(self): domino1 = Domino(1, 2) domino1.rotate(180) dx, dy = 1, 0 expected_move = '21r' move = domino1.describe_move(dx, dy) self.assertEqual(expected_move, move)
def testRemoveAndRotate(self): board = Board(3, 4) domino1 = Domino(1, 5) board.add(domino1, 0, 0) board.remove(domino1) domino1.rotate(270) self.assertEqual(270, domino1.degrees)
def testDifferentPips(self): domino1 = Domino(5, 3) domino2 = Domino(5, 4) domino3 = Domino(6, 3) eq_result = domino1 == domino2 neq_result = domino1 != domino2 self.assertFalse(eq_result) self.assertTrue(neq_result) self.assertNotEqual(domino1, domino3)
def testFillWithBacktrack(self, mock_choose): """ Force a backtrack. This scenario will get to the following grid and then be forced to backtrack, because the gaps are size 1 and 3: odd. x 3 x x - 0 0 x 2 - - 0 0|1 0 """ mock_choose.side_effect = [[Domino(0, 0)], [Domino(0, 1)], [Domino(0, 2)], [Domino(0, 3)], [Domino(0, 3)], [Domino(0, 3)], [Domino(0, 3)], [Domino(0, 4)], [Domino(0, 5)]] dummy_random = DummyRandom(randints={(0, 3): [1, 0, 1, 1]}) # directions board = Board(4, 3, max_pips=6) expected_display = """\ 0|4 0|5 0 0|3 2 - - 0 0|1 0 """ board.fill(dummy_random) display = board.display() self.assertMultiLineEqual(expected_display, display)
def testFlip(self): board = Board(3, 2, max_pips=6) domino1 = Domino(1, 5) expected_display = """\ x x x 5|1 x """ board.add(domino1, 0, 0) domino1.flip() self.assertMultiLineEqual(expected_display, board.display())
def testFillWithRandomDomino(self, mock_choose): mock_choose.side_effect = [[Domino(0, 5)], [Domino(0, 2)]] dummy_random = DummyRandom(randints={(0, 3): [1, 1]}) # directions board = Board(2, 2, max_pips=6) expected_display = """\ 5 2 - - 0 0 """ board.fill(dummy_random) display = board.display() self.assertMultiLineEqual(expected_display, display)
def testFillWithNoMatchesNext(self, mock_choose): mock_choose.side_effect = [[Domino(0, 5)], [Domino(0, 0), Domino(0, 1)]] dummy_random = DummyRandom(randints={(0, 3): [1, 1]}) # directions board = Board(2, 2, max_pips=6) expected_display = """\ 5 0 - - 0 1 """ board.fill(dummy_random, matches_allowed=False) display = board.display() self.assertMultiLineEqual(expected_display, display)
def testAddDomino(self): board = Board(4, 3) board.add(Domino(5, 6), 1, 2) pips = board[1][2].pips self.assertEqual(5, pips)
def testRotateAndAdd(self): board = Board(4, 3) domino1 = Domino(5, 6) domino1.rotate(-90) board.add(domino1, 1, 2) expected_display = """\ x 5 x x - x 6 x x x x x x """ display = board.display() self.assertMultiLineEqual(expected_display, display)
def test_create(self): state = """\ 0 1|2 - 1 3|4 === 4|5 5|6 """ expected_queue = [Domino(4, 5), Domino(5, 6)] board = QueuedBoard.create(state) self.assertEqual(1, board[0][0].pips) self.assertEqual(2, board[2][1].pips) self.assertEqual(expected_queue, board.queue)
def testMoveLeft(self): board = Board(4, 3) domino1 = Domino(5, 6) board.add(domino1, 1, 2) domino1.move(-1, 0) expected_display = """\ 5|6 x x x x x x x x x x """ display = board.display() self.assertMultiLineEqual(expected_display, display)
def testExtraDominoes(self): state = """\ 0|0 x 1|1 x """ max_pips = 2 expected_extra_dominoes = [ Domino(0, 1), Domino(0, 2), Domino(1, 2), Domino(2, 2) ] board = Board.create(state, max_pips=max_pips) self.assertEqual(expected_extra_dominoes, board.extra_dominoes)
def test_get_from_queue(self): state = """\ 0 1|2 - 1 2|0 === 0|0 1|1 """ board = QueuedBoard.create(state) expected_from_queue = Domino(0, 0) expected_queue = [Domino(1, 1)] from_queue = board.get_from_queue() self.assertEqual(expected_from_queue, from_queue) self.assertEqual(expected_queue, board.queue)
def testRemove(self): board = Board(3, 4) domino1 = Domino(1, 5) board.add(domino1, 0, 0) board.remove(domino1) self.assertEqual([], board.dominoes)
def testCreate(self): expected_dominoes = [Domino(0, 0), Domino(0, 1), Domino(0, 2), Domino(1, 1), Domino(1, 2), Domino(2, 2)] dominoes = Domino.create(2) self.assertEqual(expected_dominoes, dominoes)
def create(cls, state, border=0, max_pips=None): board_state, *other_states = state.split('===\n') board = super().create(board_state, border, max_pips) if other_states: queue_state, = other_states for line in queue_state.splitlines(): head = int(line[0]) tail = int(line[-1]) board.add_to_queue(Domino(head, tail)) return board
def testCreate(self): expected_dominoes = [ Domino(0, 0), Domino(0, 1), Domino(0, 2), Domino(1, 1), Domino(1, 2), Domino(2, 2) ] dominoes = Domino.create(2) self.assertEqual(expected_dominoes, dominoes)
def test_extra_dominoes(self): state = """\ 0 1|2 - 1 2|0 === 0|0 1|1 """ expected_extras = [Domino(2, 2)] board = QueuedBoard.create(state, max_pips=2) self.assertEqual(expected_extras, board.extra_dominoes)
def testDisplay(self): board = Board(4, 3) board.add(Domino(5, 6), 1, 2) expected_display = """\ x 5|6 x x x x x x x x x """ display = board.display() self.assertMultiLineEqual(expected_display, display)
def testRotateNegative(self): domino1 = Domino(1, 5) domino1.rotate(-90) self.assertEqual(270, domino1.degrees)
def testOccupied(self): board = Board(4, 3) board.add(Domino(2, 3), 1, 0) with self.assertRaisesRegex(BoardError, 'Position 1, 0 is occupied.'): board.add(Domino(1, 2), 0, 0)
def testInit(self): domino1 = Domino(5, 3) pips = domino1.head.pips self.assertEqual(5, pips)
def testRepr(self): domino1 = Domino(5, 3) s = repr(domino1) self.assertEqual("Domino(5, 3)", s)
def testRotateWithoutBoard(self): domino1 = Domino(5, 6) domino1.rotate(90) self.assertEqual(90, domino1.degrees)
def testGetDirection(self): dx, dy = Domino.get_direction('l') self.assertEqual((-1, 0), (dx, dy))
def testName(self): domino = Domino(1, 2) name = domino.get_name() self.assertEqual("12", name)
def testOffBoard(self): board = Board(4, 3) with self.assertRaisesRegex(BoardError, 'Position 4, 0 is off the board.'): board.add(Domino(1, 2), 3, 0)
def draw_diagram(turtle, state, cell_size, solution=False): marks = {'>': partial(draw_arrow, turtle, cell_size), '^': partial(draw_arrow, turtle, cell_size, 90), '<': partial(draw_arrow, turtle, cell_size, 180), 'v': partial(draw_arrow, turtle, cell_size, 270), '*': partial(draw_capture, turtle, cell_size)} pos = turtle.pos() lines = state.splitlines() turtle.up() turtle.forward(cell_size*0.5) turtle.right(90) turtle.forward(cell_size*len(lines)*0.5) turtle.left(90) origin = turtle.pos() board = Board.create(state) draw_board(turtle, board, cell_size) turtle.up() for y, line in enumerate(reversed(lines)): for x, c in enumerate(line): if (x+y) % 2: mark = marks.get(c) if mark is not None: mark() turtle.up() turtle.forward(cell_size*.5) turtle.back(cell_size*len(line)*.5) turtle.left(90) turtle.forward(cell_size*.5) turtle.right(90) turtle.setpos(pos) if solution: border = 1 offset = [border, border] board = Board.create(state, border=border) graph = CaptureBoardGraph() graph.walk(board) solution = graph.get_solution() for move_num, move in enumerate(solution, 1): domino_name = move[:2] for domino in board.dominoes: if domino.get_name() == domino_name: shade = (move_num-1) * 1.0/(len(solution)-1) rgb = (0, 1-shade, shade) turtle.setpos(origin) turtle.forward((domino.head.x-offset[0]) * cell_size) turtle.left(90) turtle.forward((domino.head.y-offset[1]) * cell_size) turtle.right(90) turtle.setheading(domino.degrees) turtle.forward(cell_size*.5) dx, dy = Domino.get_direction(move[-1]) turtle.setheading(math.atan2(dy, dx) * 180/math.pi) pen = turtle.pen() turtle.pencolor(rgb) circle_pos = turtle.pos() turtle.width(4) turtle.forward(cell_size*0.05) turtle.down() turtle.forward(cell_size*0.4) turtle.up() turtle.pen(pen) turtle.setpos(circle_pos) turtle.forward(8) turtle.setheading(0) turtle.right(90) turtle.forward(8) turtle.left(90) turtle.down() turtle.down() turtle.pencolor(rgb) turtle.fillcolor('white') turtle.begin_fill() turtle.circle(8) turtle.end_fill() turtle.pen(pen) turtle.write(move_num, align='center') turtle.up() state = graph.move(domino, dx, dy, offset) offset[0] += border offset[1] += border board = Board.create(state, border=border) break turtle.setpos(pos)
def draw_diagram(turtle, state, cell_size, solution=False): marks = {'>': partial(draw_arrow, turtle, cell_size), '^': partial(draw_arrow, turtle, cell_size, 90), '<': partial(draw_arrow, turtle, cell_size, 180), 'v': partial(draw_arrow, turtle, cell_size, 270), '*': partial(draw_capture, turtle, cell_size)} pos = turtle.pos() lines = state.splitlines() turtle.up() turtle.forward(cell_size*0.5) turtle.right(90) turtle.forward(cell_size*len(lines)*0.5) turtle.left(90) origin = turtle.pos() board = Board.create(state) draw_board(turtle, board, cell_size) turtle.up() for y, line in enumerate(reversed(lines)): for x, c in enumerate(line): if (x+y) % 2: mark = marks.get(c) if mark is not None: mark() turtle.up() turtle.forward(cell_size*.5) turtle.back(cell_size*len(line)*.5) turtle.left(90) turtle.forward(cell_size*.5) turtle.right(90) turtle.setpos(pos) if solution: border = 1 offset = [border, border] board = Board.create(state, border=border) for cell in board.findMatches(): turtle.setpos(origin) draw_match(turtle, cell_size, offset, cell) graph = CaptureBoardGraph() graph.walk(board) solution = graph.get_solution(partial=True) step_count = max(len(solution)-1, 1) for move_num, move in enumerate(solution, 1): domino_name = move[:2] for domino in board.dominoes: if domino.get_name() == domino_name: dx, dy = Domino.get_direction(move[-1]) turtle.setpos(origin) draw_move(turtle, cell_size, offset, domino, dx, dy, move_num, step_count) old_offset = offset[:] state = graph.move(domino, dx, dy, offset) new_board = Board.create(state, border=border) captures = set(board.dominoes) captures.difference_update(new_board.dominoes) captures.discard(domino) for capture in captures: turtle.setpos(origin) draw_capture_circle(turtle, cell_size, old_offset, capture, move_num) offset[0] += border offset[1] += border board = new_board break # Mark uncaptured dominoes for domino in board.dominoes: turtle.setpos(origin) draw_capture_circle(turtle, cell_size, offset, domino) turtle.setpos(pos)