diff --git a/config.json b/config.json index ccb1c726ba..44183ea78b 100644 --- a/config.json +++ b/config.json @@ -429,6 +429,14 @@ "difficulty": 1, "topics": [ ] + }, + { + "slug": "word-search", + "difficulty": 6, + "topics": [ + "strings", + "searching" + ] } ], "deprecated": [ diff --git a/exercises/word-search/example.py b/exercises/word-search/example.py new file mode 100644 index 0000000000..405aa1f3b7 --- /dev/null +++ b/exercises/word-search/example.py @@ -0,0 +1,57 @@ +import copy + + +class Point(object): + def __init__(self, x, y): + self.x = x + self.y = y + + def __repr__(self): + return 'Point({}:{})'.format(self.x, self.y) + + def __add__(self, other): + return Point(self.x + other.x, self.y + other.y) + + def __sub__(self, other): + return Point(self.x - other.x, self.y - other.y) + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + def __ne__(self, other): + return not(self == other) + + +DIRECTIONS = (Point(1, 0), Point(1, -1), Point(1, 1), Point(-1, -1), + Point(0, -1), Point(0, 1), Point(-1, 1), Point(-1, 0)) + + +class WordSearch(object): + def __init__(self, puzzle): + self.rows = puzzle.split() + self.width = len(self.rows[0]) + self.height = len(self.rows) + + def find_char(self, coordinate): + if coordinate.x < 0 or coordinate.x >= self.width: + return + if coordinate.y < 0 or coordinate.y >= self.height: + return + return self.rows[coordinate.y][coordinate.x] + + def find(self, word, position, direction): + current = copy.copy(position) + for letter in word: + if self.find_char(current) != letter: + return + current += direction + return position, current - direction + + def search(self, word): + positions = (Point(x, y) for x in range(self.width) for y in range(self.height)) + for pos in positions: + for d in DIRECTIONS: + result = self.find(word, pos, d) + if result: + return result + return None diff --git a/exercises/word-search/word_search.py b/exercises/word-search/word_search.py new file mode 100644 index 0000000000..61fe69b21d --- /dev/null +++ b/exercises/word-search/word_search.py @@ -0,0 +1,27 @@ +class Point(object): + def __init__(self, x, y): + self.x = x + self.y = y + + def __repr__(self): + return 'Point({}:{})'.format(self.x, self.y) + + def __add__(self, other): + return Point(self.x + other.x, self.y + other.y) + + def __sub__(self, other): + return Point(self.x - other.x, self.y - other.y) + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + def __ne__(self, other): + return not(self == other) + + +class WordSearch(object): + def __init__(self, puzzle): + pass + + def search(self, word): + return None diff --git a/exercises/word-search/word_search_test.py b/exercises/word-search/word_search_test.py new file mode 100644 index 0000000000..f279638c44 --- /dev/null +++ b/exercises/word-search/word_search_test.py @@ -0,0 +1,84 @@ +import unittest + +from word_search import WordSearch, Point + + +class WordSearchTests(unittest.TestCase): + + @classmethod + def setUpClass(self): + puzzle = ('jefblpepre\n' + 'camdcimgtc\n' + 'oivokprjsm\n' + 'pbwasqroua\n' + 'rixilelhrs\n' + 'wolcqlirpc\n' + 'screeaumgr\n' + 'alxhpburyi\n' + 'jalaycalmp\n' + 'clojurermt') + self.example = WordSearch(puzzle) + + def test_horizontal_words_left_to_right(self): + self.assertEqual( + self.example.search('clojure'), + (Point(0, 9), Point(6, 9)) + ) + + def test_horizontal_words_right_to_left(self): + self.assertEqual( + self.example.search('elixir'), + (Point(5, 4), Point(0, 4)) + ) + + def test_vertical_words_top_to_bottom(self): + self.assertEqual( + self.example.search('ecmascript'), + (Point(9, 0), Point(9, 9)) + ) + + def test_vertical_words_bottom_to_top(self): + self.assertEqual( + self.example.search('rust'), + (Point(8, 4), Point(8, 1)) + ) + + def test_diagonal_words_top_left_to_bottom_right(self): + self.assertEqual( + self.example.search('java'), + (Point(0, 0), Point(3, 3)) + ) + + def test_diagonal_upper_bottom_right_to_top_left(self): + self.assertEqual( + self.example.search('lua'), + (Point(7, 8), Point(5, 6)) + ) + + def test_diagonal_upper_bottom_left_to_top_right(self): + self.assertEqual( + self.example.search('lisp'), + (Point(2, 5), Point(5, 2)) + ) + + def test_diagonal_upper_top_right_to_bottom_left(self): + self.assertEqual( + self.example.search('ruby'), + (Point(7, 5), Point(4, 8)) + ) + + def test_words_that_are_not_in_the_puzzle(self): + self.assertIsNone(self.example.search('haskell')) + + def test_search_differently_sized_puzzles(self): + puzzle = ('qwertyuiopz\n' + 'luamsicrexe\n' + 'abcdefghijk') + self.assertEqual( + WordSearch(puzzle).search('exercism'), + (Point(10, 1), Point(3, 1)) + ) + + +if __name__ == '__main__': + unittest.main()