Skip to content

Commit

Permalink
Add Game of Life exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
Steffan153 committed Apr 6, 2024
1 parent 4eae75b commit ee5b277
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 0 deletions.
11 changes: 11 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2090,6 +2090,17 @@
"numbers"
],
"difficulty": 5
},
{
"slug": "game-of-life",
"name": "Conway's Game of Life",
"uuid": "c6ad9a2d-4ca2-4013-93df-5f6934203870",
"practices": [],
"prerequisites": [
"if-then-else-expressions",
"lists"
],
"difficulty": 7
}
],
"foregone": [
Expand Down
12 changes: 12 additions & 0 deletions exercises/practice/game-of-life/.config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"fantomas-tool": {
"version": "3.2.0",
"commands": [
"fantomas"
]
}
}
}
11 changes: 11 additions & 0 deletions exercises/practice/game-of-life/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -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.
9 changes: 9 additions & 0 deletions exercises/practice/game-of-life/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions exercises/practice/game-of-life/.meta/Example.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module GameOfLife

let tick (input: int list list) =
input
|> List.mapi (fun row cells ->
cells
|> List.mapi (fun col cell ->
match
[ (row - 1, col - 1)
(row - 1, col)
(row - 1, col + 1)
(row, col - 1)
(row, col + 1)
(row + 1, col - 1)
(row + 1, col)
(row + 1, col + 1) ]
|> List.filter (fun (x, y) ->
x >= 0
&& x < List.length input
&& y >= 0
&& y < List.length cells
&& input.[x].[y] = 1)
|> List.length
with
| 2 when cell = 1 -> 1
| 3 -> 1
| _ -> 0))
22 changes: 22 additions & 0 deletions exercises/practice/game-of-life/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"authors": [
"Steffan153"
],
"files": {
"solution": [
"GameOfLife.fs"
],
"test": [
"GameOfLifeTests.fs"
],
"example": [
".meta/Example.fs"
],
"invalidator": [
"GameOfLife.fsproj"
]
},
"blurb": "Implement Conway's Game of Life.",
"source": "Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"
}
34 changes: 34 additions & 0 deletions exercises/practice/game-of-life/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -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"
3 changes: 3 additions & 0 deletions exercises/practice/game-of-life/GameOfLife.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module GameOfLife

let tick input = failwith "You need to implement this function."
21 changes: 21 additions & 0 deletions exercises/practice/game-of-life/GameOfLife.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<Compile Include="GameOfLife.fs" />
<Compile Include="GameOfLifeTests.fs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="FsUnit.xUnit" Version="4.0.4" />
</ItemGroup>

</Project>
107 changes: 107 additions & 0 deletions exercises/practice/game-of-life/GameOfLifeTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
module GameOfLifeTests

open FsUnit.Xunit
open Xunit

open GameOfLife

[<Fact>]
let ``Empty matrix`` () =
let matrix: int list list = []
let expected: int list list = []
tick matrix |> should equal expected

[<Fact(Skip = "Remove this Skip property to run this test")>]
let ``Live cells with zero live neighbors die`` () =
let matrix =
[ [0; 0; 0];
[0; 1; 0];
[0; 0; 0] ]
let expected =
[ [0; 0; 0];
[0; 0; 0];
[0; 0; 0] ]
tick matrix |> should equal expected

[<Fact(Skip = "Remove this Skip property to run this test")>]
let ``Live cells with only one live neighbor die`` () =
let matrix =
[ [0; 0; 0];
[0; 1; 0];
[0; 1; 0] ]
let expected =
[ [0; 0; 0];
[0; 0; 0];
[0; 0; 0] ]
tick matrix |> should equal expected

[<Fact(Skip = "Remove this Skip property to run this test")>]
let ``Live cells with two live neighbors stay alive`` () =
let matrix =
[ [1; 0; 1];
[1; 0; 1];
[1; 0; 1] ]
let expected =
[ [0; 0; 0];
[1; 0; 1];
[0; 0; 0] ]
tick matrix |> should equal expected

[<Fact(Skip = "Remove this Skip property to run this test")>]
let ``Live cells with three live neighbors stay alive`` () =
let matrix =
[ [0; 1; 0];
[1; 0; 0];
[1; 1; 0] ]
let expected =
[ [0; 0; 0];
[1; 0; 0];
[1; 1; 0] ]
tick matrix |> should equal expected

[<Fact(Skip = "Remove this Skip property to run this test")>]
let ``Dead cells with three live neighbors become alive`` () =
let matrix =
[ [1; 1; 0];
[0; 0; 0];
[1; 0; 0] ]
let expected =
[ [0; 0; 0];
[1; 1; 0];
[0; 0; 0] ]
tick matrix |> should equal expected

[<Fact(Skip = "Remove this Skip property to run this test")>]
let ``Live cells with four or more neighbors die`` () =
let matrix =
[ [1; 1; 1];
[1; 1; 1];
[1; 1; 1] ]
let expected =
[ [1; 0; 1];
[0; 0; 0];
[1; 0; 1] ]
tick matrix |> should equal expected

[<Fact(Skip = "Remove this Skip property to run this test")>]
let ``Bigger matrix`` () =
let 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] ]
let 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] ]
tick matrix |> should equal expected

15 changes: 15 additions & 0 deletions generators/Generators.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2013,3 +2013,18 @@ type AffineCipher() =
"System.ArgumentException"
else
base.RenderExpected(testCase, key, value)


type GameOfLife() =
inherit ExerciseGenerator()

override _.RenderInput(_, _, value) = List.renderMultiLine value

override _.RenderExpected(_, _, value) = List.renderMultiLine value

override this.PropertiesWithIdentifier testCase = this.Properties testCase

override _.IdentifierTypeAnnotation(_, _, value) =
match Seq.isEmpty value with
| true -> Some "int list list"
| false -> None

0 comments on commit ee5b277

Please sign in to comment.