From a8dcb142c72282e7ee8e7799266ad429785bdd1a Mon Sep 17 00:00:00 2001 From: resu-xuniL Date: Sun, 19 Jul 2026 11:38:22 +0200 Subject: [PATCH 1/3] Add `word-search` exercise --- config.json | 8 + .../word-search/.docs/instructions.md | 24 + .../practice/word-search/.meta/config.json | 17 + .../practice/word-search/.meta/example.php | 79 ++ .../practice/word-search/.meta/tests.toml | 82 ++ exercises/practice/word-search/WordSearch.php | 38 + .../practice/word-search/WordSearchTest.php | 769 ++++++++++++++++++ 7 files changed, 1017 insertions(+) create mode 100644 exercises/practice/word-search/.docs/instructions.md create mode 100644 exercises/practice/word-search/.meta/config.json create mode 100644 exercises/practice/word-search/.meta/example.php create mode 100644 exercises/practice/word-search/.meta/tests.toml create mode 100644 exercises/practice/word-search/WordSearch.php create mode 100644 exercises/practice/word-search/WordSearchTest.php diff --git a/config.json b/config.json index 670d309ad..a9ee4e004 100644 --- a/config.json +++ b/config.json @@ -1138,6 +1138,14 @@ "strings" ] }, + { + "slug": "word-search", + "name": "Word Search", + "uuid": "6b215857-f382-4926-b5f8-3e61db9283d6", + "practices": [], + "prerequisites": [], + "difficulty": 4 + }, { "slug": "alphametics", "name": "Alphametics", diff --git a/exercises/practice/word-search/.docs/instructions.md b/exercises/practice/word-search/.docs/instructions.md new file mode 100644 index 000000000..e2d08aa9e --- /dev/null +++ b/exercises/practice/word-search/.docs/instructions.md @@ -0,0 +1,24 @@ +# Instructions + +In word search puzzles you get a square of letters and have to find specific words in them. + +For example: + +```text +jefblpepre +camdcimgtc +oivokprjsm +pbwasqroua +rixilelhrs +wolcqlirpc +screeaumgr +alxhpburyi +jalaycalmp +clojurermt +``` + +There are several programming languages hidden in the above square. + +Words can be hidden in all kinds of directions: left-to-right, right-to-left, vertical and diagonal. + +Given a puzzle and a list of words return the location of the first and last letter of each word. diff --git a/exercises/practice/word-search/.meta/config.json b/exercises/practice/word-search/.meta/config.json new file mode 100644 index 000000000..c67cfaf96 --- /dev/null +++ b/exercises/practice/word-search/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [ + "resu-xuniL" + ], + "files": { + "solution": [ + "WordSearch.php" + ], + "test": [ + "WordSearchTest.php" + ], + "example": [ + ".meta/example.php" + ] + }, + "blurb": "Create a program to solve a word search puzzle." +} diff --git a/exercises/practice/word-search/.meta/example.php b/exercises/practice/word-search/.meta/example.php new file mode 100644 index 000000000..c21b1679b --- /dev/null +++ b/exercises/practice/word-search/.meta/example.php @@ -0,0 +1,79 @@ +width = strlen($this->grid[0]); + $this->height = count($this->grid); + } + + public function search(array $words): array + { + foreach ($words as $word) { + for ($X = 0; $X < $this->width; $X++) { + for ($Y = 0; $Y < $this->height; $Y++) { + foreach (self::NEIGHBORHOOD as [$checkX, $checkY]) { + $search = $this->find($word, $X, $Y, $checkX, $checkY); + + if (isset($search)) { + $this->found[$word] = $search; + continue 4; + } else { + $this->found[$word] = null; + } + } + } + } + } + + return $this->found; + } + + private function find(string $word, int $X, int $Y, int $nextX, int $nextY): ?array + { + $currentX = $X; + $currentY = $Y; + + for ($i = 0; $i < strlen($word); $i++) { + if ($this->findNextLetter($currentX, $currentY) !== $word[$i]) { + return null; + } + + $currentX += $nextX; + $currentY += $nextY; + } + + return [ + "start" => [ + "column" => $X + 1, + "row" => $Y + 1 + ], + "end" => [ + "column" => $currentX + 1 - $nextX, + "row" => $currentY + 1 - $nextY + ] + ]; + } + + private function findNextLetter(int $X, int $Y): ?string + { + if ($X < 0 || $Y < 0 || $X >= $this->width || $Y >= $this->height) { + return null; + } + + return $this->grid[$Y][$X]; + } +} diff --git a/exercises/practice/word-search/.meta/tests.toml b/exercises/practice/word-search/.meta/tests.toml new file mode 100644 index 000000000..3f98113d7 --- /dev/null +++ b/exercises/practice/word-search/.meta/tests.toml @@ -0,0 +1,82 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[b4057815-0d01-41f0-9119-6a91f54b2a0a] +description = "Should accept an initial game grid and a target search word" + +[6b22bcc5-6cbf-4674-931b-d2edbff73132] +description = "Should locate one word written left to right" + +[ff462410-434b-442d-9bc3-3360c75f34a8] +description = "Should locate the same word written left to right in a different position" + +[a02febae-6347-443e-b99c-ab0afb0b8fca] +description = "Should locate a different left to right word" + +[e42e9987-6304-4e13-8232-fa07d5280130] +description = "Should locate that different left to right word in a different position" + +[9bff3cee-49b9-4775-bdfb-d55b43a70b2f] +description = "Should locate a left to right word in two line grid" + +[851a35fb-f499-4ec1-9581-395a87903a22] +description = "Should locate a left to right word in three line grid" + +[2f3dcf84-ba7d-4b75-8b8d-a3672b32c035] +description = "Should locate a left to right word in ten line grid" + +[006d4856-f365-4e84-a18c-7d129ce9eefb] +description = "Should locate that left to right word in a different position in a ten line grid" + +[eff7ac9f-ff11-443e-9747-40850c12ab60] +description = "Should locate a different left to right word in a ten line grid" + +[dea39f86-8c67-4164-8884-13bfc48bd13b] +description = "Should locate multiple words" + +[29e6a6a5-f80c-48a6-8e68-05bbbe187a09] +description = "Should locate a single word written right to left" + +[3cf34428-b43f-48b6-b332-ea0b8836011d] +description = "Should locate multiple words written in different horizontal directions" + +[2c8cd344-a02f-464b-93b6-8bf1bd890003] +description = "Should locate words written top to bottom" + +[9ee1e43d-e59d-4c32-9a5f-6a22d4a1550f] +description = "Should locate words written bottom to top" + +[6a21a676-f59e-4238-8e88-9f81015afae9] +description = "Should locate words written top left to bottom right" + +[c9125189-1861-4b0d-a14e-ba5dab29ca7c] +description = "Should locate words written bottom right to top left" + +[b19e2149-7fc5-41ec-a8a9-9bc6c6c38c40] +description = "Should locate words written bottom left to top right" + +[69e1d994-a6d7-4e24-9b5a-db76751c2ef8] +description = "Should locate words written top right to bottom left" + +[695531db-69eb-463f-8bad-8de3bf5ef198] +description = "Should fail to locate a word that is not in the puzzle" + +[fda5b937-6774-4a52-8f89-f64ed833b175] +description = "Should fail to locate words that are not on horizontal, vertical, or diagonal lines" + +[5b6198eb-2847-4e2f-8efe-65045df16bd3] +description = "Should not concatenate different lines to find a horizontal word" + +[eba44139-a34f-4a92-98e1-bd5f259e5769] +description = "Should not wrap around horizontally to find a word" + +[cd1f0fa8-76af-4167-b105-935f78364dac] +description = "Should not wrap around vertically to find a word" diff --git a/exercises/practice/word-search/WordSearch.php b/exercises/practice/word-search/WordSearch.php new file mode 100644 index 000000000..725efbce8 --- /dev/null +++ b/exercises/practice/word-search/WordSearch.php @@ -0,0 +1,38 @@ +. + * + * To disable strict typing, comment out the directive below. + */ + +declare(strict_types=1); + +class WordSearch +{ + public function __construct(array $grid) + { + throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); + } + + public function search(array $words): array + { + throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); + } +} diff --git a/exercises/practice/word-search/WordSearchTest.php b/exercises/practice/word-search/WordSearchTest.php new file mode 100644 index 000000000..8e5a1641a --- /dev/null +++ b/exercises/practice/word-search/WordSearchTest.php @@ -0,0 +1,769 @@ + null]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 6b22bcc5-6cbf-4674-931b-d2edbff73132 + */ + #[TestDox('Should locate one word written left to right')] + public function testShouldLocateOneWordWrittenLeftToRight(): void + { + $wordsToSearchFor = ["clojure"]; + $grid = ["clojurermt"]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 1], + "end" => ["column" => 7, "row" => 1] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: ff462410-434b-442d-9bc3-3360c75f34a8 + */ + #[TestDox('Should locate the same word written left to right in a different position')] + public function testShouldLocateTheSameWordWrittenLeftToRightInADifferentPosition(): void + { + $wordsToSearchFor = ["clojure"]; + $grid = ["mtclojurer"]; + $expected = [ + "clojure" => [ + "start" => ["column" => 3, "row" => 1], + "end" => ["column" => 9, "row" => 1] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: a02febae-6347-443e-b99c-ab0afb0b8fca + */ + #[TestDox('Should locate a different left to right word')] + public function testShouldLocateADifferentLeftToRightWord(): void + { + $wordsToSearchFor = ["coffee"]; + $grid = ["coffeelplx"]; + $expected = [ + "coffee" => [ + "start" => ["column" => 1, "row" => 1], + "end" => ["column" => 6, "row" => 1] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: e42e9987-6304-4e13-8232-fa07d5280130 + */ + #[TestDox('Should locate that different left to right word in a different position')] + public function testShouldLocateThatDifferentLeftToRightWordInADifferentPosition(): void + { + $wordsToSearchFor = ["coffee"]; + $grid = ["xcoffeezlp"]; + $expected = [ + "coffee" => [ + "start" => ["column" => 2, "row" => 1], + "end" => ["column" => 7, "row" => 1] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 9bff3cee-49b9-4775-bdfb-d55b43a70b2f + */ + #[TestDox('Should locate a left to right word in two line grid')] + public function testShouldLocateALeftToRightWordInTwoLineGrid(): void + { + $wordsToSearchFor = ["clojure"]; + $grid = ["jefblpepre", "tclojurerm"]; + $expected = [ + "clojure" => [ + "start" => ["column" => 2, "row" => 2], + "end" => ["column" => 8, "row" => 2] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 851a35fb-f499-4ec1-9581-395a87903a22 + */ + #[TestDox('Should locate a left to right word in three line grid')] + public function testShouldLocateALeftToRightWordInThreeLineGrid(): void + { + $wordsToSearchFor = ["clojure"]; + $grid = ["camdcimgtc", "jefblpepre", "clojurermt"]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 3], + "end" => ["column" => 7, "row" => 3] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 2f3dcf84-ba7d-4b75-8b8d-a3672b32c035 + */ + #[TestDox('Should locate a left to right word in ten line grid')] + public function testShouldLocateALeftToRightWordInTenLineGrid(): void + { + $wordsToSearchFor = ["clojure"]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 006d4856-f365-4e84-a18c-7d129ce9eefb + */ + #[TestDox('Should locate that left to right word in a different position in a ten line grid')] + public function testShouldLocateThatLeftToRightWordInADifferentPositionInATenLineGrid(): void + { + $wordsToSearchFor = ["clojure"]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "clojurermt", + "jalaycalmp" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 9], + "end" => ["column" => 7, "row" => 9] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: eff7ac9f-ff11-443e-9747-40850c12ab60 + */ + #[TestDox('Should locate a different left to right word in a ten line grid')] + public function testShouldLocateADifferentLeftToRightWordInATenLineGrid(): void + { + $wordsToSearchFor = ["fortran"]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "fortranftw", + "alxhpburyi", + "clojurermt", + "jalaycalmp" + ]; + $expected = [ + "fortran" => [ + "start" => ["column" => 1, "row" => 7], + "end" => ["column" => 7, "row" => 7] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: dea39f86-8c67-4164-8884-13bfc48bd13b + */ + #[TestDox('Should locate multiple words')] + public function testShouldLocateMultipleWords(): void + { + $wordsToSearchFor = ["fortran", "clojure"]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "fortranftw", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "fortran" => [ + "start" => ["column" => 1, "row" => 7], + "end" => ["column" => 7, "row" => 7] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 29e6a6a5-f80c-48a6-8e68-05bbbe187a09 + */ + #[TestDox('Should locate a single word written right to left')] + public function testShouldLocateASingleWordWrittenRightToLeft(): void + { + $wordsToSearchFor = ["elixir"]; + $grid = ["rixilelhrs"]; + $expected = [ + "elixir" => [ + "start" => ["column" => 6, "row" => 1], + "end" => ["column" => 1, "row" => 1] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 3cf34428-b43f-48b6-b332-ea0b8836011d + */ + #[TestDox('Should locate multiple words written in different horizontal directions')] + public function testShouldLocateMultipleWordsWrittenInDifferentHorizontalDirections(): void + { + $wordsToSearchFor = ["elixir", "clojure"]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "elixir" => [ + "start" => ["column" => 6, "row" => 5], + "end" => ["column" => 1, "row" => 5] + ], + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 2c8cd344-a02f-464b-93b6-8bf1bd890003 + */ + #[TestDox('Should locate words written top to bottom')] + public function testShouldLocateWordsWrittenTopToBottom(): void + { + $wordsToSearchFor = ["clojure", "elixir", "ecmascript"]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "elixir" => [ + "start" => ["column" => 6, "row" => 5], + "end" => ["column" => 1, "row" => 5] + ], + "ecmascript" => [ + "start" => ["column" => 10, "row" => 1], + "end" => ["column" => 10, "row" => 10] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 9ee1e43d-e59d-4c32-9a5f-6a22d4a1550f + */ + #[TestDox('Should locate words written bottom to top')] + public function testShouldLocateWordsWrittenBottomToTop(): void + { + $wordsToSearchFor = ["clojure", "elixir", "ecmascript", "rust"]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "elixir" => [ + "start" => ["column" => 6, "row" => 5], + "end" => ["column" => 1, "row" => 5] + ], + "ecmascript" => [ + "start" => ["column" => 10, "row" => 1], + "end" => ["column" => 10, "row" => 10] + ], + "rust" => [ + "start" => ["column" => 9, "row" => 5], + "end" => ["column" => 9, "row" => 2] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 6a21a676-f59e-4238-8e88-9f81015afae9 + */ + #[TestDox('Should locate words written top left to bottom right')] + public function testShouldLocateWordsWrittenTopLeftToBottomRight(): void + { + $wordsToSearchFor = ["clojure", "elixir", "ecmascript", "rust", "java"]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "elixir" => [ + "start" => ["column" => 6, "row" => 5], + "end" => ["column" => 1, "row" => 5] + ], + "ecmascript" => [ + "start" => ["column" => 10, "row" => 1], + "end" => ["column" => 10, "row" => 10] + ], + "rust" => [ + "start" => ["column" => 9, "row" => 5], + "end" => ["column" => 9, "row" => 2] + ], + "java" => [ + "start" => ["column" => 1, "row" => 1], + "end" => ["column" => 4, "row" => 4] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: c9125189-1861-4b0d-a14e-ba5dab29ca7c + */ + #[TestDox('Should locate words written bottom right to top left')] + public function testShouldLocateWordsWrittenBottomRightToTopLeft(): void + { + $wordsToSearchFor = [ + "clojure", + "elixir", + "ecmascript", + "rust", + "java", + "lua" + ]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "elixir" => [ + "start" => ["column" => 6, "row" => 5], + "end" => ["column" => 1, "row" => 5] + ], + "ecmascript" => [ + "start" => ["column" => 10, "row" => 1], + "end" => ["column" => 10, "row" => 10] + ], + "rust" => [ + "start" => ["column" => 9, "row" => 5], + "end" => ["column" => 9, "row" => 2] + ], + "java" => [ + "start" => ["column" => 1, "row" => 1], + "end" => ["column" => 4, "row" => 4] + ], + "lua" => [ + "start" => ["column" => 8, "row" => 9], + "end" => ["column" => 6, "row" => 7] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: b19e2149-7fc5-41ec-a8a9-9bc6c6c38c40 + */ + #[TestDox('Should locate words written bottom left to top right')] + public function testShouldLocateWordsWrittenBottomLeftToTopRight(): void + { + $wordsToSearchFor = [ + "clojure", + "elixir", + "ecmascript", + "rust", + "java", + "lua", + "lisp" + ]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "elixir" => [ + "start" => ["column" => 6, "row" => 5], + "end" => ["column" => 1, "row" => 5] + ], + "ecmascript" => [ + "start" => ["column" => 10, "row" => 1], + "end" => ["column" => 10, "row" => 10] + ], + "rust" => [ + "start" => ["column" => 9, "row" => 5], + "end" => ["column" => 9, "row" => 2] + ], + "java" => [ + "start" => ["column" => 1, "row" => 1], + "end" => ["column" => 4, "row" => 4] + ], + "lua" => [ + "start" => ["column" => 8, "row" => 9], + "end" => ["column" => 6, "row" => 7] + ], + "lisp" => [ + "start" => ["column" => 3, "row" => 6], + "end" => ["column" => 6, "row" => 3] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 69e1d994-a6d7-4e24-9b5a-db76751c2ef8 + */ + #[TestDox('Should locate words written top right to bottom left')] + public function testShouldLocateWordsWrittenTopRightToBottomLeft(): void + { + $wordsToSearchFor = [ + "clojure", + "elixir", + "ecmascript", + "rust", + "java", + "lua", + "lisp", + "ruby" + ]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "elixir" => [ + "start" => ["column" => 6, "row" => 5], + "end" => ["column" => 1, "row" => 5] + ], + "ecmascript" => [ + "start" => ["column" => 10, "row" => 1], + "end" => ["column" => 10, "row" => 10] + ], + "rust" => [ + "start" => ["column" => 9, "row" => 5], + "end" => ["column" => 9, "row" => 2] + ], + "java" => [ + "start" => ["column" => 1, "row" => 1], + "end" => ["column" => 4, "row" => 4] + ], + "lua" => [ + "start" => ["column" => 8, "row" => 9], + "end" => ["column" => 6, "row" => 7] + ], + "lisp" => [ + "start" => ["column" => 3, "row" => 6], + "end" => ["column" => 6, "row" => 3] + ], + "ruby" => [ + "start" => ["column" => 8, "row" => 6], + "end" => ["column" => 5, "row" => 9] + ] + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 695531db-69eb-463f-8bad-8de3bf5ef198 + */ + #[TestDox('Should fail to locate a word that is not in the puzzle')] + public function testShouldFail(): void + { + $wordsToSearchFor = [ + "clojure", + "elixir", + "ecmascript", + "rust", + "java", + "lua", + "lisp", + "ruby", + "haskell" + ]; + $grid = [ + "jefblpepre", + "camdcimgtc", + "oivokprjsm", + "pbwasqroua", + "rixilelhrs", + "wolcqlirpc", + "screeaumgr", + "alxhpburyi", + "jalaycalmp", + "clojurermt" + ]; + $expected = [ + "clojure" => [ + "start" => ["column" => 1, "row" => 10], + "end" => ["column" => 7, "row" => 10] + ], + "elixir" => [ + "start" => ["column" => 6, "row" => 5], + "end" => ["column" => 1, "row" => 5] + ], + "ecmascript" => [ + "start" => ["column" => 10, "row" => 1], + "end" => ["column" => 10, "row" => 10] + ], + "rust" => [ + "start" => ["column" => 9, "row" => 5], + "end" => ["column" => 9, "row" => 2] + ], + "java" => [ + "start" => ["column" => 1, "row" => 1], + "end" => ["column" => 4, "row" => 4] + ], + "lua" => [ + "start" => ["column" => 8, "row" => 9], + "end" => ["column" => 6, "row" => 7] + ], + "lisp" => [ + "start" => ["column" => 3, "row" => 6], + "end" => ["column" => 6, "row" => 3] + ], + "ruby" => [ + "start" => ["column" => 8, "row" => 6], + "end" => ["column" => 5, "row" => 9] + ], + "haskell" => null + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: fda5b937-6774-4a52-8f89-f64ed833b175 + */ + #[TestDox('Should fail to locate words that are not on horizontal, vertical, or diagonal lines')] + public function testShouldFailToLocateWordsThatAreNotOnHorizontalVerticalOrDiagonalLines(): void + { + $wordsToSearchFor = ["aef", "ced", "abf", "cbd"]; + $grid = ["abc", "def"]; + $expected = [ + "aef" => null, + "ced" => null, + "abf" => null, + "cbd" => null + ]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: 5b6198eb-2847-4e2f-8efe-65045df16bd3 + */ + #[TestDox('Should not concatenate different lines to find a horizontal word')] + public function testShouldNotConcatenateDifferentLinesToFindAHorizontalWord(): void + { + $wordsToSearchFor = ["elixir"]; + $grid = ["abceli", "xirdfg"]; + $expected = ["elixir" => null]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: eba44139-a34f-4a92-98e1-bd5f259e5769 + */ + #[TestDox('Should not wrap around horizontally to find a word')] + public function testShouldNotWrapAroundHorizontallyToFindAWord(): void + { + $wordsToSearchFor = ["lisp"]; + $grid = ["silabcdefp"]; + $expected = ["lisp" => null]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } + + /** + * uuid: cd1f0fa8-76af-4167-b105-935f78364dac + */ + #[TestDox('Should not wrap around vertically to find a word')] + public function testShouldNotWrapAroundVerticallyToFindAWord(): void + { + $wordsToSearchFor = ["rust"]; + $grid = [ + "s", + "u", + "r", + "a", + "b", + "c", + "t" + ]; + $expected = ["rust" => null]; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + } +} From 614f08dbdbb112be3fd987d73305bbd362adbff9 Mon Sep 17 00:00:00 2001 From: resu-xuniL Date: Mon, 27 Jul 2026 18:32:55 +0200 Subject: [PATCH 2/3] Makes object oriented --- .../practice/word-search/.meta/example.php | 56 +- exercises/practice/word-search/WordSearch.php | 18 +- .../practice/word-search/WordSearchTest.php | 677 ++++++++---------- 3 files changed, 358 insertions(+), 393 deletions(-) diff --git a/exercises/practice/word-search/.meta/example.php b/exercises/practice/word-search/.meta/example.php index c21b1679b..2368a06b7 100644 --- a/exercises/practice/word-search/.meta/example.php +++ b/exercises/practice/word-search/.meta/example.php @@ -12,7 +12,6 @@ class WordSearch private int $width; private int $height; - private array $found; public function __construct(private array $grid) { @@ -20,29 +19,24 @@ public function __construct(private array $grid) $this->height = count($this->grid); } - public function search(array $words): array + public function search(string $word): ?Result { - foreach ($words as $word) { - for ($X = 0; $X < $this->width; $X++) { - for ($Y = 0; $Y < $this->height; $Y++) { - foreach (self::NEIGHBORHOOD as [$checkX, $checkY]) { - $search = $this->find($word, $X, $Y, $checkX, $checkY); + for ($X = 0; $X < $this->width; $X++) { + for ($Y = 0; $Y < $this->height; $Y++) { + foreach (self::NEIGHBORHOOD as [$checkX, $checkY]) { + $search = $this->find($word, $X, $Y, $checkX, $checkY); - if (isset($search)) { - $this->found[$word] = $search; - continue 4; - } else { - $this->found[$word] = null; - } + if (isset($search)) { + return $search; } } } } - return $this->found; + return null; } - private function find(string $word, int $X, int $Y, int $nextX, int $nextY): ?array + private function find(string $word, int $X, int $Y, int $nextX, int $nextY): ?Result { $currentX = $X; $currentY = $Y; @@ -56,16 +50,10 @@ private function find(string $word, int $X, int $Y, int $nextX, int $nextY): ?ar $currentY += $nextY; } - return [ - "start" => [ - "column" => $X + 1, - "row" => $Y + 1 - ], - "end" => [ - "column" => $currentX + 1 - $nextX, - "row" => $currentY + 1 - $nextY - ] - ]; + return new Result( + new Location($X + 1, $Y + 1), + new Location($currentX + 1 - $nextX, $currentY + 1 - $nextY) + ); } private function findNextLetter(int $X, int $Y): ?string @@ -77,3 +65,21 @@ private function findNextLetter(int $X, int $Y): ?string return $this->grid[$Y][$X]; } } + +class Result +{ + public function __construct(private Location $start, private Location $end) + { + } +} + +class Location +{ + public function __construct(private int $column, private int $row) + { + return [ + "column:" => $this->column, + "row:" => $this->row + ]; + } +} diff --git a/exercises/practice/word-search/WordSearch.php b/exercises/practice/word-search/WordSearch.php index 725efbce8..8fb378294 100644 --- a/exercises/practice/word-search/WordSearch.php +++ b/exercises/practice/word-search/WordSearch.php @@ -31,7 +31,23 @@ public function __construct(array $grid) throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); } - public function search(array $words): array + public function search(string $word): ?Result + { + throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); + } +} + +class Result +{ + public function __construct(Location $start, Location $end) + { + throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); + } +} + +class Location +{ + public function __construct(int $column, int $row) { throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); } diff --git a/exercises/practice/word-search/WordSearchTest.php b/exercises/practice/word-search/WordSearchTest.php index 8e5a1641a..20f66fe44 100644 --- a/exercises/practice/word-search/WordSearchTest.php +++ b/exercises/practice/word-search/WordSearchTest.php @@ -18,12 +18,11 @@ public static function setUpBeforeClass(): void #[TestDox('Should accept an initial game grid and a target search word')] public function testShouldAcceptAnInitialGameGridAndATargetSearchWord(): void { - $wordsToSearchFor = ["clojure"]; - $grid = ["jefblpepre",]; - $expected = ["clojure" => null]; - $wordSearch = new WordSearch($grid); + $grid = ["jefblpepre",]; + $expectedClojure = null; + $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); } /** @@ -32,17 +31,14 @@ public function testShouldAcceptAnInitialGameGridAndATargetSearchWord(): void #[TestDox('Should locate one word written left to right')] public function testShouldLocateOneWordWrittenLeftToRight(): void { - $wordsToSearchFor = ["clojure"]; - $grid = ["clojurermt"]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 1], - "end" => ["column" => 7, "row" => 1] - ] - ]; + $grid = ["clojurermt"]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 1), + end: new Location(column: 7, row: 1), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); } /** @@ -51,17 +47,14 @@ public function testShouldLocateOneWordWrittenLeftToRight(): void #[TestDox('Should locate the same word written left to right in a different position')] public function testShouldLocateTheSameWordWrittenLeftToRightInADifferentPosition(): void { - $wordsToSearchFor = ["clojure"]; - $grid = ["mtclojurer"]; - $expected = [ - "clojure" => [ - "start" => ["column" => 3, "row" => 1], - "end" => ["column" => 9, "row" => 1] - ] - ]; + $grid = ["mtclojurer"]; + $expectedClojure = new Result( + start: new Location(column: 3, row: 1), + end: new Location(column: 9, row: 1), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); } /** @@ -70,17 +63,14 @@ public function testShouldLocateTheSameWordWrittenLeftToRightInADifferentPositio #[TestDox('Should locate a different left to right word')] public function testShouldLocateADifferentLeftToRightWord(): void { - $wordsToSearchFor = ["coffee"]; - $grid = ["coffeelplx"]; - $expected = [ - "coffee" => [ - "start" => ["column" => 1, "row" => 1], - "end" => ["column" => 6, "row" => 1] - ] - ]; + $grid = ["coffeelplx"]; + $expectedCoffee = new Result( + start: new Location(column: 1, row: 1), + end: new Location(column: 6, row: 1), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedCoffee, $wordSearch->search("coffee")); } /** @@ -89,17 +79,14 @@ public function testShouldLocateADifferentLeftToRightWord(): void #[TestDox('Should locate that different left to right word in a different position')] public function testShouldLocateThatDifferentLeftToRightWordInADifferentPosition(): void { - $wordsToSearchFor = ["coffee"]; - $grid = ["xcoffeezlp"]; - $expected = [ - "coffee" => [ - "start" => ["column" => 2, "row" => 1], - "end" => ["column" => 7, "row" => 1] - ] - ]; + $grid = ["xcoffeezlp"]; + $expectedCoffee = new Result( + start: new Location(column: 2, row: 1), + end: new Location(column: 7, row: 1), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedCoffee, $wordSearch->search("coffee")); } /** @@ -108,17 +95,14 @@ public function testShouldLocateThatDifferentLeftToRightWordInADifferentPosition #[TestDox('Should locate a left to right word in two line grid')] public function testShouldLocateALeftToRightWordInTwoLineGrid(): void { - $wordsToSearchFor = ["clojure"]; - $grid = ["jefblpepre", "tclojurerm"]; - $expected = [ - "clojure" => [ - "start" => ["column" => 2, "row" => 2], - "end" => ["column" => 8, "row" => 2] - ] - ]; + $grid = ["jefblpepre", "tclojurerm"]; + $expectedClojure = new Result( + start: new Location(column: 2, row: 2), + end: new Location(column: 8, row: 2), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); } /** @@ -127,17 +111,14 @@ public function testShouldLocateALeftToRightWordInTwoLineGrid(): void #[TestDox('Should locate a left to right word in three line grid')] public function testShouldLocateALeftToRightWordInThreeLineGrid(): void { - $wordsToSearchFor = ["clojure"]; - $grid = ["camdcimgtc", "jefblpepre", "clojurermt"]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 3], - "end" => ["column" => 7, "row" => 3] - ] - ]; + $grid = ["camdcimgtc", "jefblpepre", "clojurermt"]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 3), + end: new Location(column: 7, row: 3), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); } /** @@ -146,7 +127,6 @@ public function testShouldLocateALeftToRightWordInThreeLineGrid(): void #[TestDox('Should locate a left to right word in ten line grid')] public function testShouldLocateALeftToRightWordInTenLineGrid(): void { - $wordsToSearchFor = ["clojure"]; $grid = [ "jefblpepre", "camdcimgtc", @@ -159,15 +139,13 @@ public function testShouldLocateALeftToRightWordInTenLineGrid(): void "jalaycalmp", "clojurermt" ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ] - ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); } /** @@ -176,7 +154,6 @@ public function testShouldLocateALeftToRightWordInTenLineGrid(): void #[TestDox('Should locate that left to right word in a different position in a ten line grid')] public function testShouldLocateThatLeftToRightWordInADifferentPositionInATenLineGrid(): void { - $wordsToSearchFor = ["clojure"]; $grid = [ "jefblpepre", "camdcimgtc", @@ -189,15 +166,13 @@ public function testShouldLocateThatLeftToRightWordInADifferentPositionInATenLin "clojurermt", "jalaycalmp" ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 9], - "end" => ["column" => 7, "row" => 9] - ] - ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 9), + end: new Location(column: 7, row: 9), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); } /** @@ -206,7 +181,6 @@ public function testShouldLocateThatLeftToRightWordInADifferentPositionInATenLin #[TestDox('Should locate a different left to right word in a ten line grid')] public function testShouldLocateADifferentLeftToRightWordInATenLineGrid(): void { - $wordsToSearchFor = ["fortran"]; $grid = [ "jefblpepre", "camdcimgtc", @@ -219,15 +193,13 @@ public function testShouldLocateADifferentLeftToRightWordInATenLineGrid(): void "clojurermt", "jalaycalmp" ]; - $expected = [ - "fortran" => [ - "start" => ["column" => 1, "row" => 7], - "end" => ["column" => 7, "row" => 7] - ] - ]; + $expectedFortran = new Result( + start: new Location(column: 1, row: 7), + end: new Location(column: 7, row: 7), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedFortran, $wordSearch->search("fortran")); } /** @@ -236,7 +208,6 @@ public function testShouldLocateADifferentLeftToRightWordInATenLineGrid(): void #[TestDox('Should locate multiple words')] public function testShouldLocateMultipleWords(): void { - $wordsToSearchFor = ["fortran", "clojure"]; $grid = [ "jefblpepre", "camdcimgtc", @@ -249,19 +220,18 @@ public function testShouldLocateMultipleWords(): void "jalaycalmp", "clojurermt" ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "fortran" => [ - "start" => ["column" => 1, "row" => 7], - "end" => ["column" => 7, "row" => 7] - ] - ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedFortran = new Result( + start: new Location(column: 1, row: 7), + end: new Location(column: 7, row: 7), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedFortran, $wordSearch->search("fortran")); } /** @@ -270,17 +240,14 @@ public function testShouldLocateMultipleWords(): void #[TestDox('Should locate a single word written right to left')] public function testShouldLocateASingleWordWrittenRightToLeft(): void { - $wordsToSearchFor = ["elixir"]; $grid = ["rixilelhrs"]; - $expected = [ - "elixir" => [ - "start" => ["column" => 6, "row" => 1], - "end" => ["column" => 1, "row" => 1] - ] - ]; + $expectedElixir = new Result( + start: new Location(column: 6, row: 1), + end: new Location(column: 1, row: 1), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); } /** @@ -289,7 +256,6 @@ public function testShouldLocateASingleWordWrittenRightToLeft(): void #[TestDox('Should locate multiple words written in different horizontal directions')] public function testShouldLocateMultipleWordsWrittenInDifferentHorizontalDirections(): void { - $wordsToSearchFor = ["elixir", "clojure"]; $grid = [ "jefblpepre", "camdcimgtc", @@ -301,20 +267,19 @@ public function testShouldLocateMultipleWordsWrittenInDifferentHorizontalDirecti "alxhpburyi", "jalaycalmp", "clojurermt" - ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "elixir" => [ - "start" => ["column" => 6, "row" => 5], - "end" => ["column" => 1, "row" => 5] - ], ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedElixir = new Result( + start: new Location(column: 6, row: 5), + end: new Location(column: 1, row: 5), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); } /** @@ -323,7 +288,6 @@ public function testShouldLocateMultipleWordsWrittenInDifferentHorizontalDirecti #[TestDox('Should locate words written top to bottom')] public function testShouldLocateWordsWrittenTopToBottom(): void { - $wordsToSearchFor = ["clojure", "elixir", "ecmascript"]; $grid = [ "jefblpepre", "camdcimgtc", @@ -335,24 +299,24 @@ public function testShouldLocateWordsWrittenTopToBottom(): void "alxhpburyi", "jalaycalmp", "clojurermt" - ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "elixir" => [ - "start" => ["column" => 6, "row" => 5], - "end" => ["column" => 1, "row" => 5] - ], - "ecmascript" => [ - "start" => ["column" => 10, "row" => 1], - "end" => ["column" => 10, "row" => 10] - ] ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedElixir = new Result( + start: new Location(column: 6, row: 5), + end: new Location(column: 1, row: 5), + ); + $expectedEcmascript = new Result( + start: new Location(column: 10, row: 1), + end: new Location(column: 10, row: 10), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); + $this->assertEquals($expectedEcmascript, $wordSearch->search("ecmascript")); } /** @@ -361,7 +325,6 @@ public function testShouldLocateWordsWrittenTopToBottom(): void #[TestDox('Should locate words written bottom to top')] public function testShouldLocateWordsWrittenBottomToTop(): void { - $wordsToSearchFor = ["clojure", "elixir", "ecmascript", "rust"]; $grid = [ "jefblpepre", "camdcimgtc", @@ -373,28 +336,29 @@ public function testShouldLocateWordsWrittenBottomToTop(): void "alxhpburyi", "jalaycalmp", "clojurermt" - ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "elixir" => [ - "start" => ["column" => 6, "row" => 5], - "end" => ["column" => 1, "row" => 5] - ], - "ecmascript" => [ - "start" => ["column" => 10, "row" => 1], - "end" => ["column" => 10, "row" => 10] - ], - "rust" => [ - "start" => ["column" => 9, "row" => 5], - "end" => ["column" => 9, "row" => 2] - ] ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedElixir = new Result( + start: new Location(column: 6, row: 5), + end: new Location(column: 1, row: 5), + ); + $expectedEcmascript = new Result( + start: new Location(column: 10, row: 1), + end: new Location(column: 10, row: 10), + ); + $expectedRust = new Result( + start: new Location(column: 9, row: 5), + end: new Location(column: 9, row: 2), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); + $this->assertEquals($expectedEcmascript, $wordSearch->search("ecmascript")); + $this->assertEquals($expectedRust, $wordSearch->search("rust")); } /** @@ -403,7 +367,6 @@ public function testShouldLocateWordsWrittenBottomToTop(): void #[TestDox('Should locate words written top left to bottom right')] public function testShouldLocateWordsWrittenTopLeftToBottomRight(): void { - $wordsToSearchFor = ["clojure", "elixir", "ecmascript", "rust", "java"]; $grid = [ "jefblpepre", "camdcimgtc", @@ -415,48 +378,43 @@ public function testShouldLocateWordsWrittenTopLeftToBottomRight(): void "alxhpburyi", "jalaycalmp", "clojurermt" - ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "elixir" => [ - "start" => ["column" => 6, "row" => 5], - "end" => ["column" => 1, "row" => 5] - ], - "ecmascript" => [ - "start" => ["column" => 10, "row" => 1], - "end" => ["column" => 10, "row" => 10] - ], - "rust" => [ - "start" => ["column" => 9, "row" => 5], - "end" => ["column" => 9, "row" => 2] - ], - "java" => [ - "start" => ["column" => 1, "row" => 1], - "end" => ["column" => 4, "row" => 4] - ] ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedElixir = new Result( + start: new Location(column: 6, row: 5), + end: new Location(column: 1, row: 5), + ); + $expectedEcmascript = new Result( + start: new Location(column: 10, row: 1), + end: new Location(column: 10, row: 10), + ); + $expectedRust = new Result( + start: new Location(column: 9, row: 5), + end: new Location(column: 9, row: 2), + ); + $expectedJava = new Result( + start: new Location(column: 1, row: 1), + end: new Location(column: 4, row: 4), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); + $this->assertEquals($expectedEcmascript, $wordSearch->search("ecmascript")); + $this->assertEquals($expectedRust, $wordSearch->search("rust")); + $this->assertEquals($expectedJava, $wordSearch->search("java")); } + /** * uuid: c9125189-1861-4b0d-a14e-ba5dab29ca7c */ #[TestDox('Should locate words written bottom right to top left')] public function testShouldLocateWordsWrittenBottomRightToTopLeft(): void { - $wordsToSearchFor = [ - "clojure", - "elixir", - "ecmascript", - "rust", - "java", - "lua" - ]; $grid = [ "jefblpepre", "camdcimgtc", @@ -468,36 +426,39 @@ public function testShouldLocateWordsWrittenBottomRightToTopLeft(): void "alxhpburyi", "jalaycalmp", "clojurermt" - ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "elixir" => [ - "start" => ["column" => 6, "row" => 5], - "end" => ["column" => 1, "row" => 5] - ], - "ecmascript" => [ - "start" => ["column" => 10, "row" => 1], - "end" => ["column" => 10, "row" => 10] - ], - "rust" => [ - "start" => ["column" => 9, "row" => 5], - "end" => ["column" => 9, "row" => 2] - ], - "java" => [ - "start" => ["column" => 1, "row" => 1], - "end" => ["column" => 4, "row" => 4] - ], - "lua" => [ - "start" => ["column" => 8, "row" => 9], - "end" => ["column" => 6, "row" => 7] - ] ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedElixir = new Result( + start: new Location(column: 6, row: 5), + end: new Location(column: 1, row: 5), + ); + $expectedEcmascript = new Result( + start: new Location(column: 10, row: 1), + end: new Location(column: 10, row: 10), + ); + $expectedRust = new Result( + start: new Location(column: 9, row: 5), + end: new Location(column: 9, row: 2), + ); + $expectedJava = new Result( + start: new Location(column: 1, row: 1), + end: new Location(column: 4, row: 4), + ); + $expectedLua = new Result( + start: new Location(column: 8, row: 9), + end: new Location(column: 6, row: 7), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); + $this->assertEquals($expectedEcmascript, $wordSearch->search("ecmascript")); + $this->assertEquals($expectedRust, $wordSearch->search("rust")); + $this->assertEquals($expectedJava, $wordSearch->search("java")); + $this->assertEquals($expectedLua, $wordSearch->search("lua")); } /** @@ -506,15 +467,6 @@ public function testShouldLocateWordsWrittenBottomRightToTopLeft(): void #[TestDox('Should locate words written bottom left to top right')] public function testShouldLocateWordsWrittenBottomLeftToTopRight(): void { - $wordsToSearchFor = [ - "clojure", - "elixir", - "ecmascript", - "rust", - "java", - "lua", - "lisp" - ]; $grid = [ "jefblpepre", "camdcimgtc", @@ -526,40 +478,44 @@ public function testShouldLocateWordsWrittenBottomLeftToTopRight(): void "alxhpburyi", "jalaycalmp", "clojurermt" - ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "elixir" => [ - "start" => ["column" => 6, "row" => 5], - "end" => ["column" => 1, "row" => 5] - ], - "ecmascript" => [ - "start" => ["column" => 10, "row" => 1], - "end" => ["column" => 10, "row" => 10] - ], - "rust" => [ - "start" => ["column" => 9, "row" => 5], - "end" => ["column" => 9, "row" => 2] - ], - "java" => [ - "start" => ["column" => 1, "row" => 1], - "end" => ["column" => 4, "row" => 4] - ], - "lua" => [ - "start" => ["column" => 8, "row" => 9], - "end" => ["column" => 6, "row" => 7] - ], - "lisp" => [ - "start" => ["column" => 3, "row" => 6], - "end" => ["column" => 6, "row" => 3] - ] ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedElixir = new Result( + start: new Location(column: 6, row: 5), + end: new Location(column: 1, row: 5), + ); + $expectedEcmascript = new Result( + start: new Location(column: 10, row: 1), + end: new Location(column: 10, row: 10), + ); + $expectedRust = new Result( + start: new Location(column: 9, row: 5), + end: new Location(column: 9, row: 2), + ); + $expectedJava = new Result( + start: new Location(column: 1, row: 1), + end: new Location(column: 4, row: 4), + ); + $expectedLua = new Result( + start: new Location(column: 8, row: 9), + end: new Location(column: 6, row: 7), + ); + $expectedLisp = new Result( + start: new Location(column: 3, row: 6), + end: new Location(column: 6, row: 3), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); + $this->assertEquals($expectedEcmascript, $wordSearch->search("ecmascript")); + $this->assertEquals($expectedRust, $wordSearch->search("rust")); + $this->assertEquals($expectedJava, $wordSearch->search("java")); + $this->assertEquals($expectedLua, $wordSearch->search("lua")); + $this->assertEquals($expectedLisp, $wordSearch->search("lisp")); } /** @@ -568,16 +524,6 @@ public function testShouldLocateWordsWrittenBottomLeftToTopRight(): void #[TestDox('Should locate words written top right to bottom left')] public function testShouldLocateWordsWrittenTopRightToBottomLeft(): void { - $wordsToSearchFor = [ - "clojure", - "elixir", - "ecmascript", - "rust", - "java", - "lua", - "lisp", - "ruby" - ]; $grid = [ "jefblpepre", "camdcimgtc", @@ -589,44 +535,49 @@ public function testShouldLocateWordsWrittenTopRightToBottomLeft(): void "alxhpburyi", "jalaycalmp", "clojurermt" - ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "elixir" => [ - "start" => ["column" => 6, "row" => 5], - "end" => ["column" => 1, "row" => 5] - ], - "ecmascript" => [ - "start" => ["column" => 10, "row" => 1], - "end" => ["column" => 10, "row" => 10] - ], - "rust" => [ - "start" => ["column" => 9, "row" => 5], - "end" => ["column" => 9, "row" => 2] - ], - "java" => [ - "start" => ["column" => 1, "row" => 1], - "end" => ["column" => 4, "row" => 4] - ], - "lua" => [ - "start" => ["column" => 8, "row" => 9], - "end" => ["column" => 6, "row" => 7] - ], - "lisp" => [ - "start" => ["column" => 3, "row" => 6], - "end" => ["column" => 6, "row" => 3] - ], - "ruby" => [ - "start" => ["column" => 8, "row" => 6], - "end" => ["column" => 5, "row" => 9] - ] ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedElixir = new Result( + start: new Location(column: 6, row: 5), + end: new Location(column: 1, row: 5), + ); + $expectedEcmascript = new Result( + start: new Location(column: 10, row: 1), + end: new Location(column: 10, row: 10), + ); + $expectedRust = new Result( + start: new Location(column: 9, row: 5), + end: new Location(column: 9, row: 2), + ); + $expectedJava = new Result( + start: new Location(column: 1, row: 1), + end: new Location(column: 4, row: 4), + ); + $expectedLua = new Result( + start: new Location(column: 8, row: 9), + end: new Location(column: 6, row: 7), + ); + $expectedLisp = new Result( + start: new Location(column: 3, row: 6), + end: new Location(column: 6, row: 3), + ); + $expectedRuby = new Result( + start: new Location(column: 8, row: 6), + end: new Location(column: 5, row: 9), + ); $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); + $this->assertEquals($expectedEcmascript, $wordSearch->search("ecmascript")); + $this->assertEquals($expectedRust, $wordSearch->search("rust")); + $this->assertEquals($expectedJava, $wordSearch->search("java")); + $this->assertEquals($expectedLua, $wordSearch->search("lua")); + $this->assertEquals($expectedLisp, $wordSearch->search("lisp")); + $this->assertEquals($expectedRuby, $wordSearch->search("ruby")); } /** @@ -635,17 +586,6 @@ public function testShouldLocateWordsWrittenTopRightToBottomLeft(): void #[TestDox('Should fail to locate a word that is not in the puzzle')] public function testShouldFail(): void { - $wordsToSearchFor = [ - "clojure", - "elixir", - "ecmascript", - "rust", - "java", - "lua", - "lisp", - "ruby", - "haskell" - ]; $grid = [ "jefblpepre", "camdcimgtc", @@ -658,44 +598,50 @@ public function testShouldFail(): void "jalaycalmp", "clojurermt" ]; - $expected = [ - "clojure" => [ - "start" => ["column" => 1, "row" => 10], - "end" => ["column" => 7, "row" => 10] - ], - "elixir" => [ - "start" => ["column" => 6, "row" => 5], - "end" => ["column" => 1, "row" => 5] - ], - "ecmascript" => [ - "start" => ["column" => 10, "row" => 1], - "end" => ["column" => 10, "row" => 10] - ], - "rust" => [ - "start" => ["column" => 9, "row" => 5], - "end" => ["column" => 9, "row" => 2] - ], - "java" => [ - "start" => ["column" => 1, "row" => 1], - "end" => ["column" => 4, "row" => 4] - ], - "lua" => [ - "start" => ["column" => 8, "row" => 9], - "end" => ["column" => 6, "row" => 7] - ], - "lisp" => [ - "start" => ["column" => 3, "row" => 6], - "end" => ["column" => 6, "row" => 3] - ], - "ruby" => [ - "start" => ["column" => 8, "row" => 6], - "end" => ["column" => 5, "row" => 9] - ], - "haskell" => null - ]; + $expectedClojure = new Result( + start: new Location(column: 1, row: 10), + end: new Location(column: 7, row: 10), + ); + $expectedElixir = new Result( + start: new Location(column: 6, row: 5), + end: new Location(column: 1, row: 5), + ); + $expectedEcmascript = new Result( + start: new Location(column: 10, row: 1), + end: new Location(column: 10, row: 10), + ); + $expectedRust = new Result( + start: new Location(column: 9, row: 5), + end: new Location(column: 9, row: 2), + ); + $expectedJava = new Result( + start: new Location(column: 1, row: 1), + end: new Location(column: 4, row: 4), + ); + $expectedLua = new Result( + start: new Location(column: 8, row: 9), + end: new Location(column: 6, row: 7), + ); + $expectedLisp = new Result( + start: new Location(column: 3, row: 6), + end: new Location(column: 6, row: 3), + ); + $expectedRuby = new Result( + start: new Location(column: 8, row: 6), + end: new Location(column: 5, row: 9), + ); + $expectedHaskell = null; $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedClojure, $wordSearch->search("clojure")); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); + $this->assertEquals($expectedEcmascript, $wordSearch->search("ecmascript")); + $this->assertEquals($expectedRust, $wordSearch->search("rust")); + $this->assertEquals($expectedJava, $wordSearch->search("java")); + $this->assertEquals($expectedLua, $wordSearch->search("lua")); + $this->assertEquals($expectedLisp, $wordSearch->search("lisp")); + $this->assertEquals($expectedRuby, $wordSearch->search("ruby")); + $this->assertEquals($expectedHaskell, $wordSearch->search("haskell")); } /** @@ -704,17 +650,17 @@ public function testShouldFail(): void #[TestDox('Should fail to locate words that are not on horizontal, vertical, or diagonal lines')] public function testShouldFailToLocateWordsThatAreNotOnHorizontalVerticalOrDiagonalLines(): void { - $wordsToSearchFor = ["aef", "ced", "abf", "cbd"]; - $grid = ["abc", "def"]; - $expected = [ - "aef" => null, - "ced" => null, - "abf" => null, - "cbd" => null - ]; - $wordSearch = new WordSearch($grid); - - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $grid = ["abc", "def"]; + $expectedAef = null; + $expectedCed = null; + $expectedAbf = null; + $expectedCbd = null; + $wordSearch = new WordSearch($grid); + + $this->assertEquals($expectedAef, $wordSearch->search("aef")); + $this->assertEquals($expectedCed, $wordSearch->search("ced")); + $this->assertEquals($expectedAbf, $wordSearch->search("abf")); + $this->assertEquals($expectedCbd, $wordSearch->search("cbd")); } /** @@ -723,12 +669,11 @@ public function testShouldFailToLocateWordsThatAreNotOnHorizontalVerticalOrDiago #[TestDox('Should not concatenate different lines to find a horizontal word')] public function testShouldNotConcatenateDifferentLinesToFindAHorizontalWord(): void { - $wordsToSearchFor = ["elixir"]; - $grid = ["abceli", "xirdfg"]; - $expected = ["elixir" => null]; - $wordSearch = new WordSearch($grid); + $grid = ["abceli", "xirdfg"]; + $expectedElixir = null; + $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedElixir, $wordSearch->search("elixir")); } /** @@ -737,12 +682,11 @@ public function testShouldNotConcatenateDifferentLinesToFindAHorizontalWord(): v #[TestDox('Should not wrap around horizontally to find a word')] public function testShouldNotWrapAroundHorizontallyToFindAWord(): void { - $wordsToSearchFor = ["lisp"]; - $grid = ["silabcdefp"]; - $expected = ["lisp" => null]; - $wordSearch = new WordSearch($grid); + $grid = ["silabcdefp"]; + $expectedLisp = null; + $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedLisp, $wordSearch->search("lisp")); } /** @@ -751,7 +695,6 @@ public function testShouldNotWrapAroundHorizontallyToFindAWord(): void #[TestDox('Should not wrap around vertically to find a word')] public function testShouldNotWrapAroundVerticallyToFindAWord(): void { - $wordsToSearchFor = ["rust"]; $grid = [ "s", "u", @@ -761,9 +704,9 @@ public function testShouldNotWrapAroundVerticallyToFindAWord(): void "c", "t" ]; - $expected = ["rust" => null]; - $wordSearch = new WordSearch($grid); + $expectedRust = null; + $wordSearch = new WordSearch($grid); - $this->assertEquals($expected, $wordSearch->search($wordsToSearchFor)); + $this->assertEquals($expectedRust, $wordSearch->search("rust")); } } From b189ca3922f0e2832d12508b2823fafdf4643407 Mon Sep 17 00:00:00 2001 From: resu-xuniL Date: Thu, 30 Jul 2026 12:57:25 +0200 Subject: [PATCH 3/3] Apply suggestions from `mk-mxp` --- .../practice/word-search/.meta/config.json | 2 ++ .../practice/word-search/.meta/example.php | 12 +++------ exercises/practice/word-search/Location.php | 27 +++++++++++++++++++ exercises/practice/word-search/Result.php | 27 +++++++++++++++++++ exercises/practice/word-search/WordSearch.php | 22 ++++----------- .../practice/word-search/WordSearchTest.php | 2 ++ 6 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 exercises/practice/word-search/Location.php create mode 100644 exercises/practice/word-search/Result.php diff --git a/exercises/practice/word-search/.meta/config.json b/exercises/practice/word-search/.meta/config.json index c67cfaf96..89cf0640e 100644 --- a/exercises/practice/word-search/.meta/config.json +++ b/exercises/practice/word-search/.meta/config.json @@ -4,6 +4,8 @@ ], "files": { "solution": [ + "Location.php", + "Result.php", "WordSearch.php" ], "test": [ diff --git a/exercises/practice/word-search/.meta/example.php b/exercises/practice/word-search/.meta/example.php index 2368a06b7..30c693a44 100644 --- a/exercises/practice/word-search/.meta/example.php +++ b/exercises/practice/word-search/.meta/example.php @@ -66,20 +66,16 @@ private function findNextLetter(int $X, int $Y): ?string } } -class Result +final readonly class Result { - public function __construct(private Location $start, private Location $end) + public function __construct(private readonly Location $start, private readonly Location $end) { } } -class Location +final readonly class Location { - public function __construct(private int $column, private int $row) + public function __construct(private readonly int $column, private readonly int $row) { - return [ - "column:" => $this->column, - "row:" => $this->row - ]; } } diff --git a/exercises/practice/word-search/Location.php b/exercises/practice/word-search/Location.php new file mode 100644 index 000000000..719bcba11 --- /dev/null +++ b/exercises/practice/word-search/Location.php @@ -0,0 +1,27 @@ +. + * + * To disable strict typing, comment out the directive below. + */ + +declare(strict_types=1); + +// Can you make this data class immutable? diff --git a/exercises/practice/word-search/Result.php b/exercises/practice/word-search/Result.php new file mode 100644 index 000000000..719bcba11 --- /dev/null +++ b/exercises/practice/word-search/Result.php @@ -0,0 +1,27 @@ +. + * + * To disable strict typing, comment out the directive below. + */ + +declare(strict_types=1); + +// Can you make this data class immutable? diff --git a/exercises/practice/word-search/WordSearch.php b/exercises/practice/word-search/WordSearch.php index 8fb378294..d5787f692 100644 --- a/exercises/practice/word-search/WordSearch.php +++ b/exercises/practice/word-search/WordSearch.php @@ -26,9 +26,13 @@ class WordSearch { + // This exercises uses additional files for data classes. + // In the online editor these are available as additional + // tabs next to this file's tab. + public function __construct(array $grid) { - throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); + throw new \BadMethodCallException(sprintf('Implement the WordSearch %s method', __FUNCTION__)); } public function search(string $word): ?Result @@ -36,19 +40,3 @@ public function search(string $word): ?Result throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); } } - -class Result -{ - public function __construct(Location $start, Location $end) - { - throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); - } -} - -class Location -{ - public function __construct(int $column, int $row) - { - throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); - } -} diff --git a/exercises/practice/word-search/WordSearchTest.php b/exercises/practice/word-search/WordSearchTest.php index 20f66fe44..bfac4bf1c 100644 --- a/exercises/practice/word-search/WordSearchTest.php +++ b/exercises/practice/word-search/WordSearchTest.php @@ -9,6 +9,8 @@ class WordSearchTest extends TestCase { public static function setUpBeforeClass(): void { + require_once 'Location.php'; + require_once 'Result.php'; require_once 'WordSearch.php'; }