|
1 | | -""" |
2 | | -Conway's Game of Life implemented in Python. |
3 | | -https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life |
4 | | -""" |
| 1 | +"""Conway's Game of Life implemented in Python. |
| 2 | +https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life""" |
5 | 3 |
|
| 4 | +# Import block |
6 | 5 | from __future__ import annotations |
7 | 6 |
|
8 | 7 | from PIL import Image |
9 | 8 |
|
10 | | -# Define glider example |
| 9 | +# Constants |
11 | 10 | GLIDER = [ |
12 | 11 | [0, 1, 0, 0, 0, 0, 0, 0], |
13 | 12 | [0, 0, 1, 0, 0, 0, 0, 0], |
|
19 | 18 | [0, 0, 0, 0, 0, 0, 0, 0], |
20 | 19 | ] |
21 | 20 |
|
22 | | -# Define blinker example |
23 | | -BLINKER = [[0, 1, 0], [0, 1, 0], [0, 1, 0]] |
24 | | - |
| 21 | +BLINKER = [ |
| 22 | + [0, 1, 0], |
| 23 | + [0, 1, 0], |
| 24 | + [0, 1, 0] |
| 25 | +] |
25 | 26 |
|
| 27 | +# Functions |
26 | 28 | def new_generation(cells: list[list[int]]) -> list[list[int]]: |
27 | | - """ |
28 | | - Generates the next generation for a given state of Conway's Game of Life. |
29 | | - >>> new_generation(BLINKER) |
30 | | - [[0, 0, 0], [1, 1, 1], [0, 0, 0]] |
31 | | - """ |
32 | | - next_generation = [] |
33 | | - for i in range(len(cells)): |
34 | | - next_generation_row = [] |
35 | | - for j in range(len(cells[i])): |
36 | | - # Get the number of live neighbours |
37 | | - neighbour_count = 0 |
38 | | - if i > 0 and j > 0: |
39 | | - neighbour_count += cells[i - 1][j - 1] |
40 | | - if i > 0: |
41 | | - neighbour_count += cells[i - 1][j] |
42 | | - if i > 0 and j < len(cells[i]) - 1: |
43 | | - neighbour_count += cells[i - 1][j + 1] |
44 | | - if j > 0: |
45 | | - neighbour_count += cells[i][j - 1] |
46 | | - if j < len(cells[i]) - 1: |
47 | | - neighbour_count += cells[i][j + 1] |
48 | | - if i < len(cells) - 1 and j > 0: |
49 | | - neighbour_count += cells[i + 1][j - 1] |
50 | | - if i < len(cells) - 1: |
51 | | - neighbour_count += cells[i + 1][j] |
52 | | - if i < len(cells) - 1 and j < len(cells[i]) - 1: |
53 | | - neighbour_count += cells[i + 1][j + 1] |
54 | | - |
55 | | - # Rules of the game of life (excerpt from Wikipedia): |
56 | | - # 1. Any live cell with two or three live neighbours survives. |
57 | | - # 2. Any dead cell with three live neighbours becomes a live cell. |
58 | | - # 3. All other live cells die in the next generation. |
59 | | - # Similarly, all other dead cells stay dead. |
60 | | - alive = cells[i][j] == 1 |
61 | | - if ( |
62 | | - (alive and 2 <= neighbour_count <= 3) |
63 | | - or not alive |
64 | | - and neighbour_count == 3 |
65 | | - ): |
66 | | - next_generation_row.append(1) |
67 | | - else: |
68 | | - next_generation_row.append(0) |
69 | | - |
70 | | - next_generation.append(next_generation_row) |
71 | | - return next_generation |
72 | | - |
| 29 | + """Generates the next generation for a given state of Conway's Game of Life.""" |
| 30 | + next_gen = [[0] * len(row) for row in cells] |
| 31 | + for i, row in enumerate(cells): |
| 32 | + for j, cell in enumerate(row): |
| 33 | + neighbours = sum( |
| 34 | + cells[x][y] for x in range(i - 1, i + 2) for y in range(j - 1, j + 2) |
| 35 | + if 0 <= x < len(cells) and 0 <= y < len(row) and (x != i or y != j) |
| 36 | + ) |
| 37 | + next_gen[i][j] = 1 if cell == 1 and 2 <= neighbours <= 3 or cell == 0 \ |
| 38 | + and neighbours == 3 else 0 |
| 39 | + return next_gen |
73 | 40 |
|
74 | 41 | def generate_images(cells: list[list[int]], frames: int) -> list[Image.Image]: |
75 | | - """ |
76 | | - Generates a list of images of subsequent Game of Life states. |
77 | | - """ |
| 42 | + """Generates a list of images of subsequent Game of Life states.""" |
78 | 43 | images = [] |
79 | 44 | for _ in range(frames): |
80 | | - # Create output image |
81 | 45 | img = Image.new("RGB", (len(cells[0]), len(cells))) |
82 | 46 | pixels = img.load() |
83 | | - |
84 | | - # Save cells to image |
85 | | - for x in range(len(cells)): |
86 | | - for y in range(len(cells[0])): |
87 | | - colour = 255 - cells[y][x] * 255 |
88 | | - pixels[x, y] = (colour, colour, colour) |
89 | | - |
90 | | - # Save image |
| 47 | + for x, row in enumerate(cells): |
| 48 | + for y, cell in enumerate(row): |
| 49 | + colour = 255 - cell * 255 |
| 50 | + pixels[y, x] = (colour, colour, colour) |
91 | 51 | images.append(img) |
92 | 52 | cells = new_generation(cells) |
93 | 53 | return images |
94 | 54 |
|
95 | | - |
96 | 55 | if __name__ == "__main__": |
97 | 56 | images = generate_images(GLIDER, 16) |
98 | 57 | images[0].save("out.gif", save_all=True, append_images=images[1:]) |
0 commit comments