From c16e8beea3652fa09436c4ecd60cd3e789f4f5cc Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Wed, 26 Jun 2024 22:10:21 +1000 Subject: [PATCH] Add minesweeper exercise --- config.json | 8 + .../minesweeper/.docs/instructions.md | 26 +++ .../minesweeper/.docs/introduction.md | 5 + .../practice/minesweeper/.meta/config.json | 17 ++ .../practice/minesweeper/.meta/tests.toml | 46 +++++ exercises/practice/minesweeper/dub.sdl | 2 + .../minesweeper/example/minesweeper.d | 49 +++++ .../practice/minesweeper/source/minesweeper.d | 194 ++++++++++++++++++ 8 files changed, 347 insertions(+) create mode 100644 exercises/practice/minesweeper/.docs/instructions.md create mode 100644 exercises/practice/minesweeper/.docs/introduction.md create mode 100644 exercises/practice/minesweeper/.meta/config.json create mode 100644 exercises/practice/minesweeper/.meta/tests.toml create mode 100644 exercises/practice/minesweeper/dub.sdl create mode 100644 exercises/practice/minesweeper/example/minesweeper.d create mode 100644 exercises/practice/minesweeper/source/minesweeper.d diff --git a/config.json b/config.json index e9c5dac..65686e3 100644 --- a/config.json +++ b/config.json @@ -570,6 +570,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "minesweeper", + "name": "Minesweeper", + "uuid": "42f82a28-3ab5-450b-9a38-27ce6e180f59", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "pythagorean-triplet", "name": "Pythagorean Triplet", diff --git a/exercises/practice/minesweeper/.docs/instructions.md b/exercises/practice/minesweeper/.docs/instructions.md new file mode 100644 index 0000000..7c1df2e --- /dev/null +++ b/exercises/practice/minesweeper/.docs/instructions.md @@ -0,0 +1,26 @@ +# Instructions + +Your task is to add the mine counts to empty squares in a completed Minesweeper board. +The board itself is a rectangle composed of squares that are either empty (`' '`) or a mine (`'*'`). + +For each empty square, count the number of mines adjacent to it (horizontally, vertically, diagonally). +If the empty square has no adjacent mines, leave it empty. +Otherwise replace it with the adjacent mines count. + +For example, you may receive a 5 x 4 board like this (empty spaces are represented here with the '·' character for display on screen): + +```text +·*·*· +··*·· +··*·· +····· +``` + +Which your code should transform into this: + +```text +1*3*1 +13*31 +·2*2· +·111· +``` diff --git a/exercises/practice/minesweeper/.docs/introduction.md b/exercises/practice/minesweeper/.docs/introduction.md new file mode 100644 index 0000000..5f74a74 --- /dev/null +++ b/exercises/practice/minesweeper/.docs/introduction.md @@ -0,0 +1,5 @@ +# Introduction + +[Minesweeper][wikipedia] is a popular game where the user has to find the mines using numeric hints that indicate how many mines are directly adjacent (horizontally, vertically, diagonally) to a square. + +[wikipedia]: https://en.wikipedia.org/wiki/Minesweeper_(video_game) diff --git a/exercises/practice/minesweeper/.meta/config.json b/exercises/practice/minesweeper/.meta/config.json new file mode 100644 index 0000000..6aee79f --- /dev/null +++ b/exercises/practice/minesweeper/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "source/minesweeper.d" + ], + "test": [ + "source/minesweeper.d" + ], + "example": [ + "example/minesweeper.d" + ] + }, + "blurb": "Add the numbers to a minesweeper board." +} diff --git a/exercises/practice/minesweeper/.meta/tests.toml b/exercises/practice/minesweeper/.meta/tests.toml new file mode 100644 index 0000000..2a14222 --- /dev/null +++ b/exercises/practice/minesweeper/.meta/tests.toml @@ -0,0 +1,46 @@ +# 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. + +[0c5ec4bd-dea7-4138-8651-1203e1cb9f44] +description = "no rows" + +[650ac4c0-ad6b-4b41-acde-e4ea5852c3b8] +description = "no columns" + +[6fbf8f6d-a03b-42c9-9a58-b489e9235478] +description = "no mines" + +[61aff1c4-fb31-4078-acad-cd5f1e635655] +description = "minefield with only mines" + +[84167147-c504-4896-85d7-246b01dea7c5] +description = "mine surrounded by spaces" + +[cb878f35-43e3-4c9d-93d9-139012cccc4a] +description = "space surrounded by mines" + +[7037f483-ddb4-4b35-b005-0d0f4ef4606f] +description = "horizontal line" + +[e359820f-bb8b-4eda-8762-47b64dba30a6] +description = "horizontal line, mines at edges" + +[c5198b50-804f-47e9-ae02-c3b42f7ce3ab] +description = "vertical line" + +[0c79a64d-703d-4660-9e90-5adfa5408939] +description = "vertical line, mines at edges" + +[4b098563-b7f3-401c-97c6-79dd1b708f34] +description = "cross" + +[04a260f1-b40a-4e89-839e-8dd8525abe0e] +description = "large minefield" diff --git a/exercises/practice/minesweeper/dub.sdl b/exercises/practice/minesweeper/dub.sdl new file mode 100644 index 0000000..3a3540c --- /dev/null +++ b/exercises/practice/minesweeper/dub.sdl @@ -0,0 +1,2 @@ +name "minesweeper" +buildRequirements "disallowDeprecations" diff --git a/exercises/practice/minesweeper/example/minesweeper.d b/exercises/practice/minesweeper/example/minesweeper.d new file mode 100644 index 0000000..26dd094 --- /dev/null +++ b/exercises/practice/minesweeper/example/minesweeper.d @@ -0,0 +1,49 @@ +module minesweeper; + +import std.algorithm : max, min; + +pure string[] annotate(immutable string[] minefield) +{ + string[] result; + size_t numRows = minefield.length; + if (numRows == 0) + { + return result; + } + size_t numColumns = minefield[0].length; + result.length = numRows; + for (size_t row = 0; row < numRows; ++row) + { + string line; + for (size_t column = 0; column < numColumns; ++column) + { + if (minefield[row][column] == '*') + { + line ~= '*'; + continue; + } + char count = 0; + for (size_t r = max(1, row) - 1; r < min(numRows, row + 2); ++r) + { + for (size_t c = max(1, column) - 1; c < min(numColumns, column + 2); ++c) + { + if (minefield[r][c] == '*') + { + ++count; + } + } + } + + if (count > 0) + { + line ~= '0' + count; + } + else + { + line ~= ' '; + } + } + result[row] = line; + } + return result; +} diff --git a/exercises/practice/minesweeper/source/minesweeper.d b/exercises/practice/minesweeper/source/minesweeper.d new file mode 100644 index 0000000..2ed71e2 --- /dev/null +++ b/exercises/practice/minesweeper/source/minesweeper.d @@ -0,0 +1,194 @@ +module minesweeper; + +pure string[] annotate(immutable string[] minefield) +{ + // implement this function +} + +unittest +{ + immutable int allTestsEnabled = 0; + + // No rows + { + immutable string[] minefield = [ + ]; + string[] expected = [ + ]; + assert(annotate(minefield) == expected); + } + + static if (allTestsEnabled) + { + // No columns + { + immutable string[] minefield = [ + "", + ]; + string[] expected = [ + "", + ]; + assert(annotate(minefield) == expected); + } + + // No mines + { + immutable string[] minefield = [ + " ", + " ", + " ", + ]; + string[] expected = [ + " ", + " ", + " ", + ]; + assert(annotate(minefield) == expected); + } + + // Minefield with only mines + { + immutable string[] minefield = [ + "***", + "***", + "***", + ]; + string[] expected = [ + "***", + "***", + "***", + ]; + assert(annotate(minefield) == expected); + } + + // Mine surrounded by spaces + { + immutable string[] minefield = [ + " ", + " * ", + " ", + ]; + string[] expected = [ + "111", + "1*1", + "111", + ]; + assert(annotate(minefield) == expected); + } + + // Space surrounded by mines + { + immutable string[] minefield = [ + "***", + "* *", + "***", + ]; + string[] expected = [ + "***", + "*8*", + "***", + ]; + assert(annotate(minefield) == expected); + } + + // Horizontal line + { + immutable string[] minefield = [ + " * * ", + ]; + string[] expected = [ + "1*2*1", + ]; + assert(annotate(minefield) == expected); + } + + // Horizontal line, mines at edges + { + immutable string[] minefield = [ + "* *", + ]; + string[] expected = [ + "*1 1*", + ]; + assert(annotate(minefield) == expected); + } + + // Vertical line + { + immutable string[] minefield = [ + " ", + "*", + " ", + "*", + " ", + ]; + string[] expected = [ + "1", + "*", + "2", + "*", + "1", + ]; + assert(annotate(minefield) == expected); + } + + // Vertical line, mines at edges + { + immutable string[] minefield = [ + "*", + " ", + " ", + " ", + "*", + ]; + string[] expected = [ + "*", + "1", + " ", + "1", + "*", + ]; + assert(annotate(minefield) == expected); + } + + // Cross + { + immutable string[] minefield = [ + " * ", + " * ", + "*****", + " * ", + " * ", + ]; + string[] expected = [ + " 2*2 ", + "25*52", + "*****", + "25*52", + " 2*2 ", + ]; + assert(annotate(minefield) == expected); + } + + // Large minefield + { + immutable string[] minefield = [ + " * * ", + " * ", + " * ", + " * *", + " * * ", + " ", + ]; + string[] expected = [ + "1*22*1", + "12*322", + " 123*2", + "112*4*", + "1*22*2", + "111111", + ]; + assert(annotate(minefield) == expected); + } + } +}