-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add dominoes/README.md * Add test cases and example solution for dominoes * add dominoes to config.json * dominoes: add check for name == "__main__" * dominoes: update canonical data version and formatting fixes in README * dominoes: update README to latest description RE: exercism/problem-specifications#972
- Loading branch information
1 parent
dd2a80b
commit 1b9ed09
Showing
5 changed files
with
196 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Dominoes | ||
|
||
Make a chain of dominoes. | ||
|
||
Compute a way to order a given set of dominoes in such a way that they form a | ||
correct domino chain (the dots on one half of a stone match the dots on the | ||
neighbouring half of an adjacent stone) and that dots on the halfs of the stones | ||
which don't have a neighbour (the first and last stone) match each other. | ||
|
||
For example given the stones `[2|1]`, `[2|3]` and `[1|3]` you should compute something | ||
like `[1|2] [2|3] [3|1]` or `[3|2] [2|1] [1|3]` or `[1|3] [3|2] [2|1]` etc, where the first and last numbers are the same. | ||
|
||
For stones `[1|2]`, `[4|1]` and `[2|3]` the resulting chain is not valid: `[4|1] [1|2] [2|3]`'s first and last numbers are not the same. 4 != 3 | ||
|
||
Some test cases may use duplicate stones in a chain solution, assume that multiple Domino sets are being used. | ||
|
||
## Submitting Exercises | ||
|
||
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory. | ||
|
||
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`. | ||
|
||
|
||
For more detailed information about running tests, code style and linting, | ||
please see the [help page](http://exercism.io/languages/python). | ||
|
||
## Submitting Incomplete Solutions | ||
It's possible to submit an incomplete solution so you can see how others have completed the exercise. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
def chain(dominoes): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import unittest | ||
|
||
from dominoes import chain | ||
|
||
|
||
# Tests adapted from `problem-specifications//canonical-data.json` @ v2.0.0 | ||
|
||
class DominoesTest(unittest.TestCase): | ||
def test_empty_input_empty_output(self): | ||
input_dominoes = [] | ||
output_chain = chain(input_dominoes) | ||
self.assert_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_singleton_input_singleton_output(self): | ||
input_dominoes = [(1, 1)] | ||
output_chain = chain(input_dominoes) | ||
self.assert_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_singleton_cant_be_chained(self): | ||
input_dominoes = [(1, 2)] | ||
output_chain = chain(input_dominoes) | ||
self.refute_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_three_elements(self): | ||
input_dominoes = [(1, 2), (3, 1), (2, 3)] | ||
output_chain = chain(input_dominoes) | ||
self.assert_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_can_reverse_dominoes(self): | ||
input_dominoes = [(1, 2), (1, 3), (2, 3)] | ||
output_chain = chain(input_dominoes) | ||
self.assert_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_cant_be_chained(self): | ||
input_dominoes = [(1, 2), (4, 1), (2, 3)] | ||
output_chain = chain(input_dominoes) | ||
self.refute_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_disconnected_simple(self): | ||
input_dominoes = [(1, 1), (2, 2)] | ||
output_chain = chain(input_dominoes) | ||
self.refute_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_disconnected_double_loop(self): | ||
input_dominoes = [(1, 2), (2, 1), (3, 4), (4, 3)] | ||
output_chain = chain(input_dominoes) | ||
self.refute_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_disconnected_single_isolated(self): | ||
input_dominoes = [(1, 2), (2, 3), (3, 1), (4, 4)] | ||
output_chain = chain(input_dominoes) | ||
self.refute_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_need_backtrack(self): | ||
input_dominoes = [(1, 2), (2, 3), (3, 1), (2, 4), (2, 4)] | ||
output_chain = chain(input_dominoes) | ||
self.assert_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_separate_loops(self): | ||
input_dominoes = [(1, 2), (2, 3), (3, 1), (1, 1), (2, 2), (3, 3)] | ||
output_chain = chain(input_dominoes) | ||
self.assert_correct_chain(input_dominoes, output_chain) | ||
|
||
def test_nine_elements(self): | ||
input_dominoes = [(1, 2), (5, 3), (3, 1), (1, 2), (2, 4), (1, 6), | ||
(2, 3), (3, 4), (5, 6)] | ||
output_chain = chain(input_dominoes) | ||
self.assert_correct_chain(input_dominoes, output_chain) | ||
|
||
# Utility methods | ||
|
||
def normalize_dominoes(self, dominoes): | ||
return list(sorted(tuple(sorted(domino)) for domino in dominoes)) | ||
|
||
def assert_same_dominoes(self, input_dominoes, output_chain): | ||
msg = ('Dominoes used in the output must be the same ' | ||
'as the ones given in the input') | ||
input_normal = self.normalize_dominoes(input_dominoes) | ||
output_normal = self.normalize_dominoes(output_chain) | ||
self.assertEqual(input_normal, output_normal, msg) | ||
|
||
def assert_consecutive_dominoes_match(self, output_chain): | ||
for i in range(len(output_chain) - 1): | ||
msg = ("In chain {}, right end of domino {} ({}) " | ||
"and left end of domino {} ({}) must match") | ||
msg = msg.format(output_chain, | ||
i, | ||
output_chain[i], | ||
i + 1, | ||
output_chain[i + 1]) | ||
self.assertEqual(output_chain[i][1], output_chain[i + 1][0], msg) | ||
|
||
def assert_dominoes_at_ends_match(self, output_chain): | ||
msg = ("In chain {}, left end of first domino ({}) and " | ||
"right end of last domino ({}) must match") | ||
msg = msg.format(output_chain, output_chain[0], output_chain[-1]) | ||
self.assertEqual(output_chain[0][0], output_chain[-1][1], msg) | ||
|
||
def assert_correct_chain(self, input_dominoes, output_chain): | ||
msg = 'There should be a chain for {}'.format(input_dominoes) | ||
self.assertIsNotNone(output_chain, msg) | ||
self.assert_same_dominoes(input_dominoes, output_chain) | ||
if not any(output_chain): | ||
return | ||
self.assert_consecutive_dominoes_match(output_chain) | ||
self.assert_dominoes_at_ends_match(output_chain) | ||
|
||
def refute_correct_chain(self, input_dominoes, output_chain): | ||
msg = 'There should be no valid chain for {}'.format(input_dominoes) | ||
self.assertIsNone(output_chain, msg) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from itertools import permutations | ||
from functools import reduce | ||
|
||
|
||
def swap(a, b): | ||
return (b, a) | ||
|
||
|
||
def build_chain(chain, domino): | ||
if chain is not None: | ||
last = chain[-1] | ||
if len(chain) == 1 and last[0] == domino[0]: | ||
return [swap(*last), domino] | ||
elif len(chain) == 1 and last[0] == domino[1]: | ||
return [swap(*last), swap(*domino)] | ||
elif last[1] == domino[0]: | ||
return chain + [domino] | ||
elif last[1] == domino[1]: | ||
return chain + [swap(*domino)] | ||
return None | ||
|
||
|
||
def chain(dominoes): | ||
if not any(dominoes): | ||
return [] | ||
for perm in permutations(dominoes): | ||
chain = reduce(build_chain, perm[1:], [perm[0]]) | ||
if chain is not None and chain[0][0] == chain[-1][1]: | ||
return chain | ||
return None |