From d86688a946989daefaed2f5b03e86d7ff4280894 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sat, 5 Jul 2025 09:00:35 +1000 Subject: [PATCH] flower-field replaces minesweeper --- .github/workflows/tests.yml | 2 +- config.json | 84 +++++++++---------- .../flower-field/.docs/instructions.md | 26 ++++++ .../flower-field/.docs/introduction.md | 7 ++ .../practice/flower-field/.meta/config.json | 33 ++++++++ .../examples/success-standard/package.yaml | 16 ++++ .../success-standard/src/FlowerField.hs | 25 ++++++ .../practice/flower-field/.meta/tests.toml | 46 ++++++++++ exercises/practice/flower-field/package.yaml | 21 +++++ .../practice/flower-field/src/FlowerField.hs | 4 + exercises/practice/flower-field/stack.yaml | 1 + exercises/practice/flower-field/test/Tests.hs | 69 +++++++++++++++ 12 files changed, 289 insertions(+), 45 deletions(-) create mode 100644 exercises/practice/flower-field/.docs/instructions.md create mode 100644 exercises/practice/flower-field/.docs/introduction.md create mode 100644 exercises/practice/flower-field/.meta/config.json create mode 100644 exercises/practice/flower-field/.meta/examples/success-standard/package.yaml create mode 100644 exercises/practice/flower-field/.meta/examples/success-standard/src/FlowerField.hs create mode 100644 exercises/practice/flower-field/.meta/tests.toml create mode 100644 exercises/practice/flower-field/package.yaml create mode 100644 exercises/practice/flower-field/src/FlowerField.hs create mode 100644 exercises/practice/flower-field/stack.yaml create mode 100644 exercises/practice/flower-field/test/Tests.hs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1b4c414e1..61a0491f4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -95,7 +95,7 @@ jobs: # most of the time caches should hit. echo "::set-output name=week-no::$(date -u +%Y-%U)" - - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 + - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 id: cache with: path: | diff --git a/config.json b/config.json index 145ade90f..a6a03145e 100644 --- a/config.json +++ b/config.json @@ -42,60 +42,60 @@ "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "3aa220cb-606f-45c5-9b7a-4bce0e4eb20d", - "prerequisites": [], - "status": "beta", "concepts": [ "basics" - ] + ], + "prerequisites": [], + "status": "beta" }, { "slug": "temperature", "name": "Temperature", "uuid": "6ed15adb-f022-4bbd-bbb3-22845deabc91", + "concepts": [ + "numbers" + ], "prerequisites": [ "basics" ], - "status": "beta", - "concepts": [ - "numbers" - ] + "status": "beta" }, { "slug": "pacman-rules", "name": "Pac-Man Rules", "uuid": "9050f8c3-9976-4c4d-93e7-c9c549b1c524", + "concepts": [ + "booleans" + ], "prerequisites": [ "basics" ], - "status": "wip", - "concepts": [ - "booleans" - ] + "status": "wip" }, { "slug": "guessing-game", "name": "Guessing Game", "uuid": "fb9868eb-ce4f-4e6b-aa0d-b47d3451070f", + "concepts": [ + "pattern-matching-literals" + ], "prerequisites": [ "numbers" ], - "status": "beta", - "concepts": [ - "pattern-matching-literals" - ] + "status": "beta" }, { "slug": "valentines-day", "name": "Valentines Day", "uuid": "537d8df3-0b12-4dbe-aa86-65ae79c4de0e", + "concepts": [ + "algebraic-data-types" + ], "prerequisites": [ "pattern-matching-literals", "numbers" ], - "status": "beta", - "concepts": [ - "algebraic-data-types" - ] + "status": "beta" } ], "practice": [ @@ -297,8 +297,7 @@ "uuid": "dde7cf64-7e3b-4e5c-8a65-5d639fa8a307", "practices": [], "prerequisites": [], - "difficulty": 5, - "topics": [] + "difficulty": 5 }, { "slug": "luhn", @@ -325,6 +324,14 @@ "number_theory" ] }, + { + "slug": "flower-field", + "name": "Flower Field", + "uuid": "1eff202c-ef0c-43d2-9077-7837914bc8b0", + "practices": [], + "prerequisites": [], + "difficulty": 7 + }, { "slug": "minesweeper", "name": "Minesweeper", @@ -332,7 +339,7 @@ "practices": [], "prerequisites": [], "difficulty": 7, - "topics": [] + "status": "deprecated" }, { "slug": "game-of-life", @@ -340,8 +347,7 @@ "uuid": "eb221634-15c6-463c-8268-54a3c3aa0c66", "practices": [], "prerequisites": [], - "difficulty": 7, - "topics": [] + "difficulty": 7 }, { "slug": "perfect-numbers", @@ -496,8 +502,7 @@ "uuid": "00b6c83b-e652-4f71-a094-b3034f77fd7b", "practices": [], "prerequisites": [], - "difficulty": 4, - "topics": [] + "difficulty": 4 }, { "slug": "food-chain", @@ -868,8 +873,7 @@ "uuid": "01401d15-6667-4f94-bcd2-ec5a70df1cc6", "practices": [], "prerequisites": [], - "difficulty": 4, - "topics": [] + "difficulty": 4 }, { "slug": "sieve", @@ -926,8 +930,7 @@ "uuid": "78971281-153d-4bdc-8f90-4b7eded2b201", "practices": [], "prerequisites": [], - "difficulty": 8, - "topics": [] + "difficulty": 8 }, { "slug": "pov", @@ -1042,8 +1045,7 @@ "uuid": "f49d76f7-f826-4b6a-a514-47af7e84144a", "practices": [], "prerequisites": [], - "difficulty": 6, - "topics": [] + "difficulty": 6 }, { "slug": "sgf-parsing", @@ -1097,8 +1099,7 @@ "uuid": "7157a846-5846-47a4-97c2-daad7f763512", "practices": [], "prerequisites": [], - "difficulty": 3, - "topics": [] + "difficulty": 3 }, { "slug": "roman-numerals", @@ -1302,7 +1303,6 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": null, "status": "deprecated" }, { @@ -1312,7 +1312,6 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": null, "status": "deprecated" }, { @@ -1322,7 +1321,6 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": null, "status": "deprecated" }, { @@ -1332,7 +1330,6 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": null, "status": "deprecated" }, { @@ -1342,7 +1339,6 @@ "practices": [], "prerequisites": [], "difficulty": 1, - "topics": null, "status": "deprecated" }, { @@ -1443,15 +1439,15 @@ } ], "tags": [ + "execution_mode/compiled", "paradigm/declarative", "paradigm/functional", - "typing/static", - "typing/strong", - "execution_mode/compiled", - "platform/windows", - "platform/mac", "platform/linux", + "platform/mac", + "platform/windows", "runtime/standalone_executable", + "typing/static", + "typing/strong", "used_for/backends", "used_for/financial_systems" ] diff --git a/exercises/practice/flower-field/.docs/instructions.md b/exercises/practice/flower-field/.docs/instructions.md new file mode 100644 index 000000000..bbdae0c2c --- /dev/null +++ b/exercises/practice/flower-field/.docs/instructions.md @@ -0,0 +1,26 @@ +# Instructions + +Your task is to add flower counts to empty squares in a completed Flower Field garden. +The garden itself is a rectangle board composed of squares that are either empty (`' '`) or a flower (`'*'`). + +For each empty square, count the number of flowers adjacent to it (horizontally, vertically, diagonally). +If the empty square has no adjacent flowers, leave it empty. +Otherwise replace it with the count of adjacent flowers. + +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/flower-field/.docs/introduction.md b/exercises/practice/flower-field/.docs/introduction.md new file mode 100644 index 000000000..af9b61536 --- /dev/null +++ b/exercises/practice/flower-field/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +[Flower Field][history] is a compassionate reimagining of the popular game Minesweeper. +The object of the game is to find all the flowers in the garden using numeric hints that indicate how many flowers are directly adjacent (horizontally, vertically, diagonally) to a square. +"Flower Field" shipped in regional versions of Microsoft Windows in Italy, Germany, South Korea, Japan and Taiwan. + +[history]: https://web.archive.org/web/20020409051321fw_/http://rcm.usr.dsi.unimi.it/rcmweb/fnm/ diff --git a/exercises/practice/flower-field/.meta/config.json b/exercises/practice/flower-field/.meta/config.json new file mode 100644 index 000000000..365d5490f --- /dev/null +++ b/exercises/practice/flower-field/.meta/config.json @@ -0,0 +1,33 @@ +{ + "authors": [ + "etrepum" + ], + "contributors": [ + "ffflorian", + "iHiD", + "keiravillekode", + "kytrinyx", + "lpalma", + "petertseng", + "ppartarr", + "rbasso", + "sshine", + "tejasbubane" + ], + "files": { + "solution": [ + "src/FlowerField.hs", + "package.yaml" + ], + "test": [ + "test/Tests.hs" + ], + "example": [ + ".meta/examples/success-standard/src/FlowerField.hs" + ], + "invalidator": [ + "stack.yaml" + ] + }, + "blurb": "Mark all the flowers in a garden." +} diff --git a/exercises/practice/flower-field/.meta/examples/success-standard/package.yaml b/exercises/practice/flower-field/.meta/examples/success-standard/package.yaml new file mode 100644 index 000000000..7eebccbed --- /dev/null +++ b/exercises/practice/flower-field/.meta/examples/success-standard/package.yaml @@ -0,0 +1,16 @@ +name: flower-field + +dependencies: + - base + +library: + exposed-modules: FlowerField + source-dirs: src + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - flower-field + - hspec diff --git a/exercises/practice/flower-field/.meta/examples/success-standard/src/FlowerField.hs b/exercises/practice/flower-field/.meta/examples/success-standard/src/FlowerField.hs new file mode 100644 index 000000000..4b22390ae --- /dev/null +++ b/exercises/practice/flower-field/.meta/examples/success-standard/src/FlowerField.hs @@ -0,0 +1,25 @@ +module FlowerField (annotate) where + +import Data.Char (intToDigit) +import Data.Maybe (mapMaybe) + +annotate :: [String] -> [String] +annotate xss = [[ fixTile x (i, j) + | (j, x ) <- zip [0..] xs ] + | (i, xs) <- zip [0..] xss ] + where + + flowers = length . filter (== '*') . mapMaybe (`lookup` tiles) . neighbors + + fixTile ' ' position = case flowers position of + 0 -> ' ' + x -> intToDigit x + fixTile x _ = x + + neighbors (i, j) = [ (i - 1, j - 1), (i - 1, j), (i - 1, j + 1) + , (i , j - 1), (i , j + 1) + , (i + 1, j - 1), (i + 1, j), (i + 1, j + 1) ] + + tiles = [ ((i, j), x) + | (i, xs) <- zip [0 :: Int ..] xss + , (j, x ) <- zip [0 :: Int ..] xs ] diff --git a/exercises/practice/flower-field/.meta/tests.toml b/exercises/practice/flower-field/.meta/tests.toml new file mode 100644 index 000000000..c2b24fdaf --- /dev/null +++ b/exercises/practice/flower-field/.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. + +[237ff487-467a-47e1-9b01-8a891844f86c] +description = "no rows" + +[4b4134ec-e20f-439c-a295-664c38950ba1] +description = "no columns" + +[d774d054-bbad-4867-88ae-069cbd1c4f92] +description = "no flowers" + +[225176a0-725e-43cd-aa13-9dced501f16e] +description = "garden full of flowers" + +[3f345495-f1a5-4132-8411-74bd7ca08c49] +description = "flower surrounded by spaces" + +[6cb04070-4199-4ef7-a6fa-92f68c660fca] +description = "space surrounded by flowers" + +[272d2306-9f62-44fe-8ab5-6b0f43a26338] +description = "horizontal line" + +[c6f0a4b2-58d0-4bf6-ad8d-ccf4144f1f8e] +description = "horizontal line, flowers at edges" + +[a54e84b7-3b25-44a8-b8cf-1753c8bb4cf5] +description = "vertical line" + +[b40f42f5-dec5-4abc-b167-3f08195189c1] +description = "vertical line, flowers at edges" + +[58674965-7b42-4818-b930-0215062d543c] +description = "cross" + +[dd9d4ca8-9e68-4f78-a677-a2a70fd7a7b8] +description = "large garden" diff --git a/exercises/practice/flower-field/package.yaml b/exercises/practice/flower-field/package.yaml new file mode 100644 index 000000000..d526dad15 --- /dev/null +++ b/exercises/practice/flower-field/package.yaml @@ -0,0 +1,21 @@ +name: flower-field +version: 1.1.0.5 + +dependencies: + - base + +library: + exposed-modules: FlowerField + source-dirs: src + ghc-options: -Wall + # dependencies: + # - foo # List here the packages you + # - bar # want to use in your solution. + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - flower-field + - hspec diff --git a/exercises/practice/flower-field/src/FlowerField.hs b/exercises/practice/flower-field/src/FlowerField.hs new file mode 100644 index 000000000..62ac83f64 --- /dev/null +++ b/exercises/practice/flower-field/src/FlowerField.hs @@ -0,0 +1,4 @@ +module FlowerField (annotate) where + +annotate :: [String] -> [String] +annotate board = error "You need to implement this function." diff --git a/exercises/practice/flower-field/stack.yaml b/exercises/practice/flower-field/stack.yaml new file mode 100644 index 000000000..115878212 --- /dev/null +++ b/exercises/practice/flower-field/stack.yaml @@ -0,0 +1 @@ +resolver: lts-20.18 diff --git a/exercises/practice/flower-field/test/Tests.hs b/exercises/practice/flower-field/test/Tests.hs new file mode 100644 index 000000000..f2ebf263e --- /dev/null +++ b/exercises/practice/flower-field/test/Tests.hs @@ -0,0 +1,69 @@ +import Data.Foldable (for_) +import Test.Hspec (Spec, describe, it, shouldBe) +import Test.Hspec.Runner (configFailFast, defaultConfig, hspecWith) + +import FlowerField (annotate) + +main :: IO () +main = hspecWith defaultConfig {configFailFast = True} specs + +specs :: Spec +specs = describe "annotate" $ for_ cases test + where + + test (description, board) = it description assertion + where + assertion = annotate (clearBoard board) `shouldBe` board + clearBoard = map (map flowerOrSpace) + flowerOrSpace '*' = '*' + flowerOrSpace _ = ' ' + + cases = [ ("no rows", [] ) + + , ("no columns", [ "" ] ) + + , ("no flowers", [ " " + , " " + , " " ] ) + + , ("board with only flowers", [ "***" + , "***" + , "***" ] ) + + , ("flower surrounded by spaces", [ "111" + , "1*1" + , "111" ] ) + + , ("space surrounded by flowers", [ "***" + , "*8*" + , "***" ] ) + + , ("horizontal line", [ "1*2*1" ] ) + + , ("horizontal line, flowers at edges", [ "*1 1*" ] ) + + , ("vertical line", [ "1" + , "*" + , "2" + , "*" + , "1" ] ) + + , ("vertical line, flowers at edges", [ "*" + , "1" + , " " + , "1" + , "*" ] ) + + , ("cross", [ " 2*2 " + , "25*52" + , "*****" + , "25*52" + , " 2*2 " ] ) + + , ("large board", [ "1*22*1" + , "12*322" + , " 123*2" + , "112*4*" + , "1*22*2" + , "111111" ] ) + ]