-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path39_Dropbox_Conways_Game_of_Life.py
executable file
·193 lines (145 loc) · 7.17 KB
/
39_Dropbox_Conways_Game_of_Life.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
189
190
191
192
193
"""
Conway's Game of Life takes place on an infinite two-dimensional
board of square cells. Each cell is either dead or alive, and at each tick,
the following rules apply:
- Any live cell with less than two live neighbours dies.
- Any live cell with two or three live neighbours remains living.
- Any live cell with more than three live neighbours dies.
- Any dead cell with exactly three live neighbours becomes a live cell.
- A cell neighbours another cell if it is horizontally, vertically, or diagonally adjacent.
Implement Conway's Game of Life. It should be able to be initialized with a starting list
of live cell coordinates and the number of steps it should run for. Once initialized,
it should print out the board state at each step. Since it's an infinite board,
print out only the relevant coordinates, i.e. from the top-leftmost live cell to
bottom-rightmost live cell.
You can represent a live cell with an asterisk (*) and a dead cell with a dot (.).
"""
import copy
class GameOfLife:
def __init__(self, alive_coordinates: list, steps=0):
# self.board, new_alive_coordinates= self.define_board(alive_coordinates)
self.board = self.define_board(alive_coordinates)
self.print_board()
print('\n------------\n')
for i in range(steps):
print("Step number: {}\n".format(i))
self.board = self.tick()
self.print_board()
print('\n------------\n')
def tick(self):
# pad the board before simulation
padded_board = self.pad_board(self.board)
temp_board = copy.deepcopy(padded_board)
new_alive_coordinates = list() # store alive cell coordinates to later prune the no-active areas of the board.
board_rows = len(padded_board)
board_cols = len(padded_board[0])
# make changes in temp board looking at padded board
for row in range(board_rows):
for col in range(board_cols):
neighbours = self.get_neighbours(padded_board, pos=(row, col))
num_alive_neighbours = sum(neighbours)
cell = padded_board[row][col] # look at the cell itself
# check cell state
if cell == 1:
# cell is alive
if num_alive_neighbours > 3 or num_alive_neighbours < 2:
#cell dies
temp_board[row][col] = 0
else:
# otherwise continue living
new_alive_coordinates.append((row,col))
else:
# cell is in dead state
if num_alive_neighbours == 3:
# cell rises from the dead
temp_board[row][col] = 1
new_alive_coordinates.append((row,col))
# prune empty rows and cols by figuring out where alive cells are
min_row = min(new_alive_coordinates, key=lambda x: x[0])[0]
max_row = max(new_alive_coordinates, key=lambda x: x[0])[0]
min_col = min(new_alive_coordinates, key=lambda x: x[1])[1]
max_col = max(new_alive_coordinates, key=lambda x: x[1])[1]
temp_board = temp_board[min_row:max_row+1] # remove non-active rows
for i in range(len(temp_board)): # remove non-active cols
temp_board[i] = temp_board[i][min_col:max_col+1]
return temp_board
@staticmethod
def pad_board(board):
# make changes in temp board looking at padded_board
padded_board = copy.deepcopy(board)
# create empty row, same size as the board cols
empty_row = [0 for _ in range(len(board[0]))]
# -> add to empty rows before and after the board
padded_board = [empty_row] + padded_board + [empty_row]
# -> add empty col before and after row
for i in range(len(padded_board)):
padded_board[i] = [0] + padded_board[i] + [0]
return padded_board
def define_board(self, alive_coordinates):
min_row = min(alive_coordinates, key=lambda x: x[0])[0]
max_row = max(alive_coordinates, key=lambda x: x[0])[0]
min_col = min(alive_coordinates, key=lambda x: x[1])[1]
max_col = max(alive_coordinates, key=lambda x: x[1])[1]
# create board
board = [[0 for _ in range(max_col-min_col+1)] for _ in range(max_row-min_row+1)]
# new_coordinates = list()
# mark the alive coordinates
for cell in alive_coordinates:
row, col= cell
row -=min_row
col -=min_col
board[row][col] = 1
# new_coordinates.append((row, col)) # new alive cell after scaling rows and cols
return board#, new_coordinates
@staticmethod
def get_neighbours(board, pos):
row, col = pos # position of target cell
board_rows = len(board)
board_cols = len(board[0])
neighbours = []
for i in [-1, 0, 1]:
neighbour_row = row + i
# check for out of bound rows
if neighbour_row >= board_rows or neighbour_row < 0:
continue
for j in [-1, 0, 1]:
neighbour_col = col + j
# check for out of bound cols
if neighbour_col >= board_cols or neighbour_col < 0:
continue
# ignore the cell it self, only interested in neighbours
if neighbour_col == col and neighbour_row == row:
continue
neighbours.append(board[neighbour_row][neighbour_col])
return neighbours
def print_board(self):
board_rows = len(self.board)
board_cols = len(self.board[0])
for row in range(board_rows):
for col in range(board_cols):
if self.board[row][col] == 1:
print('*', end=' ')
else:
print('.', end=' ')
print(end='\n') # new line
if __name__ == '__main__':
#Conway = GameOfLife([(5, 0), (6, 1), (1, 2), (1, 1)], steps=3)
#Conway = GameOfLife(alive_coordinates=[(0,0), (1,0), (2,2)], steps=5)
# Conway = GameOfLife(alive_coordinates=[(1, 0), (2, 1), (0, 2), (1, 2), (2, 2)], steps=5)
# Conway = GameOfLife(alive_coordinates=[(0, 0), (1, 0), (1, 1), (1,5)], steps=5)
# Conway = GameOfLife(alive_coordinates=[(0, 0), (1, 0), (1, 1), (1, 5), (2,5), (2,6)], steps=4)
# Conway = GameOfLife(alive_coordinates=[(0, 0), (1, 0), (1, 1),
# (2, 5), (2, 6), (2, 7),
# (5, 10)], steps=4)
# https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Examples_of_patterns
# Toad
# Conway = GameOfLife(alive_coordinates=[(2, 5), (2, 6), (2, 7),
# (3,6), (3,7),(3,8)], steps=4)
# blinker
# Conway = GameOfLife(alive_coordinates=[(2, 5), (2, 6), (2, 7)], steps=4)
# beacon
# Conway = GameOfLife(alive_coordinates=[(2, 1), (1, 1), (1, 2),
# (4, 3), (4, 4), (3, 4)], steps=8)
# glider
Conway = GameOfLife(alive_coordinates=[(1, 3), (2, 3), (3, 3),
(2, 1), (3, 2)], steps=11)