Conway’s Game of Life#
This version of Conway’s Game of Life speeds everything up by using controlling a cell’s visibility through its alpha value, and handing the drawing logic off to the graphics card.
Grid-based games can take a while to render the program uses classic raster-based graphics. Every cell has to be re-drawn every single frame. If the cells are complex at all, that adds to the rendering time.
In this program, we create all cells in the grid to begin with. (This does causes the program to pause a while at start-up.)
After the sprites are created, we turn the cells on and off by their alpha value. We can update the entire grid by simply sending a list of alpha values to the graphics card. This significantly improves drawing time.
conway_alpha.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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | """
Conway's Game of Life
This code shows how to set up sprites in a grid, and then use their
'alpha' value to quickly turn them on and off.
After installing the "arcade" package version 2.4.4+, this program can be run by
typing:
python -m arcade.examples.conway_alpha
"""
import arcade
import random
# Set how many rows and columns we will have
ROW_COUNT = 70
COLUMN_COUNT = 128
# This sets the WIDTH and HEIGHT of each grid location
CELL_WIDTH = 15
CELL_HEIGHT = 15
# This sets the margin between each cell
# and on the edges of the screen.
CELL_MARGIN = 0
# Do the math to figure out our screen dimensions
SCREEN_WIDTH = (CELL_WIDTH + CELL_MARGIN) * COLUMN_COUNT + CELL_MARGIN
SCREEN_HEIGHT = (CELL_HEIGHT + CELL_MARGIN) * ROW_COUNT + CELL_MARGIN
SCREEN_TITLE = "Conway's Game of Life"
# Colors and alpha values
ALIVE_COLOR = arcade.color.BISTRE
BACKGROUND_COLOR = arcade.color.ANTIQUE_WHITE
ALPHA_ON = 255
ALPHA_OFF = 0
def create_grids():
"""
Create a 2D and 1D grid of sprites. We use the 1D SpriteList for drawing,
and the 2D list for accessing via grid. Both lists point to the same set of
sprites.
"""
# One dimensional list of all sprites in the two-dimensional sprite list
grid_sprites_one_dim = arcade.SpriteList()
# This will be a two-dimensional grid of sprites to mirror the two
# dimensional grid of numbers. This points to the SAME sprites that are
# in grid_sprite_list, just in a 2d manner.
grid_sprites_two_dim = []
# Create a list of sprites to represent each grid location
for row in range(ROW_COUNT):
grid_sprites_two_dim.append([])
for column in range(COLUMN_COUNT):
# Make the sprite as a soft circle
sprite = arcade.SpriteCircle(CELL_WIDTH // 2, ALIVE_COLOR, soft=True)
# Position the sprite
x = column * (CELL_WIDTH + CELL_MARGIN) + (CELL_WIDTH / 2 + CELL_MARGIN)
y = row * (CELL_HEIGHT + CELL_MARGIN) + (CELL_HEIGHT / 2 + CELL_MARGIN)
sprite.center_x = x
sprite.center_y = y
# Add the sprite to both lists
grid_sprites_one_dim.append(sprite)
grid_sprites_two_dim[row].append(sprite)
return grid_sprites_one_dim, grid_sprites_two_dim
def randomize_grid(grid: arcade.SpriteList):
""" Randomize the grid to alive/dead """
for cell in grid:
pick = random.randrange(2)
if pick:
cell.alpha = ALPHA_ON
else:
cell.alpha = ALPHA_OFF
class MyGame(arcade.Window):
"""
Main application class.
"""
def __init__(self, width: int, height: int, title: str):
"""
Set up the application.
"""
super().__init__(width, height, title)
self.background_color = BACKGROUND_COLOR
# We need two layers. One holds the current state of our grid, the other
# holds the next frame's state. We flip back and forth between the two.
grid_sprites_one_dim1, grid_sprites_two_dim1 = create_grids()
grid_sprites_one_dim2, grid_sprites_two_dim2 = create_grids()
self.layers_grid_sprites_one_dim = [grid_sprites_one_dim1, grid_sprites_one_dim2]
self.layers_grid_sprites_two_dim = [grid_sprites_two_dim1, grid_sprites_two_dim2]
self.cur_layer = 0
randomize_grid(self.layers_grid_sprites_one_dim[0])
def on_draw(self):
""" Render the screen. """
# Clear all pixels in the window
self.clear()
self.layers_grid_sprites_one_dim[0].draw()
def on_update(self, delta_time: float):
""" Update the grid """
# Flip layers
if self.cur_layer == 0:
layer1 = self.layers_grid_sprites_two_dim[0]
layer2 = self.layers_grid_sprites_two_dim[1]
self.cur_layer = 1
else:
layer1 = self.layers_grid_sprites_two_dim[1]
layer2 = self.layers_grid_sprites_two_dim[0]
self.cur_layer = 0
# Count the neighbors that are alive
for row in range(ROW_COUNT):
for column in range(COLUMN_COUNT):
live_neighbors = 0
# -1 -1
if row > 0 and column > 0 \
and layer1[row - 1][column - 1].alpha == ALPHA_ON:
live_neighbors += 1
# -1 0
if row > 0 and layer1[row - 1][column].alpha == ALPHA_ON:
live_neighbors += 1
# -1 +1
if row > 0 and column < COLUMN_COUNT - 1\
and layer1[row - 1][column + 1].alpha == ALPHA_ON:
live_neighbors += 1
# 0 +1
if column < COLUMN_COUNT - 1 \
and layer1[row][column + 1].alpha == ALPHA_ON:
live_neighbors += 1
# +1 +1
if row < ROW_COUNT - 1 \
and column < COLUMN_COUNT - 1 \
and layer1[row + 1][column + 1].alpha == ALPHA_ON:
live_neighbors += 1
# +1 0
if row < ROW_COUNT - 1 and layer1[row + 1][column].alpha == ALPHA_ON:
live_neighbors += 1
# +1 -1
if row < ROW_COUNT - 1 and column > 0 \
and layer1[row + 1][column - 1].alpha == ALPHA_ON:
live_neighbors += 1
# 0 -1
if column > 0 and layer1[row][column - 1].alpha == ALPHA_ON:
live_neighbors += 1
"""
Implement Conway's game of life rules
Any live cell with two or three live neighbours survives.
Any dead cell with three live neighbours becomes a live cell.
All other live cells die in the next generation. Similarly, all other dead cells stay dead.
"""
if layer1[row][column].alpha == ALPHA_ON and (live_neighbors == 2 or live_neighbors == 3):
if layer2[row][column].alpha == ALPHA_OFF:
layer2[row][column].alpha = ALPHA_ON
elif layer1[row][column].alpha == ALPHA_OFF and live_neighbors == 3:
if layer2[row][column].alpha == ALPHA_OFF:
layer2[row][column].alpha = ALPHA_ON
else:
if layer2[row][column].alpha == ALPHA_ON:
layer2[row][column].alpha = ALPHA_OFF
def main():
""" Main function - starting point to the program """
window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
window.center_window()
arcade.run()
if __name__ == "__main__":
main()
|