Skip to content

Commit

Permalink
Add game-of-life exercise (#347)
Browse files Browse the repository at this point in the history
* Add `game-of-life` exercise

* Minor fixes

* Fix import

* Install dplyr in CI
  • Loading branch information
ErikSchierboom authored Sep 18, 2024
1 parent 8e8a4e2 commit 36d408c
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 4 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:

steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

- uses: r-lib/actions/setup-r@v2
with:
r-version: 4.3.1
Expand All @@ -40,18 +40,18 @@ jobs:

strategy:
matrix:
R: [ '4.3.1' ]
R: ["4.3.1"]

steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.R }}

- name: Install project dependencies
run: |
install.packages(c("testthat", "jsonlite", "lintr"))
install.packages(c("testthat", "jsonlite", "lintr", "dplyr"))
shell: Rscript {0}

- name: Run exercism/r ci (runs tests) for all exercises
Expand Down
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 3
},
{
"slug": "game-of-life",
"name": "Conway's Game of Life",
"uuid": "5ba723f2-dd9e-452a-b5f3-cfe19a2650b5",
"practices": [],
"prerequisites": [],
"difficulty": 4
}
]
},
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
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": [
"erikschierboom"
],
"files": {
"solution": [
"game-of-life.R"
],
"test": [
"test_game-of-life.R"
],
"example": [
".meta/example.R"
]
},
"blurb": "Implement Conway's Game of Life.",
"source": "Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"
}
19 changes: 19 additions & 0 deletions exercises/practice/game-of-life/.meta/example.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
library(dplyr)

tick <- function(cells) {
coords <- expand.grid(seq_len(nrow(cells)), seq_len(ncol(cells)))

matrix(apply(coords, 1, function(coord) {
cell <- cells[coord[1], coord[2]]
neighbor_coords <- dplyr::inner_join(
expand.grid(coord[1] + -1:1, coord[2] + -1:1),
coords
)
live_neighbors <- sum(
apply(neighbor_coords, 1, function (neighbor_coord) {
cells[neighbor_coord[1], neighbor_coord[2]]
})) - cell
ifelse(live_neighbors == 3 ||
live_neighbors == 2 && cell == 1, 1, 0)
}), nrow(cells))
}
35 changes: 35 additions & 0 deletions exercises/practice/game-of-life/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 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"
include = false

[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/game-of-life.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tick <- function(cells) {

}
110 changes: 110 additions & 0 deletions exercises/practice/game-of-life/test_game-of-life.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
source("./game-of-life.R")
library(testthat)

test_that("live cells with zero live neighbors die", {
expect_equal(
tick(
matrix(
c(0, 0, 0,
0, 1, 0,
0, 0, 0), 3, byrow = TRUE)),
matrix(
c(0, 0, 0,
0, 0, 0,
0, 0, 0), 3, byrow = TRUE)
)
})

test_that("live cells with only one live neighbor die", {
expect_equal(
tick(
matrix(
c(0, 0, 0,
0, 1, 0,
0, 1, 0), 3, byrow = TRUE)),
matrix(
c(0, 0, 0,
0, 0, 0,
0, 0, 0), 3, byrow = TRUE)
)
})

test_that("live cells with two live neighbors stay alive", {
expect_equal(
tick(
matrix(
c(1, 0, 1,
1, 0, 1,
1, 0, 1), 3, byrow = TRUE)),
matrix(
c(0, 0, 0,
1, 0, 1,
0, 0, 0), 3, byrow = TRUE)
)
})

test_that("live cells with three live neighbors stay alive", {
expect_equal(
tick(
matrix(
c(0, 1, 0,
1, 0, 0,
1, 1, 0), 3, byrow = TRUE)),
matrix(
c(0, 0, 0,
1, 0, 0,
1, 1, 0), 3, byrow = TRUE)
)
})

test_that("dead cells with three live neighbors become alive", {
expect_equal(
tick(
matrix(
c(1, 1, 0,
0, 0, 0,
1, 0, 0), 3, byrow = TRUE)),
matrix(
c(0, 0, 0,
1, 1, 0,
0, 0, 0), 3, byrow = TRUE)
)
})

test_that("live cells with four or more neighbors die", {
expect_equal(
tick(
matrix(
c(1, 1, 1,
1, 1, 1,
1, 1, 1), 3, byrow = TRUE)),
matrix(
c(1, 0, 1,
0, 0, 0,
1, 0, 1), 3, byrow = TRUE)
)
})

test_that("bigger matrix", {
expect_equal(
tick(
matrix(
c(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), 8)),
matrix(
c(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), 8)
)
})

0 comments on commit 36d408c

Please sign in to comment.