-
Notifications
You must be signed in to change notification settings - Fork 0
/
life.py
executable file
·164 lines (125 loc) · 4.27 KB
/
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
#!/usr/bin/python3
import time
import os
MOVES = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]
class Bcolors:
HEADER = "\033[95m"
OKBLUE = "\033[94m"
OKGREEN = "\033[92m"
WARNING = "\033[93m"
FAIL = "\033[91m"
ENDC = "\033[0m"
def disable(self):
self.HEADER = ""
self.OKBLUE = ""
self.OKGREEN = ""
self.WARNING = ""
self.FAIL = ""
self.ENDC = ""
def is_position_in_range(pos_x, pos_y, board):
board_size_x = len(board)
board_size_y = len(board[0])
return pos_x >= 0 and pos_x < board_size_x and pos_y >= 0 and pos_y < board_size_y
def get_adjacent_neighbours_count(board, cell):
neighbours = 0
for move in MOVES:
(dx, dy) = move
(cx, cy) = cell
pos_x = cx + dx
pos_y = cy + dy
if is_position_in_range(pos_x, pos_y, board):
if board[pos_x][pos_y] == 1:
neighbours += 1
return neighbours
def get_dead_cells(board, cells):
"""Compute which cells will die on this tick
1. A cell dies if it has less than 2 neighbours (loneliness)
2. A cell also dies if it has more than 3 neighbours (overpopulation)
"""
dead_cells = set()
for cell in cells:
cell_neighbours = get_adjacent_neighbours_count(board, cell)
if cell_neighbours < 2 or cell_neighbours > 3:
dead_cells.add(cell)
return dead_cells
def get_adjacent_neighbours(board, live_cell):
"""
Get squares(neighbours) adjacent to a cell
"""
adjacent_neighbours = []
for move in MOVES:
(dx, dy) = move
(cx, cy) = live_cell
pos_x = cx + dx
pos_y = cy + dy
if is_position_in_range(pos_x, pos_y, board):
if board[pos_x][pos_y] != 1:
adjacent_neighbours.append((pos_x, pos_y))
return adjacent_neighbours
def get_newborn_cells(board, cells):
"""Computes which cells will be born in the next generation
It does so by:
1. Calculating all the neighbours squares for the existing cells
2. Determines if those neighbours squares have 3 adjacent cells
3. If 2 is True then a new cell is born in that square
"""
maybe_newborn_cells = set()
for current_cell in cells:
adjacent_neighbours = get_adjacent_neighbours(board, current_cell)
for neighbour in adjacent_neighbours:
maybe_newborn_cells.add(neighbour)
newborn_cells = []
for maybe_newborn in maybe_newborn_cells:
if get_adjacent_neighbours_count(board, maybe_newborn) == 3:
newborn_cells.append(maybe_newborn)
return newborn_cells
def life(board, cells):
board_copy = board.copy()
newborn_cells = get_newborn_cells(board, cells)
dead_cells = get_dead_cells(board, cells)
live_cells = set(cells).difference(dead_cells)
next_generation = [*newborn_cells, *[live for live in live_cells]]
for newborn in newborn_cells:
(nx, ny) = newborn
board_copy[nx][ny] = 1
for dead in dead_cells:
(dx, dy) = dead
board_copy[dx][dy] = 0
return [board_copy, next_generation]
def print_board(board):
for row in range(len(board)):
for column in range(len(board[row])):
if board[row][column] != 0:
print(f"{Bcolors.OKGREEN}*{Bcolors.ENDC}", end=" ")
else:
print("-", end=" ")
print()
def get_inital_cells(board):
cells = []
for row in range(len(board)):
for column in range(len(board[row])):
if board[row][column] == 1:
cells.append((row, column))
return cells
def read_pattern_from_file(filename):
with open(filename) as f:
board = []
line = f.readline()
while line:
board.append([int(cell) for cell in line.split()])
line = f.readline()
return board
if __name__ == "__main__":
board = read_pattern_from_file("gosper_glider_gun.in")
cells = get_inital_cells(board)
generation = 1
while True:
os.system("clear")
print(f"Generation: {generation}")
print_board(board)
[new_board, next_generation] = life(board, cells)
board = new_board
cells = next_generation
time.sleep(0.3)
os.system("clear")
generation += 1