From 4bee6e47c6eb118114cf0e3194fae57cd512b5d4 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Mon, 28 Oct 2024 23:37:06 +1100 Subject: [PATCH] Add game-of-life exercise (#221) --- config.json | 8 ++ .../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/proof.ci.wren | 41 ++++++ .../practice/game-of-life/.meta/tests.toml | 34 +++++ exercises/practice/game-of-life/LICENSE | 21 +++ .../game-of-life/game-of-life.spec.wren | 120 ++++++++++++++++++ .../practice/game-of-life/game-of-life.wren | 5 + exercises/practice/game-of-life/package.wren | 14 ++ 10 files changed, 282 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/proof.ci.wren create mode 100644 exercises/practice/game-of-life/.meta/tests.toml create mode 100644 exercises/practice/game-of-life/LICENSE create mode 100644 exercises/practice/game-of-life/game-of-life.spec.wren create mode 100644 exercises/practice/game-of-life/game-of-life.wren create mode 100644 exercises/practice/game-of-life/package.wren diff --git a/config.json b/config.json index a42fea9..3ea4493 100644 --- a/config.json +++ b/config.json @@ -662,6 +662,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "game-of-life", + "name": "Conway's Game of Life", + "uuid": "25825370-3447-4d7f-892a-752a1fc43ad2", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "grade-school", "name": "Grade School", 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 0000000..4953140 --- /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 0000000..2347b93 --- /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 0000000..a29c23b --- /dev/null +++ b/exercises/practice/game-of-life/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "game-of-life.wren" + ], + "test": [ + "game-of-life.spec.wren" + ], + "example": [ + ".meta/proof.ci.wren" + ] + }, + "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/proof.ci.wren b/exercises/practice/game-of-life/.meta/proof.ci.wren new file mode 100644 index 0000000..bf8998a --- /dev/null +++ b/exercises/practice/game-of-life/.meta/proof.ci.wren @@ -0,0 +1,41 @@ +class GameOfLife { + static tick(matrix) { + var result = [] + for (i in 0...matrix.count) { + result.add([]) + for (j in 0...matrix[i].count) { + var liveNeighbors = 0 + for (di in -1..1) { + var ni = i + di + if (ni < 0 || ni >= matrix.count) { + continue + } + + for (dj in -1..1) { + var nj = j + dj + if (nj < 0 || nj >= matrix.count) { + continue + } + + if (di == 0 && dj == 0) { + continue + } + + if (matrix[ni][nj] != 0) { + liveNeighbors = liveNeighbors + 1 + } + } + } + + if (liveNeighbors == 2) { + result[-1].add(matrix[i][j]) + } else if (liveNeighbors == 3) { + result[-1].add(1) + } else { + result[-1].add(0) + } + } + } + return result + } +} 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 0000000..398cd45 --- /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/LICENSE b/exercises/practice/game-of-life/LICENSE new file mode 100644 index 0000000..c362f61 --- /dev/null +++ b/exercises/practice/game-of-life/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Exercism + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/exercises/practice/game-of-life/game-of-life.spec.wren b/exercises/practice/game-of-life/game-of-life.spec.wren new file mode 100644 index 0000000..1299e64 --- /dev/null +++ b/exercises/practice/game-of-life/game-of-life.spec.wren @@ -0,0 +1,120 @@ +import "./game-of-life" for GameOfLife +import "wren-testie/testie" for Testie, Expect + +Testie.test("GameOfLife") { |do, skip| + do.test("empty matrix") { + var matrix = [ + ] + var expected = [ + ] + Expect.value(GameOfLife.tick(matrix)).toEqual(expected) + } + + skip.test("live cells with zero live neighbors die") { + var matrix = [ + [0, 0, 0], + [0, 1, 0], + [0, 0, 0], + ] + var expected = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ] + Expect.value(GameOfLife.tick(matrix)).toEqual(expected) + } + + skip.test("live cells with only one live neighbor die") { + var matrix = [ + [0, 0, 0], + [0, 1, 0], + [0, 1, 0], + ] + var expected = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ] + Expect.value(GameOfLife.tick(matrix)).toEqual(expected) + } + + skip.test("live cells with two live neighbors stay alive") { + var matrix = [ + [1, 0, 1], + [1, 0, 1], + [1, 0, 1], + ] + var expected = [ + [0, 0, 0], + [1, 0, 1], + [0, 0, 0], + ] + Expect.value(GameOfLife.tick(matrix)).toEqual(expected) + } + + skip.test("live cells with three live neighbors stay alive") { + var matrix = [ + [0, 1, 0], + [1, 0, 0], + [1, 1, 0], + ] + var expected = [ + [0, 0, 0], + [1, 0, 0], + [1, 1, 0], + ] + Expect.value(GameOfLife.tick(matrix)).toEqual(expected) + } + + skip.test("dead cells with three live neighbors become alive") { + var matrix = [ + [1, 1, 0], + [0, 0, 0], + [1, 0, 0], + ] + var expected = [ + [0, 0, 0], + [1, 1, 0], + [0, 0, 0], + ] + Expect.value(GameOfLife.tick(matrix)).toEqual(expected) + } + + skip.test("live cells with four or more neighbors die") { + var matrix = [ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1], + ] + var expected = [ + [1, 0, 1], + [0, 0, 0], + [1, 0, 1], + ] + Expect.value(GameOfLife.tick(matrix)).toEqual(expected) + } + + skip.test("bigger matrix") { + var matrix = [ + [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], + ] + var expected = [ + [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], + ] + Expect.value(GameOfLife.tick(matrix)).toEqual(expected) + } +} diff --git a/exercises/practice/game-of-life/game-of-life.wren b/exercises/practice/game-of-life/game-of-life.wren new file mode 100644 index 0000000..c788c51 --- /dev/null +++ b/exercises/practice/game-of-life/game-of-life.wren @@ -0,0 +1,5 @@ +class GameOfLife { + static tick(matrix) { + Fiber.abort("Remove this statement and implement this function") + } +} diff --git a/exercises/practice/game-of-life/package.wren b/exercises/practice/game-of-life/package.wren new file mode 100644 index 0000000..c554090 --- /dev/null +++ b/exercises/practice/game-of-life/package.wren @@ -0,0 +1,14 @@ +import "wren-package" for WrenPackage, Dependency +import "os" for Process + +class Package is WrenPackage { + construct new() {} + name { "exercism/game-of-life" } + dependencies { + return [ + Dependency.new("wren-testie", "0.3.0", "https://github.com/joshgoebel/wren-testie.git") + ] + } +} + +Package.new().default()