Skip to content

Commit d75f149

Browse files
committed
Add game-of-life
1 parent 39e917c commit d75f149

9 files changed

Lines changed: 278 additions & 0 deletions

File tree

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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
self.assertEqual(
10+
tick(
11+
[
12+
{% for row in case.input.matrix %}
13+
{{ row }},
14+
{% endfor %}
15+
]
16+
),
17+
[
18+
{% for row in case.expected %}
19+
{{ row }},
20+
{% endfor %}
21+
]
22+
)
23+
{% 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: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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-25
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+
self.assertEqual(tick([]), [])
15+
16+
def test_live_cells_with_zero_live_neighbors_die(self):
17+
self.assertEqual(
18+
tick(
19+
[
20+
[0, 0, 0],
21+
[0, 1, 0],
22+
[0, 0, 0],
23+
]
24+
),
25+
[
26+
[0, 0, 0],
27+
[0, 0, 0],
28+
[0, 0, 0],
29+
],
30+
)
31+
32+
def test_live_cells_with_only_one_live_neighbor_die(self):
33+
self.assertEqual(
34+
tick(
35+
[
36+
[0, 0, 0],
37+
[0, 1, 0],
38+
[0, 1, 0],
39+
]
40+
),
41+
[
42+
[0, 0, 0],
43+
[0, 0, 0],
44+
[0, 0, 0],
45+
],
46+
)
47+
48+
def test_live_cells_with_two_live_neighbors_stay_alive(self):
49+
self.assertEqual(
50+
tick(
51+
[
52+
[1, 0, 1],
53+
[1, 0, 1],
54+
[1, 0, 1],
55+
]
56+
),
57+
[
58+
[0, 0, 0],
59+
[1, 0, 1],
60+
[0, 0, 0],
61+
],
62+
)
63+
64+
def test_live_cells_with_three_live_neighbors_stay_alive(self):
65+
self.assertEqual(
66+
tick(
67+
[
68+
[0, 1, 0],
69+
[1, 0, 0],
70+
[1, 1, 0],
71+
]
72+
),
73+
[
74+
[0, 0, 0],
75+
[1, 0, 0],
76+
[1, 1, 0],
77+
],
78+
)
79+
80+
def test_dead_cells_with_three_live_neighbors_become_alive(self):
81+
self.assertEqual(
82+
tick(
83+
[
84+
[1, 1, 0],
85+
[0, 0, 0],
86+
[1, 0, 0],
87+
]
88+
),
89+
[
90+
[0, 0, 0],
91+
[1, 1, 0],
92+
[0, 0, 0],
93+
],
94+
)
95+
96+
def test_live_cells_with_four_or_more_neighbors_die(self):
97+
self.assertEqual(
98+
tick(
99+
[
100+
[1, 1, 1],
101+
[1, 1, 1],
102+
[1, 1, 1],
103+
]
104+
),
105+
[
106+
[1, 0, 1],
107+
[0, 0, 0],
108+
[1, 0, 1],
109+
],
110+
)
111+
112+
def test_bigger_matrix(self):
113+
self.assertEqual(
114+
tick(
115+
[
116+
[1, 1, 0, 1, 1, 0, 0, 0],
117+
[1, 0, 1, 1, 0, 0, 0, 0],
118+
[1, 1, 1, 0, 0, 1, 1, 1],
119+
[0, 0, 0, 0, 0, 1, 1, 0],
120+
[1, 0, 0, 0, 1, 1, 0, 0],
121+
[1, 1, 0, 0, 0, 1, 1, 1],
122+
[0, 0, 1, 0, 1, 0, 0, 1],
123+
[1, 0, 0, 0, 0, 0, 1, 1],
124+
]
125+
),
126+
[
127+
[1, 1, 0, 1, 1, 0, 0, 0],
128+
[0, 0, 0, 0, 0, 1, 1, 0],
129+
[1, 0, 1, 1, 1, 1, 0, 1],
130+
[1, 0, 0, 0, 0, 0, 0, 1],
131+
[1, 1, 0, 0, 1, 0, 0, 1],
132+
[1, 1, 0, 1, 0, 0, 0, 1],
133+
[1, 0, 0, 0, 0, 0, 0, 0],
134+
[0, 0, 0, 0, 0, 0, 1, 1],
135+
],
136+
)

0 commit comments

Comments
 (0)