Skip to content

Commit b2bc11e

Browse files
committed
connect: Implement the exercise "connect"
1 parent e4f4fd8 commit b2bc11e

File tree

5 files changed

+230
-0
lines changed

5 files changed

+230
-0
lines changed

config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,17 @@
813813
"text formatting"
814814
]
815815
},
816+
{
817+
"uuid": "f5503274-ac23-11e7-abc4-cec278b6b50a",
818+
"slug": "connect",
819+
"core": false,
820+
"unlocked_by": null,
821+
"difficulty": 1,
822+
"topics": [
823+
"parsing",
824+
"transforming"
825+
]
826+
},
816827
{
817828
"uuid": "33f689ee-1d9c-4908-a71c-f84bff3510df",
818829
"slug": "collatz-conjecture",

exercises/connect/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Connect
2+
3+
Compute the result for a game of Hex / Polygon.
4+
5+
The abstract boardgame known as
6+
[Hex](https://en.wikipedia.org/wiki/Hex_%28board_game%29) / Polygon /
7+
CON-TAC-TIX is quite simple in rules, though complex in practice. Two players
8+
place stones on a rhombus with hexagonal fields. The player to connect his/her
9+
stones to the opposite side first wins. The four sides of the rhombus are
10+
divided between the two players (i.e. one player gets assigned a side and the
11+
side directly opposite it and the other player gets assigned the two other
12+
sides).
13+
14+
Your goal is to build a program that given a simple representation of a board
15+
computes the winner (or lack thereof). Note that all games need not be "fair".
16+
(For example, players may have mismatched piece counts.)
17+
18+
The boards look like this (with spaces added for readability, which won't be in
19+
the representation passed to your code):
20+
21+
```
22+
. O . X .
23+
. X X O .
24+
O O O X .
25+
. X O X O
26+
X O O O X
27+
```
28+
29+
"Player `O`" plays from top to bottom, "Player `X`" plays from left to right. In
30+
the above example `O` has made a connection from left to right but nobody has
31+
won since `O` didn't connect top and bottom.
32+
33+
### Submitting Exercises
34+
35+
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
36+
37+
For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
38+
39+
40+
For more detailed information about running tests, code style and linting,
41+
please see the [help page](http://exercism.io/languages/python).
42+
43+
## Submitting Incomplete Solutions
44+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

exercises/connect/connect.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
class ConnectGame:
3+
def __init__(self, board):
4+
pass

exercises/connect/connect_test.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import unittest
2+
import connect
3+
4+
testcases = [
5+
{
6+
"description": "an empty board has no winner",
7+
"board":
8+
""" . . . . .
9+
. . . . .
10+
. . . . .
11+
. . . . .
12+
. . . . .""",
13+
"winner": ""
14+
},
15+
{
16+
"description": "O can win on a 1x1 board",
17+
"board": "O",
18+
"winner": "O"
19+
},
20+
{
21+
"description": "X can win on a 1x1 board",
22+
"board": "X",
23+
"winner": "X"
24+
},
25+
{
26+
"description": "only edges does not make a winner",
27+
"board":
28+
""" O O O X
29+
X . . X
30+
X . . X
31+
X O O O""",
32+
"winner": ""
33+
},
34+
{
35+
"description": "illegal diagonal does not make a winner",
36+
"board":
37+
""" X O . .
38+
O X X X
39+
O X O .
40+
. O X .
41+
X X O O""",
42+
"winner": ""
43+
},
44+
{
45+
"description": "nobody wins crossing adjacent angles",
46+
"board":
47+
""" X . . .
48+
. X O .
49+
O . X O
50+
. O . X
51+
. . O .""",
52+
"winner": ""
53+
},
54+
{
55+
"description": "X wins crossing from left to right",
56+
"board":
57+
""" . O . .
58+
O X X X
59+
O X O .
60+
X X O X
61+
. O X .""",
62+
"winner": "X"
63+
},
64+
{
65+
"description": "X wins using a convoluted path",
66+
"board":
67+
""" . X X . .
68+
X . X . X
69+
. X . X .
70+
. X X . .
71+
O O O O O""",
72+
"winner": "X"
73+
},
74+
{
75+
"description": "O wins crossing from top to bottom",
76+
"board":
77+
""" . O . .
78+
O X X X
79+
O O O .
80+
X X O X
81+
. O X .""",
82+
"winner": "O"
83+
},
84+
{
85+
"description": "X wins using a spiral path",
86+
"board":
87+
""" O X X X X X X X X
88+
O X O O O O O O O
89+
O X O X X X X X O
90+
O X O X O O O X O
91+
O X O X X X O X O
92+
O X O O O X O X O
93+
O X X X X X O X O
94+
O O O O O O O X O
95+
X X X X X X X X O """,
96+
"winner": "X"
97+
},
98+
]
99+
100+
class SieveTest(unittest.TestCase):
101+
def test_game(self):
102+
for t in testcases:
103+
winner = connect.play(t["board"])
104+
expected = t["winner"] if t["winner"] else "None"
105+
got = winner if winner else "None"
106+
self.assertEqual(winner, t["winner"],
107+
"Test failed: %s, expected winner: %s, got: %s" % (t["description"], expected, got))
108+
109+
if __name__ == '__main__':
110+
unittest.main()

exercises/connect/example.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
class ConnectGame:
3+
4+
directions = [(0,1), (0,-1), (1,0), (-1,0), (1,-1), (-1,1)]
5+
white = "O"
6+
black = "X"
7+
none = ""
8+
9+
def __init__(self, lines):
10+
self.board = self.make_board(lines)
11+
assert(len(self.board) > 0)
12+
13+
self.width = len(self.board[0])
14+
self.height = len(self.board)
15+
assert(self.width > 0 and self.height > 0)
16+
17+
for l in self.board:
18+
assert(len(l) == self.width)
19+
20+
def valid(self, x, y):
21+
return x >= 0 and x < self.width and y >= 0 and y < self.height
22+
23+
def make_board(self, lines):
24+
return ["".join(l.split()) for l in lines.splitlines()]
25+
26+
def player_reach_dest(self, player, x, y):
27+
if player == self.black:
28+
return x == self.width - 1
29+
if player == self.white:
30+
return y == self.height - 1
31+
32+
def walk_board(self, player, x, y, visited=[]):
33+
if (x, y) in visited:
34+
return False
35+
36+
if (not self.valid(x, y)) or self.board[y][x] != player:
37+
return False
38+
39+
if self.player_reach_dest(player, x, y):
40+
return True
41+
42+
for d in self.directions:
43+
if self.walk_board(player, x + d[0], y + d[1], visited + [(x,y)]):
44+
return True
45+
46+
def check_player_is_winner(self, player):
47+
if player == self.black:
48+
return any([self.walk_board(player, 0, y) for y in range(self.height)])
49+
if player == self.white:
50+
return any([self.walk_board(player, x, 0) for x in range(self.width)])
51+
52+
def get_winner(self):
53+
if self.check_player_is_winner(self.black):
54+
return self.black
55+
if self.check_player_is_winner(self.white):
56+
return self.white
57+
return self.none
58+
59+
def play(board):
60+
game = ConnectGame(board)
61+
return game.get_winner()

0 commit comments

Comments
 (0)