Skip to content

Commit

Permalink
add game of life
Browse files Browse the repository at this point in the history
  • Loading branch information
jiegillet committed May 17, 2024
1 parent d3b42cf commit bf5801b
Show file tree
Hide file tree
Showing 12 changed files with 285 additions and 0 deletions.
16 changes: 16 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2313,6 +2313,22 @@
],
"difficulty": 5
},
{
"slug": "game-of-life",
"name": "Game of Life",
"uuid": "32d53ab8-abea-4483-a8cb-ee3b908a9dd7",
"practices": [
"enum"
],
"prerequisites": [
"enum",
"lists",
"pattern-matching",
"pipe-operator",
"multiple-clause-functions"
],
"difficulty": 6
},
{
"slug": "knapsack",
"name": "Knapsack",
Expand Down
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
4 changes: 4 additions & 0 deletions exercises/practice/game-of-life/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
26 changes: 26 additions & 0 deletions exercises/practice/game-of-life/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
game_of_life-*.tar

# Temporary files, for example, from tests.
/tmp/
19 changes: 19 additions & 0 deletions exercises/practice/game-of-life/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"jiegillet"
],
"files": {
"solution": [
"lib/game_of_life.ex"
],
"test": [
"test/game_of_life_test.exs"
],
"example": [
".meta/example.ex"
]
},
"blurb": "Implement Conway's Game of Life.",
"source": "Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"
}
44 changes: 44 additions & 0 deletions exercises/practice/game-of-life/.meta/example.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
defmodule GameOfLife do
@doc """
Apply the rules of Conway's Game of Life to a grid of cells
"""

@spec tick(matrix :: list(list(0 | 1))) :: list(list(0 | 1))
def tick([]), do: []

def tick(matrix) do
neighbors = count_neighbors(matrix)

Enum.zip_with(matrix, neighbors, fn row_matrix, row_neighbor ->
Enum.zip_with(row_matrix, row_neighbor, &rule/2)
end)
end

defp count_neighbors(matrix) do
shift_left = shift_left(matrix)
shift_right = shift_right(matrix)

shifts = [
shift_left,
shift_right,
shift_up(matrix),
shift_down(matrix),
shift_left |> shift_up(),
shift_left |> shift_down(),
shift_right |> shift_up(),
shift_right |> shift_down()
]

Enum.zip_with(shifts, fn rows -> Enum.zip_with(rows, &Enum.sum/1) end)
end

defp shift_right(matrix), do: Enum.map(matrix, fn row -> [0 | row] end)
defp shift_left(matrix), do: Enum.map(matrix, fn row -> Enum.drop(row, 1) ++ [0] end)
defp shift_up([first | rest]), do: rest ++ [Enum.map(first, fn _ -> 0 end)]
defp shift_down([first | _] = matrix), do: [Enum.map(first, fn _ -> 0 end) | matrix]

defp rule(1, 2), do: 1
defp rule(1, 3), do: 1
defp rule(0, 3), do: 1
defp rule(_cell, _live_neighbors), do: 0
end
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"
9 changes: 9 additions & 0 deletions exercises/practice/game-of-life/lib/game_of_life.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule GameOfLife do
@doc """
Apply the rules of Conway's Game of Life to a grid of cells
"""

@spec tick(matrix :: list(list(0 | 1))) :: list(list(0 | 1))
def tick(matrix) do
end
end
28 changes: 28 additions & 0 deletions exercises/practice/game-of-life/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule GameOfLife.MixProject do
use Mix.Project

def project do
[
app: :game_of_life,
version: "0.1.0",
# elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end
83 changes: 83 additions & 0 deletions exercises/practice/game-of-life/test/game_of_life_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
defmodule GameOfLifeTest do
use ExUnit.Case

# @tag :pending
test "empty matrix" do
assert GameOfLife.tick([]) == []
end

@tag :pending
test "live cells with zero live neighbors die" do
matrix = [[0, 0, 0], [0, 1, 0], [0, 0, 0]]
output = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

assert GameOfLife.tick(matrix) == output
end

@tag :pending
test "live cells with only one live neighbor die" do
matrix = [[0, 0, 0], [0, 1, 0], [0, 1, 0]]
output = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

assert GameOfLife.tick(matrix) == output
end

@tag :pending
test "live cells with two live neighbors stay alive" do
matrix = [[1, 0, 1], [1, 0, 1], [1, 0, 1]]
output = [[0, 0, 0], [1, 0, 1], [0, 0, 0]]

assert GameOfLife.tick(matrix) == output
end

@tag :pending
test "live cells with three live neighbors stay alive" do
matrix = [[0, 1, 0], [1, 0, 0], [1, 1, 0]]
output = [[0, 0, 0], [1, 0, 0], [1, 1, 0]]

assert GameOfLife.tick(matrix) == output
end

@tag :pending
test "dead cells with three live neighbors become alive" do
matrix = [[1, 1, 0], [0, 0, 0], [1, 0, 0]]
output = [[0, 0, 0], [1, 1, 0], [0, 0, 0]]

assert GameOfLife.tick(matrix) == output
end

@tag :pending
test "live cells with four or more neighbors die" do
matrix = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
output = [[1, 0, 1], [0, 0, 0], [1, 0, 1]]

assert GameOfLife.tick(matrix) == output
end

@tag :pending
test "bigger matrix" do
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]
]

output = [
[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]
]

assert GameOfLife.tick(matrix) == output
end
end
2 changes: 2 additions & 0 deletions exercises/practice/game-of-life/test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)

0 comments on commit bf5801b

Please sign in to comment.