-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame.py
132 lines (110 loc) · 4.93 KB
/
game.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""
CONWAY'S GAME OF LIFE
The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.
The game is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input.
One interacts with the Game of Life by creating an initial configuration and observing how it evolves.
Rules:
1. Any live cell with fewer than two live neighbors dies, as if by underpopulation.
2. Any live cell with two or three live neighbors lives on to the next generation.
3. Any live cell with more than three live neighbors dies, as if by overpopulation.
4. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.cm as cm
plt.style.use('dark_background')
plt.rcParams['toolbar'] = 'None'
# Set up the initial state of the game
def initialize_game(width, height):
"""
initialize the game state assigning a random value to each cell in the grid (0 or 1) with a 90% chance of a cell being dead
:param width: The width of the game board
:param height: The height of the game board
:return: The initial state of the game
"""
game_state = np.random.choice([0, 1], size=(width, height), p=[0.8, 0.2])
return game_state
# Update the game state based on the rules of Conway's Game of Life
def update_game_state(game_state):
"""
Update the game state based on the rules of Conway's Game of Life
:param game_state: The current state of the game
:return: The updated state of the game expressed as a boolean array (True = alive, False = dead)
"""
# Count the number of neighbors for each cell in the grid (wrapping around the edges, so that the grid is topologically a torus)
neighbors_count = sum(np.roll(np.roll(game_state, i, 0), j, 1)
for i in (-1, 0, 1) for j in (-1, 0, 1)
if (i != 0 or j != 0))
# Apply the rules of Conway's Game of Life
# 1. Any live cell with fewer than two live neighbors dies, as if by underpopulation.
# 2. Any live cell with two or three live neighbors lives on to the next generation.
# 3. Any live cell with more than three live neighbors dies, as if by overpopulation.
# 4. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
game_state = (neighbors_count == 3) | (game_state & (neighbors_count == 2))
#create global variable to store the number of live neighbors
live_neighbors = neighbors_count
return game_state
# Generate the animation frames
def generate_frames(game_state):
while True:
yield game_state
game_state = update_game_state(game_state)
def get_updated_colors(game_state):
"""
Update the color and transparency of the scatter markers:
Transparent - dead
Translucent - alive
Coloured squares/cells depending on the the number of neighbours
"""
neighbors_count = sum(np.roll(np.roll(game_state, i, 0), j, 1)
for i in (-1, 0, 1) for j in (-1, 0, 1)
if (i != 0 or j != 0))
#compute the colors for each cell to be inferno colored
cmap = plt.colormaps['inferno']
rescale = neighbors_count / 8 # Maximum of 8 neighbors
colors = [cmap(neighbors) for neighbors in rescale.flatten()]
#extract the colors for the live cells
colors = [color for color, is_live in zip(colors, game_state.flatten()) if is_live]
return colors
# Create the animation
def create_animation(game_state):
#define figure and axis
fig, ax = plt.subplots()
# hide the axes
ax.set_axis_off()
#avoid autoscaling
# ax.set_xlim(-5, 55)
# ax.set_ylim(-5, 55)
#set the size in pixels to be 1920x1080
fig.set_size_inches(19.20, 10.80)
#set aspect to be equal
ax.set_aspect('equal')
def update(frame):
"""
Update the animation
:param frame: The current frame of the animation
:return: The updated scatter plot
"""
#clear the plot but not the axis
ax.clear()
ax.set_axis_off()
# ax.set_xlim(-5, 55)
# ax.set_ylim(-5, 55)
ax.set_aspect('equal')
#update the game state
#get the updated colors
colors = get_updated_colors(frame)
scatter = ax.scatter(np.where(frame)[0], np.where(frame)[1], color=colors, s=70)
return scatter
#arguments are: figure, update function, frames (the input to the update function), interval (the delay between frames in milliseconds)
anim = animation.FuncAnimation(fig, update, frames=generate_frames(game_state), interval=100)
plt.show()
# Main function
def main():
width = 200
height = 100
game_state = initialize_game(width, height)
create_animation(game_state)
if __name__ == '__main__':
main()