``````

In [1]:

from ipythonblocks import BlockGrid as bg
from IPython.html.widgets import interact, interactive, fixed
from IPython.html import widgets
import random
import numpy as np
from IPython.display import Image

``````
``````

:0: FutureWarning: IPython widgets are experimental and may change in the future.

``````
``````

In [2]:

#create random x by x grid of 0s,1s,2s
def array_city(x, p1, p2):
p0 = 1-(p1+p2)
p1 = 1-(p0+p2)
p2 = 1-(p0+p1)
grid = (np.random.choice([0, 1 , 2], size = (x, x), p = [p0, p1, p2]))
print (grid)
return grid

``````
``````

In [3]:

interact(array_city,x = (0,20,1), p1 = (0,1,0.1), p2 = (0,1,0.1));

``````
``````

[[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]]

``````
``````

In [4]:

#return value of surrounding neighbors at position (row,col) of grid
def get_neighbors(row,col,grid):
x = len(grid)
#4corners
#top left
if row == 0 and col == 0:
return grid[(1,0)],grid[(1,1)],grid[(0,1)]
#bottom left
elif row == x-1 and col == 0:
return grid[(x-2,0)],grid[(x-1,1)],grid[(x-2,1)]
#bottom right
elif row == x-1 and col == x-1:
return grid[(x-2,x-1)],grid[(x-2,x-2)],grid[(x-1,x-2)]
#top right
elif row == 0 and col == x-1:
return grid[(0,x-2)],grid[(1,x-1)],grid[(1,x-2)]
#edges
#top
elif row == 0 and 1 <= col <= x-2:
return grid[(0,col-1)],grid[(1,col-1)],grid[(1,col)],grid[(1,col+1)],grid[(0,col+1)]
#bottom
elif row == x-1 and 1 <= col <= x-2:
return grid[(x-1,col-1)],grid[(x-2,col-1)],grid[(x-2,col)],grid[(x-2,col+1)],grid[(x-1,col+1)]
#right
elif 1 <= row <= x-2 and col == x-1:
return grid[(row-1,x-1)],grid[(row-1,x-2)],grid[(row,x-2)],grid[(row+1,x-2)],grid[(row+1,x-1)]
#left
elif 1 <= row <= x-2 and col == 0:
return grid[(row-1,0)],grid[(row-1,1)],grid[(row,1)],grid[(row+1,1)],grid[(row+1,0)]
#all middle spaces
else:
return grid[(row-1,col-1)],grid[(row,col-1)],grid[(row+1,col-1)],grid[(row+1,col)],grid[(row+1,col+1)],grid[(row,col+1)],grid[(row-1,col+1)],grid[(row-1,col)]

``````
``````

In [5]:

#create a fixed 3x3 and 10x10 grid for testing
test_grid = np.array([[0,1,2],[2,1,0],[1,0,2]])
presentation_grid = np.array([[1,2,2,0,2,1,2,2,1,0],[1,2,1,2,0,0,0,2,1,2],[0,0,2,1,1,2,2,0,1,2],[2,2,1,1,0,2,1,1,2,0],[0,2,2,1,1,1,0,0,2,1],[0,2,1,2,2,1,0,0,2,1],[2,1,2,1,1,1,2,0,2,1],[0,0,2,1,1,2,2,0,2,1],[0,2,1,2,1,0,2,1,0,0],[0,0,2,2,1,1,2,2,1,2]])
print (test_grid)
print ()
print (presentation_grid)

``````
``````

[[0 1 2]
[2 1 0]
[1 0 2]]

[[1 2 2 0 2 1 2 2 1 0]
[1 2 1 2 0 0 0 2 1 2]
[0 0 2 1 1 2 2 0 1 2]
[2 2 1 1 0 2 1 1 2 0]
[0 2 2 1 1 1 0 0 2 1]
[0 2 1 2 2 1 0 0 2 1]
[2 1 2 1 1 1 2 0 2 1]
[0 0 2 1 1 2 2 0 2 1]
[0 2 1 2 1 0 2 1 0 0]
[0 0 2 2 1 1 2 2 1 2]]

``````
``````

In [6]:

#test each position in 3x3 grid
assert get_neighbors(0,0,test_grid) == (2,1,1) #top left
assert get_neighbors(0,2,test_grid) == (1,0,1) #top right
assert get_neighbors(2,0,test_grid) == (2,0,1) #bottom left
assert get_neighbors(2,2,test_grid) == (0,1,0) #bottom right
assert get_neighbors(0,1,test_grid) == (0,2,1,0,2) #top
assert get_neighbors(2,1,test_grid) == (1,2,1,0,2)#bottom
assert get_neighbors(1,0,test_grid) == (0,1,1,0,1) #left
assert get_neighbors(1,2,test_grid) == (2,1,1,0,2) #right
assert get_neighbors(1,1,test_grid) == (0,2,1,0,2,0,2,1)#middle

``````
``````

In [7]:

#compute satisfaction of position (row,col) in grid
def sat_per(row,col,grid):
n = get_neighbors(row,col,grid)
zeros,ones,twos = 0,0,0
for i in n:
if i == 0:
zeros += 1
elif i == 1:
ones += 1
else:
twos += 1
p = (zeros/len(n),ones/len(n),twos/len(n))
if grid[row,col] == 0:
return p[0]
elif grid[row,col] == 1:
return p[1]
else:
return p[2]

``````
``````

In [9]:

assert sat_per(0,0,test_grid) == 0 #top left
assert sat_per(0,2,test_grid) == 0 #top right
assert sat_per(2,2,test_grid) == 0 #bottom right
assert sat_per(0,1,test_grid) == 0.2 #top
assert sat_per(2,1,test_grid) == 0.2 #bottom
assert sat_per(1,0,test_grid) == 0 #left
assert sat_per(1,2,test_grid) == 0.2 #right
assert sat_per(1,1,test_grid) == 0.25#middle

``````
``````

In [10]:

#return coordinates of every block that is satisfied in grid
def sat(satisfaction,grid):
sat = []
x = len(grid)
for row in range(0,x):
for col in range(0,x):
if grid[row,col] == 1 and sat_per(row,col,grid) >= satisfaction:
sat.append((row,col))
elif grid[row,col] == 2 and sat_per(row,col,grid) >= satisfaction:
sat.append((row,col))
else:
pass
np.random.shuffle(sat)
return sat

``````
``````

In [13]:

assert sat(0.34,test_grid) == []
#Cannot write more assert cases because of the np.random.shuffle(sat) line

``````
``````

In [14]:

#return coordinates of every unsatisfied block in grid
def unsat(satisfaction,grid):
unsat = []
x = len(grid)
for row in range(0,x):
for col in range(0,x):
if grid[row,col] == 1 and sat_per(row,col,grid) < satisfaction:
unsat.append((row,col))
elif grid[row,col] == 2 and sat_per(row,col,grid) < satisfaction:
unsat.append((row,col))
else:
pass
np.random.shuffle(unsat)
return unsat

``````
``````

In [17]:

#return coordinates of every empty block in grid
def empty(grid):
empty = []
x = len(grid)
for row in range(0,x):
for col in range(0,x):
if grid[row,col] == 0:
empty.append((row,col))
#np.random.shuffle(empty)
return empty

``````
``````

In [20]:

#return True if changing position (row,col) to new_value makes position (row,col) satisfied, else return False
def should_move(grid,row,col,satisfaction,new_value):
temp_grid = grid.copy()
temp_grid[row,col] = new_value
if sat_per(row,col,temp_grid) >= satisfaction:
return True
else:
return False

``````
``````

In [23]:

assert should_move(test_grid,2,1,0.4,1) == True
assert should_move(test_grid,2,1,0.4,2) == True
assert should_move(test_grid,1,2,0.4,1) == True
assert should_move(test_grid,1,2,0.4,2) == True
assert should_move(test_grid,0,0,1,1) == False
assert should_move(test_grid,2,1,0.7,1) == False

``````
``````

In [24]:

#take value of position (row,col), assign that value to a random empty position.  If satisfied, swap values.
def do_move(grid,row,col,satisfaction):
value = grid[row,col]
#reason for np.random.shuffle
e = empty(grid)
for i,j in e:
if should_move(grid,i,j,satisfaction,value):
grid[row,col] = 0
grid[i,j] = value
break

``````
``````

In [25]:

#run do_move on every coordinate in list of unsatisfied positions
def move_all(satisfaction,grid):
u = unsat(satisfaction,grid)
for i,j in u:
do_move(grid,i,j,satisfaction)

``````
``````

In [26]:

#keep running move_all on grid until every block reaches satisfaction
def sat_all(grid,satisfaction):
x = len(grid)
i = 0
for row in range(0,x):
for col in range(0,x):
if sat_per(row,col,grid) < satisfaction:
move_all(satisfaction,grid)
i+=1
else:
if sat_per(row,col,grid) >= satisfaction:
pass
print ("Number of loops:",i)

``````
``````

In [28]:

def visualize_rwb(grid):
g = bg(grid.shape[0], grid.shape[0],block_size = 7)
for row in range(g.height):
for col in range(g.width):
block = g[row,col]
if grid[row,col] == 0:
block.blue = 1000
block.red = 1000
block.green = 1000
if grid[row,col] == 1:
block.blue = 1000
block.red = 0
block.green = 0
if grid[row,col] == 2:
block.red = 1000
block.green = 0
block.blue = 0
return g

``````
``````

In [29]:

#visualize a grid using camo
def visualize(grid):
g = bg(grid.shape[0], grid.shape[0],block_size = 7)
for row in range(g.height):
for col in range(g.width):
block = g[row,col]
if grid[row,col] == 0:
block.blue = 1000
block.red = 1000
block.green = 1000
if grid[row,col] == 1:
block.blue = 39
block.red = 99
block.green = 50
if grid[row,col] == 2:
block.red = 30
block.green = 99
block.blue = 39
return g

``````
``````

In [30]:

g = array_city(100,0.45,0.45)
visualize_rwb(g)

``````
``````

[[1 2 2 ..., 2 2 1]
[2 2 2 ..., 2 0 2]
[2 1 1 ..., 2 2 1]
...,
[1 2 2 ..., 2 2 0]
[2 2 1 ..., 2 2 1]
[2 1 1 ..., 1 2 1]]

Out[30]:

table.blockgrid {border: none;} .blockgrid tr {border: none;} .blockgrid td {padding: 0px;} #blocksdb078b43-2fb8-4120-871a-e4a244f490a2 td {border: 1px solid white;}``````