Skip to content

Commit 159a403

Browse files
authored
Add game-of-life (#4077)
* Add `game-of-life` * Fix test case formatting
1 parent 7dcd007 commit 159a403

File tree

9 files changed

+258
-0
lines changed

9 files changed

+258
-0
lines changed

config.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,16 @@
959959
"prerequisites": ["basics", "bools", "numbers", "classes"],
960960
"difficulty": 2
961961
},
962+
{
963+
"slug": "game-of-life",
964+
"name": "Conway's Game of Life",
965+
"uuid": "1675a497-d3b2-4772-bbee-4edae5a44e91",
966+
"practices": [],
967+
"prerequisites": [
968+
"lists"
969+
],
970+
"difficulty": 3
971+
},
962972
{
963973
"slug": "eliuds-eggs",
964974
"name": "Eliud's Eggs",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Instructions
2+
3+
After each generation, the cells interact with their eight neighbors, which are cells adjacent horizontally, vertically, or diagonally.
4+
5+
The following rules are applied to each cell:
6+
7+
- Any live cell with two or three live neighbors lives on.
8+
- Any dead cell with exactly three live neighbors becomes a live cell.
9+
- All other cells die or stay dead.
10+
11+
Given a matrix of 1s and 0s (corresponding to live and dead cells), apply the rules to each cell, and return the next generation.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Introduction
2+
3+
[Conway's Game of Life][game-of-life] is a fascinating cellular automaton created by the British mathematician John Horton Conway in 1970.
4+
5+
The game consists of a two-dimensional grid of cells that can either be "alive" or "dead."
6+
7+
After each generation, the cells interact with their eight neighbors via a set of rules, which define the new generation.
8+
9+
[game-of-life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"BNAndras"
4+
],
5+
"files": {
6+
"solution": [
7+
"game_of_life.py"
8+
],
9+
"test": [
10+
"game_of_life_test.py"
11+
],
12+
"example": [
13+
".meta/example.py"
14+
]
15+
},
16+
"blurb": "Implement Conway's Game of Life.",
17+
"source": "Wikipedia",
18+
"source_url": "https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"
19+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
def tick(matrix):
2+
def count_neighbors(r, c):
3+
count = 0
4+
for dr, dc in [
5+
(-1, -1), (-1, 0), (-1, 1),
6+
(0, -1), (0, 1),
7+
(1, -1), (1, 0), (1, 1),
8+
]:
9+
nr, nc = r + dr, c + dc
10+
if 0 <= nr < rows and 0 <= nc < cols:
11+
count += matrix[nr][nc]
12+
return count
13+
14+
if not matrix:
15+
return []
16+
17+
rows = len(matrix)
18+
cols = len(matrix[0])
19+
20+
new_matrix = []
21+
for r in range(rows):
22+
new_row = []
23+
for c in range(cols):
24+
neighbors = count_neighbors(r, c)
25+
current = matrix[r][c]
26+
state = 0
27+
if current == 1 and (neighbors == 2 or neighbors == 3):
28+
state = 1
29+
elif current == 0 and neighbors == 3:
30+
state = 1
31+
new_row.append(state)
32+
new_matrix.append(new_row)
33+
34+
return new_matrix
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{% import "generator_macros.j2" as macros with context %}
2+
{{ macros.canonical_ref() }}
3+
4+
{{ macros.header() }}
5+
6+
class {{ exercise | camel_case }}Test(unittest.TestCase):
7+
{% for case in cases %}
8+
def test_{{ case.description | to_snake }}(self):
9+
matrix = [
10+
{% for row in case.input.matrix %}
11+
{{ row }},
12+
{% endfor %}
13+
]
14+
expected = [
15+
{% for row in case.expected %}
16+
{{ row }},
17+
{% endfor %}
18+
]
19+
self.assertEqual(
20+
tick(matrix), expected
21+
)
22+
{% endfor %}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[ae86ea7d-bd07-4357-90b3-ac7d256bd5c5]
13+
description = "empty matrix"
14+
15+
[4ea5ccb7-7b73-4281-954a-bed1b0f139a5]
16+
description = "live cells with zero live neighbors die"
17+
18+
[df245adc-14ff-4f9c-b2ae-f465ef5321b2]
19+
description = "live cells with only one live neighbor die"
20+
21+
[2a713b56-283c-48c8-adae-1d21306c80ae]
22+
description = "live cells with two live neighbors stay alive"
23+
24+
[86d5c5a5-ab7b-41a1-8907-c9b3fc5e9dae]
25+
description = "live cells with three live neighbors stay alive"
26+
27+
[015f60ac-39d8-4c6c-8328-57f334fc9f89]
28+
description = "dead cells with three live neighbors become alive"
29+
30+
[2ee69c00-9d41-4b8b-89da-5832e735ccf1]
31+
description = "live cells with four or more neighbors die"
32+
33+
[a79b42be-ed6c-4e27-9206-43da08697ef6]
34+
description = "bigger matrix"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def tick(matrix):
2+
pass
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# These tests are auto-generated with test data from:
2+
# https://github.com/exercism/problem-specifications/tree/main/exercises/game-of-life/canonical-data.json
3+
# File last updated on 2026-01-26
4+
5+
import unittest
6+
7+
from game_of_life import (
8+
tick,
9+
)
10+
11+
12+
class GameOfLifeTest(unittest.TestCase):
13+
def test_empty_matrix(self):
14+
matrix = []
15+
expected = []
16+
self.assertEqual(tick(matrix), expected)
17+
18+
def test_live_cells_with_zero_live_neighbors_die(self):
19+
matrix = [
20+
[0, 0, 0],
21+
[0, 1, 0],
22+
[0, 0, 0],
23+
]
24+
expected = [
25+
[0, 0, 0],
26+
[0, 0, 0],
27+
[0, 0, 0],
28+
]
29+
self.assertEqual(tick(matrix), expected)
30+
31+
def test_live_cells_with_only_one_live_neighbor_die(self):
32+
matrix = [
33+
[0, 0, 0],
34+
[0, 1, 0],
35+
[0, 1, 0],
36+
]
37+
expected = [
38+
[0, 0, 0],
39+
[0, 0, 0],
40+
[0, 0, 0],
41+
]
42+
self.assertEqual(tick(matrix), expected)
43+
44+
def test_live_cells_with_two_live_neighbors_stay_alive(self):
45+
matrix = [
46+
[1, 0, 1],
47+
[1, 0, 1],
48+
[1, 0, 1],
49+
]
50+
expected = [
51+
[0, 0, 0],
52+
[1, 0, 1],
53+
[0, 0, 0],
54+
]
55+
self.assertEqual(tick(matrix), expected)
56+
57+
def test_live_cells_with_three_live_neighbors_stay_alive(self):
58+
matrix = [
59+
[0, 1, 0],
60+
[1, 0, 0],
61+
[1, 1, 0],
62+
]
63+
expected = [
64+
[0, 0, 0],
65+
[1, 0, 0],
66+
[1, 1, 0],
67+
]
68+
self.assertEqual(tick(matrix), expected)
69+
70+
def test_dead_cells_with_three_live_neighbors_become_alive(self):
71+
matrix = [
72+
[1, 1, 0],
73+
[0, 0, 0],
74+
[1, 0, 0],
75+
]
76+
expected = [
77+
[0, 0, 0],
78+
[1, 1, 0],
79+
[0, 0, 0],
80+
]
81+
self.assertEqual(tick(matrix), expected)
82+
83+
def test_live_cells_with_four_or_more_neighbors_die(self):
84+
matrix = [
85+
[1, 1, 1],
86+
[1, 1, 1],
87+
[1, 1, 1],
88+
]
89+
expected = [
90+
[1, 0, 1],
91+
[0, 0, 0],
92+
[1, 0, 1],
93+
]
94+
self.assertEqual(tick(matrix), expected)
95+
96+
def test_bigger_matrix(self):
97+
matrix = [
98+
[1, 1, 0, 1, 1, 0, 0, 0],
99+
[1, 0, 1, 1, 0, 0, 0, 0],
100+
[1, 1, 1, 0, 0, 1, 1, 1],
101+
[0, 0, 0, 0, 0, 1, 1, 0],
102+
[1, 0, 0, 0, 1, 1, 0, 0],
103+
[1, 1, 0, 0, 0, 1, 1, 1],
104+
[0, 0, 1, 0, 1, 0, 0, 1],
105+
[1, 0, 0, 0, 0, 0, 1, 1],
106+
]
107+
expected = [
108+
[1, 1, 0, 1, 1, 0, 0, 0],
109+
[0, 0, 0, 0, 0, 1, 1, 0],
110+
[1, 0, 1, 1, 1, 1, 0, 1],
111+
[1, 0, 0, 0, 0, 0, 0, 1],
112+
[1, 1, 0, 0, 1, 0, 0, 1],
113+
[1, 1, 0, 1, 0, 0, 0, 1],
114+
[1, 0, 0, 0, 0, 0, 0, 0],
115+
[0, 0, 0, 0, 0, 0, 1, 1],
116+
]
117+
self.assertEqual(tick(matrix), expected)

0 commit comments

Comments
 (0)