From a090730b88ac2db4481fb7b0999dba5c7a5cf6eb Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 21 Jan 2025 17:04:13 +0100 Subject: [PATCH] Add `game-of-life` exercise --- config.json | 11 ++ .../game-of-life/.docs/instructions.md | 11 ++ .../game-of-life/.docs/introduction.md | 9 ++ .../practice/game-of-life/.meta/config.json | 19 ++++ .../practice/game-of-life/.meta/example.clj | 25 +++++ .../practice/game-of-life/.meta/generator.tpl | 17 +++ .../practice/game-of-life/.meta/tests.toml | 34 ++++++ exercises/practice/game-of-life/deps.edn | 6 + exercises/practice/game-of-life/project.clj | 4 + .../game-of-life/src/game_of_life.clj | 7 ++ .../game-of-life/test/game_of_life_test.clj | 105 ++++++++++++++++++ 11 files changed, 248 insertions(+) create mode 100644 exercises/practice/game-of-life/.docs/instructions.md create mode 100644 exercises/practice/game-of-life/.docs/introduction.md create mode 100644 exercises/practice/game-of-life/.meta/config.json create mode 100644 exercises/practice/game-of-life/.meta/example.clj create mode 100644 exercises/practice/game-of-life/.meta/generator.tpl create mode 100644 exercises/practice/game-of-life/.meta/tests.toml create mode 100644 exercises/practice/game-of-life/deps.edn create mode 100644 exercises/practice/game-of-life/project.clj create mode 100644 exercises/practice/game-of-life/src/game_of_life.clj create mode 100644 exercises/practice/game-of-life/test/game_of_life_test.clj diff --git a/config.json b/config.json index 6e4f43649..d722d1e80 100644 --- a/config.json +++ b/config.json @@ -1383,6 +1383,17 @@ ], "difficulty": 5 }, + { + "slug": "game-of-life", + "name": "Conway's Game of Life", + "uuid": "136eef87-a87b-4f3e-b587-6f45b4e96d6e", + "practices": [], + "prerequisites": [ + "vectors", + "numbers" + ], + "difficulty": 5 + }, { "slug": "wordy", "name": "Wordy", diff --git a/exercises/practice/game-of-life/.docs/instructions.md b/exercises/practice/game-of-life/.docs/instructions.md new file mode 100644 index 000000000..495314064 --- /dev/null +++ b/exercises/practice/game-of-life/.docs/instructions.md @@ -0,0 +1,11 @@ +# Instructions + +After each generation, the cells interact with their eight neighbors, which are cells adjacent horizontally, vertically, or diagonally. + +The following rules are applied to each cell: + +- Any live cell with two or three live neighbors lives on. +- Any dead cell with exactly three live neighbors becomes a live cell. +- All other cells die or stay dead. + +Given a matrix of 1s and 0s (corresponding to live and dead cells), apply the rules to each cell, and return the next generation. diff --git a/exercises/practice/game-of-life/.docs/introduction.md b/exercises/practice/game-of-life/.docs/introduction.md new file mode 100644 index 000000000..2347b936e --- /dev/null +++ b/exercises/practice/game-of-life/.docs/introduction.md @@ -0,0 +1,9 @@ +# Introduction + +[Conway's Game of Life][game-of-life] is a fascinating cellular automaton created by the British mathematician John Horton Conway in 1970. + +The game consists of a two-dimensional grid of cells that can either be "alive" or "dead." + +After each generation, the cells interact with their eight neighbors via a set of rules, which define the new generation. + +[game-of-life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life diff --git a/exercises/practice/game-of-life/.meta/config.json b/exercises/practice/game-of-life/.meta/config.json new file mode 100644 index 000000000..648fc36a4 --- /dev/null +++ b/exercises/practice/game-of-life/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "erikschierboom" + ], + "files": { + "solution": [ + "src/game_of_life.clj" + ], + "test": [ + "test/game_of_life_test.clj" + ], + "example": [ + ".meta/example.clj" + ] + }, + "blurb": "Implement Conway's Game of Life.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life" +} diff --git a/exercises/practice/game-of-life/.meta/example.clj b/exercises/practice/game-of-life/.meta/example.clj new file mode 100644 index 000000000..94f04f7ff --- /dev/null +++ b/exercises/practice/game-of-life/.meta/example.clj @@ -0,0 +1,25 @@ +(ns game-of-life) + +(defn live-neighbors-count [matrix y x] + (->> (for [dy [-1 0 1] dx [-1 0 1] + :when (not (and (= dy 0) (= dx 0)))] + (get-in matrix [(+ y dy) (+ x dx)] 0)) + (apply +))) + +(defn next-generation [cell neighbors-count] + (if + (or (= 3 neighbors-count) + (and (= 2 neighbors-count) (= 1 cell))) + 1 + 0)) + +(defn tick [matrix] + (mapv + (fn [y row] + (mapv + (fn [x cell] (next-generation cell (live-neighbors-count matrix y x))) + (range) + row)) + (range) + matrix)) + \ No newline at end of file diff --git a/exercises/practice/game-of-life/.meta/generator.tpl b/exercises/practice/game-of-life/.meta/generator.tpl new file mode 100644 index 000000000..97de0767a --- /dev/null +++ b/exercises/practice/game-of-life/.meta/generator.tpl @@ -0,0 +1,17 @@ +(ns game-of-life-test + (:require [clojure.test :refer [deftest testing is]] + game-of-life)) + +{{#test_cases.tick}} +(deftest tick_test_{{idx}} + (testing {{description}} + (is + (= + [{{#expected~}} + {{.}} + {{/expected}}] + (game-of-life/tick + [{{#input.matrix~}} + {{.}} + {{/input.matrix}}]))))) +{{/test_cases.tick}} diff --git a/exercises/practice/game-of-life/.meta/tests.toml b/exercises/practice/game-of-life/.meta/tests.toml new file mode 100644 index 000000000..398cd4546 --- /dev/null +++ b/exercises/practice/game-of-life/.meta/tests.toml @@ -0,0 +1,34 @@ +# 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. + +[ae86ea7d-bd07-4357-90b3-ac7d256bd5c5] +description = "empty matrix" + +[4ea5ccb7-7b73-4281-954a-bed1b0f139a5] +description = "live cells with zero live neighbors die" + +[df245adc-14ff-4f9c-b2ae-f465ef5321b2] +description = "live cells with only one live neighbor die" + +[2a713b56-283c-48c8-adae-1d21306c80ae] +description = "live cells with two live neighbors stay alive" + +[86d5c5a5-ab7b-41a1-8907-c9b3fc5e9dae] +description = "live cells with three live neighbors stay alive" + +[015f60ac-39d8-4c6c-8328-57f334fc9f89] +description = "dead cells with three live neighbors become alive" + +[2ee69c00-9d41-4b8b-89da-5832e735ccf1] +description = "live cells with four or more neighbors die" + +[a79b42be-ed6c-4e27-9206-43da08697ef6] +description = "bigger matrix" diff --git a/exercises/practice/game-of-life/deps.edn b/exercises/practice/game-of-life/deps.edn new file mode 100644 index 000000000..561c3e2da --- /dev/null +++ b/exercises/practice/game-of-life/deps.edn @@ -0,0 +1,6 @@ +{:aliases {:test {:extra-paths ["test"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/url "https://github.com/cognitect-labs/test-runner.git" + :sha "705ad25bbf0228b1c38d0244a36001c2987d7337"}} + :main-opts ["-m" "cognitect.test-runner"] + :exec-fn cognitect.test-runner.api/test}}} \ No newline at end of file diff --git a/exercises/practice/game-of-life/project.clj b/exercises/practice/game-of-life/project.clj new file mode 100644 index 000000000..54e955f6f --- /dev/null +++ b/exercises/practice/game-of-life/project.clj @@ -0,0 +1,4 @@ +(defproject game-of-life "0.1.0-SNAPSHOT" + :description "game-of-life exercise." + :url "https://github.com/exercism/clojure/tree/main/exercises/practice/game-of-life" + :dependencies [[org.clojure/clojure "1.11.1"]]) diff --git a/exercises/practice/game-of-life/src/game_of_life.clj b/exercises/practice/game-of-life/src/game_of_life.clj new file mode 100644 index 000000000..a30a39eb7 --- /dev/null +++ b/exercises/practice/game-of-life/src/game_of_life.clj @@ -0,0 +1,7 @@ +(ns game-of-life) + +(defn tick + "Return the next generation of the given matrix." + [matrix] + ;; function body + ) \ No newline at end of file diff --git a/exercises/practice/game-of-life/test/game_of_life_test.clj b/exercises/practice/game-of-life/test/game_of_life_test.clj new file mode 100644 index 000000000..17826f957 --- /dev/null +++ b/exercises/practice/game-of-life/test/game_of_life_test.clj @@ -0,0 +1,105 @@ +(ns game-of-life-test + (:require [clojure.test :refer [deftest testing is]] + game-of-life)) + +(deftest tick_test_1 + (testing "empty matrix" + (is + (= + [] + (game-of-life/tick + []))))) + +(deftest tick_test_2 + (testing "live cells with zero live neighbors die" + (is + (= + [[0 0 0] + [0 0 0] + [0 0 0]] + (game-of-life/tick + [[0 0 0] + [0 1 0] + [0 0 0]]))))) + +(deftest tick_test_3 + (testing "live cells with only one live neighbor die" + (is + (= + [[0 0 0] + [0 0 0] + [0 0 0]] + (game-of-life/tick + [[0 0 0] + [0 1 0] + [0 1 0]]))))) + +(deftest tick_test_4 + (testing "live cells with two live neighbors stay alive" + (is + (= + [[0 0 0] + [1 0 1] + [0 0 0]] + (game-of-life/tick + [[1 0 1] + [1 0 1] + [1 0 1]]))))) + +(deftest tick_test_5 + (testing "live cells with three live neighbors stay alive" + (is + (= + [[0 0 0] + [1 0 0] + [1 1 0]] + (game-of-life/tick + [[0 1 0] + [1 0 0] + [1 1 0]]))))) + +(deftest tick_test_6 + (testing "dead cells with three live neighbors become alive" + (is + (= + [[0 0 0] + [1 1 0] + [0 0 0]] + (game-of-life/tick + [[1 1 0] + [0 0 0] + [1 0 0]]))))) + +(deftest tick_test_7 + (testing "live cells with four or more neighbors die" + (is + (= + [[1 0 1] + [0 0 0] + [1 0 1]] + (game-of-life/tick + [[1 1 1] + [1 1 1] + [1 1 1]]))))) + +(deftest tick_test_8 + (testing "bigger matrix" + (is + (= + [[1 1 0 1 1 0 0 0] + [0 0 0 0 0 1 1 0] + [1 0 1 1 1 1 0 1] + [1 0 0 0 0 0 0 1] + [1 1 0 0 1 0 0 1] + [1 1 0 1 0 0 0 1] + [1 0 0 0 0 0 0 0] + [0 0 0 0 0 0 1 1]] + (game-of-life/tick + [[1 1 0 1 1 0 0 0] + [1 0 1 1 0 0 0 0] + [1 1 1 0 0 1 1 1] + [0 0 0 0 0 1 1 0] + [1 0 0 0 1 1 0 0] + [1 1 0 0 0 1 1 1] + [0 0 1 0 1 0 0 1] + [1 0 0 0 0 0 1 1]])))))