diff --git a/config.json b/config.json index 6bfb15a..fa77fb9 100644 --- a/config.json +++ b/config.json @@ -1047,6 +1047,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "game-of-life", + "name": "Conway's Game Of Life", + "uuid": "9a66392e-acde-4c17-a8c6-281498eb635a", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "rectangles", "name": "Rectangles", 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/GameOfLife.example.ps1 b/exercises/practice/game-of-life/.meta/GameOfLife.example.ps1 new file mode 100644 index 0000000..f5d29a6 --- /dev/null +++ b/exercises/practice/game-of-life/.meta/GameOfLife.example.ps1 @@ -0,0 +1,100 @@ +Function Invoke-GameOfLife() { + <# + .SYNOPSIS + Compute the next generation of cells for Conway's Game of Life. + + .DESCRIPTION + Given a matrix of integer acting as cells in Conway's Game of Life, compute the next generation. + Each cell has two states : alive (1) or dead (0). + Each cell have eight neighbors, and 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. + + .PARAMETER Matrix + A matrix represent the current state of the game. + + .EXAMPLE + $matrix = @( + @(1, 1), + @(1, 0) + ) + + Invok-GameOfLife -Matrix $matrix + Returns: + @( + @(1, 1), + @(1, 1) + ) + #Bottom right cell come alive and the other three cells stay alive follow the logic of the rules. + #> + [CmdletBinding()] + Param( + [int[][]] $Matrix + ) + if ($Matrix.Count -eq 0) { + return @() + } + + $mapValues = @{} + for ($r = 0; $r -lt $Matrix.Count; $r++) { + for ($c = 0; $c -lt $Matrix[$r].Count; $c++) { + $cell = [Cell]::new($r,$c) + Update-Cell $cell $mapValues $Matrix + + $neighbors = $Cell.GetNeighbors($Matrix.Count) + foreach ($n in $neighbors) { + Update-Cell $n $mapValues $Matrix + } + $isAlive = $Matrix[$r][$c] -eq 1 + $liveNeighbors = ($neighbors | Where-Object {$mapValues[$_.ToString()] -eq 1}).Count + if ($isAlive -and ($liveNeighbors -eq 2 -or $liveNeighbors -eq 3) -or (-not $isAlive -and $liveNeighbors -eq 3)) { + $Matrix[$r][$c] = 1 + }else { + $Matrix[$r][$c] = 0 + } + } + } + $Matrix +} +class Cell { + [int]$Row + [int]$Column + + Cell([int]$row, [int]$col) { + $this.Row = $row + $this.Column = $col + } + + [System.Collections.Generic.List[Cell]] GetNeighbors([int]$Limit) { + $neighbors = [System.Collections.Generic.List[Cell]]::new() + foreach ($i in -1..1) { + foreach ($j in -1..1) { + if ($i -eq 0 -and $j -eq 0) { + continue + } + $newR = $this.Row + $i + $newC = $this.Column + $j + if ($newR -ge 0 -and $newR -lt $Limit -and $newC -ge 0 -and $newC -lt $Limit) { + $neighbors.Add([Cell]::new($newR, $newC)) + } + } + } + return $neighbors + } + + [string]ToString() { + return "$($this.Row):$($this.Column)" + } +} + +function Update-Cell { + param ( + [Cell]$Cell, + [hashtable]$Map, + [int[][]] $Matrix + ) + if (-not $Map.ContainsKey($Cell.ToString())) { + $Map[$Cell.ToString()] = $Matrix[$Cell.Row][$Cell.Column] + } +} 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..2672d60 --- /dev/null +++ b/exercises/practice/game-of-life/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glaxxie" + ], + "files": { + "solution": [ + "GameOfLife.ps1" + ], + "test": [ + "GameOfLife.tests.ps1" + ], + "example": [ + ".meta/GameOfLife.example.ps1" + ] + }, + "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/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/GameOfLife.ps1 b/exercises/practice/game-of-life/GameOfLife.ps1 new file mode 100644 index 0000000..b9807ec --- /dev/null +++ b/exercises/practice/game-of-life/GameOfLife.ps1 @@ -0,0 +1,36 @@ +Function Invoke-GameOfLife() { + <# + .SYNOPSIS + Compute the next generation of cells for Conway's Game of Life. + + .DESCRIPTION + Given a matrix of integer acting as cells in Conway's Game of Life, compute the next generation. + Each cell has two states : alive (1) or dead (0). + Each cell have eight neighbors, and 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. + + .PARAMETER Matrix + A matrix represent the current state of the game. + + .EXAMPLE + $matrix = @( + @(1, 1), + @(1, 0) + ) + + Invok-GameOfLife -Matrix $matrix + Returns: + @( + @(1, 1), + @(1, 1) + ) + #Bottom right cell come alive and the other three cells stay alive follow the logic of the rules. + #> + [CmdletBinding()] + Param( + [int[][]] $Matrix + ) + Throw "Please implement this function" +} diff --git a/exercises/practice/game-of-life/GameOfLife.tests.ps1 b/exercises/practice/game-of-life/GameOfLife.tests.ps1 new file mode 100644 index 0000000..4c4a766 --- /dev/null +++ b/exercises/practice/game-of-life/GameOfLife.tests.ps1 @@ -0,0 +1,127 @@ +BeforeAll { + . "./GameOfLife.ps1" +} + +Describe "GameOfLife test cases" { + It "empty matrix" { + $got = Invoke-GameOfLife -Matrix @() + $want = @() + + $got | Should -BeExactly $want + } + + It "live cells with zero live neighbors die" { + $got = Invoke-GameOfLife -Matrix @( + @(0, 0, 0), + @(0, 1, 0), + @(0, 0, 0) + ) + $want = @( + @(0, 0, 0), + @(0, 0, 0), + @(0, 0, 0) + ) + + $got | Should -BeExactly $want + } + + It "live cells with only one live neighbor die" { + $got = Invoke-GameOfLife -Matrix @( + @(0, 0, 0), + @(0, 1, 0), + @(0, 1, 0) + ) + $want = @( + @(0, 0, 0), + @(0, 0, 0), + @(0, 0, 0) + ) + + $got | Should -BeExactly $want + } + + It "live cells with two live neighbors stay alive" { + $got = Invoke-GameOfLife -Matrix @( + @(1, 0, 1), + @(1, 0, 1), + @(1, 0, 1) + ) + $want = @( + @(0, 0, 0), + @(1, 0, 1), + @(0, 0, 0) + ) + + $got | Should -BeExactly $want + } + + It "live cells with three live neighbors stay alive" { + $got = Invoke-GameOfLife -Matrix @( + @(0, 1, 0), + @(1, 0, 0), + @(1, 1, 0) + ) + $want = @( + @(0, 0, 0), + @(1, 0, 0), + @(1, 1, 0) + ) + + $got | Should -BeExactly $want + } + + It "dead cells with three live neighbors become alive" { + $got = Invoke-GameOfLife -Matrix @( + @(1, 1, 0), + @(0, 0, 0), + @(1, 0, 0) + ) + $want = @( + @(0, 0, 0), + @(1, 1, 0), + @(0, 0, 0) + ) + + $got | Should -BeExactly $want + } + + It "live cells with four or more neighbors die" { + $got = Invoke-GameOfLife -Matrix @( + @(1, 1, 1), + @(1, 1, 1), + @(1, 1, 1) + ) + $want = @( + @(1, 0, 1), + @(0, 0, 0), + @(1, 0, 1) + ) + + $got | Should -BeExactly $want + } + + It "bigger matrix" { + $got = Invoke-GameOfLife -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) + ) + $want = @( + @(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) + ) + + $got | Should -BeExactly $want + } +}