| 1 | """Focused tactical and protocol regressions; run directly with Python 3.""" |
| 2 | import contextlib |
| 3 | import io |
| 4 | from pathlib import Path |
| 5 | import sys |
| 6 | import unittest |
| 7 | |
| 8 | sys.path.insert(0, str(Path(__file__).resolve().parent)) |
| 9 | import bot |
| 10 | |
| 11 | |
| 12 | class BrainTests(unittest.TestCase): |
| 13 | def setUp(self): |
| 14 | bot.N = 15 |
| 15 | bot.board.clear() |
| 16 | |
| 17 | def stones(self, points, colour=1): |
| 18 | bot.board.update((p, colour) for p in points) |
| 19 | |
| 20 | def test_first_move(self): |
| 21 | self.assertEqual(bot.move(), (7, 7)) |
| 22 | |
| 23 | def test_exact_five_in_every_direction(self): |
| 24 | for dx, dy in bot.DIRECTIONS: |
| 25 | bot.board.clear() |
| 26 | self.stones([(7 + i * dx, 7 + i * dy) for i in (-2, -1, 1, 2)]) |
| 27 | self.assertTrue(bot.evaluate((7, 7), 1)[0]) |
| 28 | self.assertEqual(bot.move(), (7, 7)) |
| 29 | |
| 30 | def test_overline_is_not_win(self): |
| 31 | self.stones([(x, 7) for x in (3, 4, 5, 7, 8)]) |
| 32 | self.assertFalse(bot.evaluate((6, 7), 1)[0]) |
| 33 | |
| 34 | def test_win_before_block(self): |
| 35 | self.stones([(x, 4) for x in range(4)], 1) |
| 36 | self.stones([(x, 10) for x in range(4)], 2) |
| 37 | self.assertEqual(bot.move(), (4, 4)) |
| 38 | |
| 39 | def test_block_opponent_broken_five(self): |
| 40 | self.stones([(x, 7) for x in (3, 4, 6, 7)], 2) |
| 41 | self.assertEqual(bot.move(), (5, 7)) |
| 42 | |
| 43 | def test_open_line_beats_closed(self): |
| 44 | self.stones([(6, 7), (8, 7)]) |
| 45 | open_score = bot.evaluate((7, 7), 1)[1] |
| 46 | self.stones([(5, 7)], 2) |
| 47 | self.assertGreater(open_score, bot.evaluate((7, 7), 1)[1]) |
| 48 | |
| 49 | def test_gap_four_has_winning_completion(self): |
| 50 | self.stones([(5, 7), (8, 7), (9, 7)]) |
| 51 | _, offsets, _ = bot.line_value(bot.line_at(6, 7, 1, 1, 0)) |
| 52 | self.assertIn(1, offsets) |
| 53 | |
| 54 | def test_open_four_has_two_winning_points(self): |
| 55 | self.stones([(5, 7), (6, 7), (8, 7)]) |
| 56 | _, offsets, _ = bot.line_value(bot.line_at(7, 7, 1, 1, 0)) |
| 57 | self.assertEqual(offsets, {-3, 2}) |
| 58 | |
| 59 | def test_edge_is_closed(self): |
| 60 | self.stones([(0, 7), (1, 7)]) |
| 61 | _, offsets, _ = bot.line_value(bot.line_at(2, 7, 1, 1, 0)) |
| 62 | self.assertFalse(offsets) |
| 63 | self.assertNotEqual(bot.line_at(2, 7, 1, 1, 0)[0], '.') |
| 64 | |
| 65 | def test_snapshot_restart_and_blocked_cells(self): |
| 66 | commands = 'START 15\nBEGIN\nBOARD\n0,0,3\n1,0,2\nDONE\nRESTART\nBEGIN\nEND\n' |
| 67 | out = io.StringIO() |
| 68 | old_stdin = sys.stdin |
| 69 | try: |
| 70 | sys.stdin = io.StringIO(commands) |
| 71 | with contextlib.redirect_stdout(out): |
| 72 | bot.main() |
| 73 | finally: |
| 74 | sys.stdin = old_stdin |
| 75 | lines = out.getvalue().splitlines() |
| 76 | self.assertEqual(lines[0:2], ['OK', '7,7']) |
| 77 | self.assertNotIn(lines[2], ['0,0', '1,0']) |
| 78 | self.assertEqual(lines[3:], ['OK', '7,7']) |
| 79 | self.assertEqual(bot.board, {(7, 7): 1}) |
| 80 | |
| 81 | def test_board_replaces_previous_position(self): |
| 82 | self.stones([(14, 14)], 2) |
| 83 | old_stdin = sys.stdin |
| 84 | try: |
| 85 | sys.stdin = io.StringIO('BOARD\n0,0,3\n1,0,2\nDONE\nEND\n') |
| 86 | with contextlib.redirect_stdout(io.StringIO()): |
| 87 | bot.main() |
| 88 | finally: |
| 89 | sys.stdin = old_stdin |
| 90 | self.assertNotIn((14, 14), bot.board) |
| 91 | self.assertEqual(bot.board[(0, 0)], 3) |
| 92 | self.assertEqual(bot.board[(1, 0)], 2) |
| 93 | self.assertEqual(len(bot.board), 3) |
| 94 | |
| 95 | |
| 96 | if __name__ == '__main__': |
| 97 | unittest.main() |