-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStateSpace.py
More file actions
135 lines (114 loc) · 4.86 KB
/
Copy pathStateSpace.py
File metadata and controls
135 lines (114 loc) · 4.86 KB
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
import random
import os
import time
import string
debug = False
class StateSpace:
def __init__(self, width, height, init_type = "random"):
self.width = width # number of columns
self.height = height # number of rows
if init_type == "random":
self.state_space = self.rand_state_init()
elif init_type == "dead":
self.state_space = self.dead_state_init()
elif init_type == "user":
self.state_space = None
self.x_max = height-1 # bottom-most x coordinate in graph
self.y_max = width-1 # right-most y coordinate in graph
def rand_state_init(self):
# generates and returns a randomly initiated "mixed" or "dead and alive"
# state_space of dimensions width*height
state_space = []
for i in range (self.height):
row = []
for j in range(self.width):
row.append(random.randint(0,1))
state_space.append(row)
return state_space
def dead_state_init(self):
# generates and returns a fully "dead" state_space of dimensions width*height
state_space = []
for i in range (self.height):
row = []
for j in range(self.width):
row.append(0)
state_space.append(row)
return state_space
def cell_growth(self, x, y):
# takes cell coordinates [x][y] and produces a map of the cells neighborhood
# x -> row position of cell
# y -> column position of cell
cell = self.state_space[x][y] # cell specified through passed in parameters
neigborhood_map = [ # a coordinate map of all cell(x,y)'s neighbors
[[x-1, y-1], [x-1, y+0], [x-1, y+1]],
[[x+0, y-1], [x+0, y+0], [x+0, y+1]],
[[x+1, y-1], [x+1, y+0], [x+1, y+1]]
]
# pruning the nieghborhood based on edge cases (i.e. if cell is touching wall or vertex in the grid)
if x == 0:
# north of neighborhood removed if cell is touching top wall of grid
neigborhood_map = neigborhood_map[1::]
elif x == self.x_max:
# south of neighborhood removed if cell is touching top wall of grid
neigborhood_map = neigborhood_map[0:-1]
if y == 0:
# east of neighborhood removed if cell is touching left wall
for i in neigborhood_map:
del i[0]
elif y == self.y_max:
# west of neighborhood removed if cell is touching left wall
for i in neigborhood_map:
del i[-1]
neighborcount = 0 # variable to hold count of all existing neighbors
for i in neigborhood_map:
for n in i:
n_x = n[0] # height coordinate for neighbor
n_y = n[1] # width coordinate for neighhbor
if self.state_space[n_x][n_y] == 1:
neighborcount += 1
if cell == 1:
# removing cell(x,y) from count. This was the easest way to not have issues with map dimensions while pruning.
neighborcount -= 1
# Cell(x,y) either dies (0) or lives (1), based of its neighborcount
# within the constraints of the game of life
if cell == 1 and neighborcount < 2 or neighborcount > 3:
# too many or too few neighbors for a living cell to stay alive
return 0
elif cell == 0 and neighborcount != 3:
# not enough neighbors for reproduction/ a dead cell to spring to life
return 0
else: # all other conditions just right for reproduction.
return 1
def run(self, iterations):
# runs the game for specified number of iterations
for i in range(iterations):
self.take_step()
print("iteration:", i) # outputs iteration count to screen.
def take_step(self):
# generates next state and populates it based off of
# current living/dead cells and their nieghborhoods
fresh_space = self.dead_state_init()
# i -> every row in the gridworld/state_space
for i in range(self.height):
# j -> every column in the gridworld/state_space
for j in range(self.width):
fresh_space[i][j] = self.cell_growth(i, j)
self.state_space = fresh_space
print(self.render())
time.sleep(.02)
cls()
def render(self):
# pretty-printing state_space to screen
render_string = ""
for i in self.state_space:
render_string += " | "
for j in i:
if j == 1:
render_string += "[.]"
else:
render_string += " "
render_string += " |\n"
return render_string
def cls() -> None:
# clears screen -> used to "flipbook" the output to create a video effect
os.system('cls' if os.name=='nt' else 'clear')