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]:

In [31]:
sat_all(g,0.4)
visualize_rwb(g)


Number of loops: 48
Out[31]:

In [32]:
sat_all(g,0.4)
visualize(g)


Number of loops: 38
Out[32]:

In [ ]: