In [ ]:
import matplotlib.pyplot as plt
from matplotlib.patches import RegularPolygon
import matplotlib.patches as mpatches
import numpy as np
import scipy.stats as stat
import random
In [ ]:
sums = list(range(2,13))
prob_dict = {}
for s in sums:
    prob_dict[s] = 0

for i in range(1,7):
    for j in range(1,7):
        prob_dict[i+j] += 1


for k in prob_dict.keys():
    prob_dict[k] = prob_dict[k]/36

prob_dict[0] = 0

prob_dict
Out[ ]:
{2: 0.027777777777777776,
 3: 0.05555555555555555,
 4: 0.08333333333333333,
 5: 0.1111111111111111,
 6: 0.1388888888888889,
 7: 0.16666666666666666,
 8: 0.1388888888888889,
 9: 0.1111111111111111,
 10: 0.08333333333333333,
 11: 0.05555555555555555,
 12: 0.027777777777777776,
 0: 0}
In [ ]:
import math
In [ ]:
class tile(object):

    def __init__(self, x, y, r, value, resource, id):
        self.x = x
        self.y = y
        self.r = r
        self.value = value
        self.resource = resource
        self.id = id


class point(object): 
    def __init__(self, x, y, r, id):
        self.x = x
        self.y = y
        self.r = r
        self.tiles = [] 
        self.id = id
        self.resource_dict = {}

        y_shift = r/2
        x_shift = r/2*np.sqrt(3)  
        self.neighbors = [[self.x-x_shift, self.y+y_shift], [self.x+x_shift, self.y+y_shift], [self.x, self.y-y_shift],
                           [self.x, self.y+y_shift], [self.x-x_shift, self.y-y_shift], [self.x+x_shift, self.y-y_shift]] 
        
        self.neighbor_point_ids = []

    def next_to(self, tile, buffer=0.45):
        for i in range(len(self.neighbors)):
            temp = self.neighbors[i]
            if abs(temp[0]-tile.x)<buffer and abs(temp[1]-tile.y)<buffer:
                return True
        return False
    
    
    def add_tile(self, tile ):
        self.tiles = self.tiles + [tile]
        t_resource = tile.resource
        if t_resource in self.resource_dict.keys():
            self.resource_dict[t_resource] += prob_dict[tile.value]
        else:
            self.resource_dict[t_resource] = prob_dict[tile.value]

    def get_value(self):
        temp = 0
        for k in self.resource_dict.keys():
            temp += self.resource_dict[k]
        return temp
        

        
In [ ]:
def create_board_layout(a,b,r):

    widths = list(range(a,b+1,1)) + list(range(b-1,a-1,-1))
    hieghts = list(range(len(widths)))
    n = sum(widths)

    y_shift = r/2
    x_shift = r/2*np.sqrt(3)

    x_points = []
    y_points = []
    tiles = []
    count = 0
    for i in range(len(widths)):
        w = widths[i]
        left = (max(widths) - w)/2
        for j in range(w):
            count += 1
            t = tile(j+left, i, r, None, None, count)
            tiles.append(t)

            # upper left
            x_points.append(j + left - x_shift)
            y_points.append(i + y_shift)

            # upper
            x_points.append(j + left)
            y_points.append(i + r)


        # upper right
        x_points.append(j + left + x_shift)
        y_points.append(i + y_shift)

        if i <= len(widths)/2:

            # lower left
            x_points.append(0 + left - x_shift)
            y_points.append(i - y_shift) 

            # lower right
            x_points.append(w - 1 + left + x_shift)
            y_points.append(i - y_shift) 


    # Last Row
    w = min(widths)
    for j in range(w):
        # lower
        x_points.append(j + left)
        y_points.append(0 - r)

        # lower left
        x_points.append(j + left - x_shift)
        y_points.append(0 - y_shift) 

    return tiles, x_points, y_points, n
    
In [ ]:
def draw_board(tiles, r_map, r_labels):
    fig, ax = plt.subplots(1, figsize=(12,12))
    ax.set_facecolor("#cfdfff")
    
    for i in range(n):
        t = tiles[i]
        # Draw Tile
        hexagon = RegularPolygon((t.x, t.y), numVertices=6, radius=r, alpha=1, edgecolor='black', facecolor=r_map[t.resource])
        ax.text(t.x, t.y, t.value)
        ax.text(t.x-0.1, t.y - 0.1, str(prob_dict[values[i]])[:5] )
        ax.add_patch(hexagon)
        plt.autoscale(enable = True)

    patches = []
    for j in range(len(r_labels)):
        patches.append(mpatches.Patch(facecolor=r_map[j], label=r_labels[j], edgecolor="black"))
    ax.legend(handles=patches)

    return fig, ax

def create_points(tiles, x_points, y_points, r):
    # Create Points
    points = []
    point_values = []
    count = 0
    for i in range(m):
        p = point(x_points[i], y_points[i], r, count)
        points.append(p)
        for t in tiles:
            if p.next_to(t):
                p.add_tile(t)          
                #plt.plot([p.x,t.x],[p.y, t.y])
        point_values.append(p.get_value())
        count += 1

    # Find Neighboring Points
    for i in range(m):
        p = points[i]
        for p2 in points:
            if p.next_to(p2):
                if (p.x == p2.x and p.y == p2.y) == False:  
                    p.neighbor_point_ids.append(p2.id)

    return points

def draw_points(points, ranks):
    for i in range(len(points)):
        p = points[i]
        plt.scatter(p.x, p.y, s=1500*p.get_value(), c ="orange", edgecolors="black", zorder=10)
        ax.text(p.x-0.05, p.y-0.05, int(ranks[i]) , zorder=15)

def deep_value(points, max_d):
    m = len(points)
    deep_point_values = np.zeros((m, max_d))
    for j in range(d):
        # iterate through points
        for i in range(m):
            p = points[i]
            if j == 0:
                deep_point_values[i,j] = p.get_value()
            else:
                temp = deep_point_values[i,j-1]
                for id in p.neighbor_point_ids:
                    temp += points[id].get_value()*gamma**j
                deep_point_values[i,j] = temp

    return deep_point_values

def draw_connections(p, ids=None, w=[], color="lightpink"):
    
    if ids == None:
        ids = p.neighbor_point_ids

    for i in range(len(ids)):
        pi = points[ids[i]]
        if len(w) == 0:
            plt.plot([pi.x, p.x], [pi.y, p.y], color=color, linewidth=10)
        else:
            plt.plot([pi.x, p.x], [pi.y, p.y], color=color, linewidth=w[i]*20)

def best_path(points, deep_point_values, d, l, start=None):
    m = len(points)
    seen = []
    if start ==  None:
        ranks = m - stat.rankdata(deep_point_values[:, d], method='min')
        best_i = np.argmin(ranks)
    else:
        best_i = start
    seen.append(best_i)
    pi = points[best_i]
    for i in range(l):
        options = pi.neighbor_point_ids
        for o in options:
            if o in seen:
                options.remove(o)
        neighbor_values = deep_point_values[options, d]
        best_i = pi.neighbor_point_ids[np.argmax(neighbor_values)]
        pi = points[best_i]
        seen.append(best_i)
    return seen

def draw_path(seen, color):
    for i in range(1, len(seen)):
        id1 = seen[i-1]
        id2 = seen[i]
        p1 = points[id1]
        p2 = points[id2]
        plt.plot([p1.x, p2.x], [p1.y, p2.y], color=color, linewidth=10*(1 - i/len(seen)))
In [ ]:
# Set Up Board
r = 1/np.sqrt(3)
gamma = 0.8 # discount factor
tiles, x_points, y_points, n = create_board_layout(3, 5, r)
m = len(x_points)

# Randomly Assign Values
all_nums = [2,2,3,3,4,4,5,5,6,6,8,8,9,9,10,10,11,11,12]
values = random.sample(all_nums, n) #np.random.randint(2, 12, size=n)

# Randomly Assign Resources
# Wheat, Wood, Sheep, Stone, Brick, Desert
all_resources = [0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,4,4,4,5]
resources = random.sample(all_resources, n) #np.random.randint(4, size=n)
r_labels = ["Wheat", "Wood", "Sheep", "Stone", "Brick", "Desert"]
r_map = ["#fcba03", "darkgreen", "#56a870", "#919090","#cc4331", "white"]

for i in range(n):
    t = tiles[i]
    t.resource = resources[i]
    t.value = values[i]

points = create_points(tiles, x_points, y_points, r)

deep_point_values = deep_value(points, 10)
ranks = m - stat.rankdata(deep_point_values[:, 0], method='min')
seen = best_path(points, deep_point_values, 0, 10)
print(seen)

fig, ax = draw_board(tiles, r_map, r_labels)    
draw_points(points, ranks)

best_i = np.argmin(ranks)
best_p = points[best_i]
draw_connections(best_p)

# for id in seen:
#    draw_connections(points[id]) 
draw_path(seen, color="#96037e")

plt.show()  


plt.show() 
[1, 11, 12, 13, 14, 15, 5, 4, 3, 13, 14]
In [ ]:
fig, ax = draw_board(tiles, r_map, r_labels)    
draw_points(points, ranks)

deep_point_values = deep_value(points, 10)
seen = best_path(points, deep_point_values, 0, 20)
print(seen)

# for id in seen:
#    draw_connections(points[id]) 
draw_path(seen, color="#96037e")

plt.show() 
[36, 37, 38, 39, 27, 28, 16, 15, 5, 4, 3, 2, 1, 11, 10, 9, 31, 20, 21, 22, 23]
In [ ]:
import pandas as pd
import seaborn as sns
In [ ]:
vdf = pd.DataFrame(deep_point_values)
vdf.style.background_gradient(cmap ='coolwarm')
Out[ ]:
0 1 2 3 4 5 6 7 8 9
0 0.222222 0.733333 1.142222 1.469333 1.731022 1.940373 2.107854 2.241839 0.000000 0.000000
1 0.305556 0.705556 1.025556 1.281556 1.486356 1.650196 1.781268 1.886125 0.000000 0.000000
2 0.277778 0.677778 0.997778 1.253778 1.458578 1.622418 1.753490 1.858347 0.000000 0.000000
3 0.305556 0.727778 1.065556 1.335778 1.551956 1.724898 1.863252 1.973935 0.000000 0.000000
4 0.277778 0.588889 0.837778 1.036889 1.196178 1.323609 1.425554 1.507110 0.000000 0.000000
5 0.250000 0.583333 0.850000 1.063333 1.234000 1.370533 1.479760 1.567141 0.000000 0.000000
6 0.111111 0.155556 0.191111 0.219556 0.242311 0.260516 0.275079 0.286730 0.000000 0.000000
7 0.111111 0.377778 0.591111 0.761778 0.898311 1.007538 1.094919 1.164824 0.000000 0.000000
8 0.055556 0.100000 0.135556 0.164000 0.186756 0.204960 0.219524 0.231174 0.000000 0.000000
9 0.222222 0.688889 1.062222 1.360889 1.599822 1.790969 1.943886 2.066220 0.000000 0.000000
10 0.361111 0.805556 1.161111 1.445556 1.673111 1.855156 2.000791 2.117300 0.000000 0.000000
11 0.333333 0.777778 1.133333 1.417778 1.645333 1.827378 1.973013 2.089522 0.000000 0.000000
12 0.250000 0.494444 0.690000 0.846444 0.971600 1.071724 1.151824 1.215904 0.000000 0.000000
13 0.250000 0.450000 0.610000 0.738000 0.840400 0.922320 0.987856 1.040285 0.000000 0.000000
14 0.277778 0.633333 0.917778 1.145333 1.327378 1.473013 1.589522 1.682729 0.000000 0.000000
15 0.305556 0.705556 1.025556 1.281556 1.486356 1.650196 1.781268 1.886125 0.000000 0.000000
16 0.222222 0.311111 0.382222 0.439111 0.484622 0.521031 0.550158 0.573460 0.000000 0.000000
17 0.111111 0.200000 0.271111 0.328000 0.373511 0.409920 0.439047 0.462349 0.000000 0.000000
18 0.111111 0.466667 0.751111 0.978667 1.160711 1.306347 1.422855 1.516062 0.000000 0.000000
19 0.055556 0.144444 0.215556 0.272444 0.317956 0.354364 0.383492 0.406793 0.000000 0.000000
20 0.111111 0.311111 0.471111 0.599111 0.701511 0.783431 0.848967 0.901396 0.000000 0.000000
21 0.138889 0.472222 0.738889 0.952222 1.122889 1.259422 1.368649 1.456030 0.000000 0.000000
22 0.277778 0.677778 0.997778 1.253778 1.458578 1.622418 1.753490 1.858347 0.000000 0.000000
23 0.305556 0.772222 1.145556 1.444222 1.683156 1.874302 2.027220 2.149553 0.000000 0.000000
24 0.305556 0.727778 1.065556 1.335778 1.551956 1.724898 1.863252 1.973935 0.000000 0.000000
25 0.222222 0.377778 0.502222 0.601778 0.681422 0.745138 0.796110 0.836888 0.000000 0.000000
26 0.194444 0.394444 0.554444 0.682444 0.784844 0.866764 0.932300 0.984729 0.000000 0.000000
27 0.250000 0.627778 0.930000 1.171778 1.365200 1.519938 1.643728 1.742760 0.000000 0.000000
28 0.250000 0.538889 0.770000 0.954889 1.102800 1.221129 1.315792 1.391522 0.000000 0.000000
29 0.138889 0.450000 0.698889 0.898000 1.057289 1.184720 1.286665 1.368221 0.000000 0.000000
30 0.055556 0.211111 0.335556 0.435111 0.514756 0.578471 0.629444 0.670222 0.000000 0.000000
31 0.111111 0.377778 0.591111 0.761778 0.898311 1.007538 1.094919 1.164824 0.000000 0.000000
32 0.055556 0.188889 0.295556 0.380889 0.449156 0.503769 0.547460 0.582412 0.000000 0.000000
33 0.027778 0.272222 0.467778 0.624222 0.749378 0.849502 0.929602 0.993681 0.000000 0.000000
34 0.166667 0.544444 0.846667 1.088444 1.281867 1.436604 1.560395 1.659427 0.000000 0.000000
35 0.305556 0.683333 0.985556 1.227333 1.420756 1.575493 1.699284 1.798316 0.000000 0.000000
36 0.305556 0.616667 0.865556 1.064667 1.223956 1.351387 1.453332 1.534887 0.000000 0.000000
37 0.222222 0.533333 0.782222 0.981333 1.140622 1.268053 1.369998 1.451554 0.000000 0.000000
38 0.166667 0.611111 0.966667 1.251111 1.478667 1.660711 1.806347 1.922855 0.000000 0.000000
39 0.222222 0.688889 1.062222 1.360889 1.599822 1.790969 1.943886 2.066220 0.000000 0.000000
40 0.166667 0.477778 0.726667 0.925778 1.085067 1.212498 1.314443 1.395999 0.000000 0.000000
41 0.083333 0.327778 0.523333 0.679778 0.804933 0.905058 0.985157 1.049237 0.000000 0.000000
42 0.138889 0.383333 0.578889 0.735333 0.860489 0.960613 1.040713 1.104793 0.000000 0.000000
43 0.138889 0.383333 0.578889 0.735333 0.860489 0.960613 1.040713 1.104793 0.000000 0.000000
44 0.166667 0.544444 0.846667 1.088444 1.281867 1.436604 1.560395 1.659427 0.000000 0.000000
45 0.027778 0.250000 0.427778 0.570000 0.683778 0.774800 0.847618 0.905872 0.000000 0.000000
46 0.111111 0.333333 0.511111 0.653333 0.767111 0.858133 0.930951 0.989205 0.000000 0.000000
47 0.083333 0.238889 0.363333 0.462889 0.542533 0.606249 0.657221 0.697999 0.000000 0.000000
48 0.083333 0.283333 0.443333 0.571333 0.673733 0.755653 0.821189 0.873618 0.000000 0.000000
49 0.111111 0.444444 0.711111 0.924444 1.095111 1.231644 1.340871 1.428252 0.000000 0.000000
50 0.111111 0.377778 0.591111 0.761778 0.898311 1.007538 1.094919 1.164824 0.000000 0.000000
51 0.083333 0.350000 0.563333 0.734000 0.870533 0.979760 1.067141 1.137046 0.000000 0.000000
52 0.194444 0.572222 0.874444 1.116222 1.309644 1.464382 1.588172 1.687205 0.000000 0.000000
53 0.055556 0.166667 0.255556 0.326667 0.383556 0.429067 0.465476 0.494603 0.000000 0.000000
54 0.138889 0.472222 0.738889 0.952222 1.122889 1.259422 1.368649 1.456030 0.000000 0.000000