-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathboard.py
120 lines (92 loc) · 3.84 KB
/
board.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
from typing import Tuple
import numpy as np
import scipy as sp
from pyrsistent import freeze, pset, s, v
from pyrsistent.typing import PSet
from toolz.curried import map, partial, pipe
from my_types import Complex, Cycle
from settings import BOARD_SIZE, BORDER_SCALE, EPSILON, SEED
from topology import (
closure,
edges_from_cycles,
faces_from_edges,
outer_edges_from_cycle,
verts_from_edges,
)
class Board:
def __init__(self) -> None:
if SEED is not None:
np.random.seed(SEED)
def reflect(u: np.ndarray, w: np.ndarray, a: float) -> np.ndarray:
return u - 2 * np.broadcast_to(w, u.shape) * (
np.reshape(np.dot(u, w) - a, (len(u), 1))
)
control_points = np.random.rand(BOARD_SIZE, 2) - 0.5
reflect_control_points = partial(reflect, control_points)
down_reflect = reflect_control_points(np.array([0, 1]), -0.5)
up_reflect = reflect_control_points(np.array([0, 1]), 0.5)
left_reflect = reflect_control_points(np.array([1, 0]), -0.5)
right_reflect = reflect_control_points(np.array([1, 0]), 0.5)
extended_points = np.concatenate(
(control_points, up_reflect, down_reflect, left_reflect, right_reflect)
)
voronoi = sp.spatial.Voronoi(extended_points)
self.cycles = freeze(
np.array(voronoi.regions)[voronoi.point_region[: voronoi.npoints // 5]]
)
edges = edges_from_cycles(self.cycles)
verts = verts_from_edges(edges)
self.points, self.blue_base, self.red_base, self.blue_base_cs, self.red_base_cs = self.make_border(
voronoi.vertices, edges
)
self.xs = verts | edges | self.blue_base | self.red_base
@staticmethod
def make_border(
points: np.ndarray, edges: Complex
) -> Tuple[np.ndarray, Complex, Complex, PSet[Cycle], PSet[Cycle]]:
def first_index(array: np.ndarray, value: np.ndarray) -> float:
return next(
i for i, _ in enumerate(array) if np.linalg.norm(value - _) < EPSILON
)
first_index_points = partial(first_index, points)
corners = v(v(-0.5, 0.5), v(-0.5, -0.5), v(0.5, -0.5), v(0.5, 0.5))
ul, dl, dr, ur = pipe(corners, map(np.array), map(first_index_points))
max_ind = len(points)
cul = max_ind
cdl = max_ind + 1
cdr = max_ind + 2
cur = max_ind + 3
left_c = v(ul, cul, cdl, dl)
right_c = v(dr, cdr, cur, ur)
down_c = v(dl, cdl, cdr, dr)
up_c = v(ur, cur, cul, ul)
red_base_cs = s(left_c, right_c)
blue_base_cs = s(up_c, down_c)
def border_edges(
pts: np.ndarray, es: Complex, coord: int, side: float
) -> Complex:
return pset(
edge
for edge in es
if all(
np.linalg.norm(pts[vert][coord] - side) < EPSILON for vert in edge
)
)
border_edges_from_square_side = partial(border_edges, points, edges)
left_faces = faces_from_edges(
border_edges_from_square_side(0, -0.5) | outer_edges_from_cycle(left_c)
)
right_faces = faces_from_edges(
border_edges_from_square_side(0, 0.5) | outer_edges_from_cycle(right_c)
)
down_faces = faces_from_edges(
border_edges_from_square_side(1, -0.5) | outer_edges_from_cycle(down_c)
)
up_faces = faces_from_edges(
border_edges_from_square_side(1, 0.5) | outer_edges_from_cycle(up_c)
)
red_base = closure(left_faces | right_faces)
blue_base = closure(down_faces | up_faces)
border_points = np.array(corners) * BORDER_SCALE
aug_points = np.concatenate((points, border_points))
return aug_points, blue_base, red_base, blue_base_cs, red_base_cs