-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsim.py
144 lines (126 loc) · 3.41 KB
/
sim.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env python
# encoding: utf-8
"""
sim.py
CS266 Ant Sim
"""
EPS = 0.000001
import numpy as np
from param import G
from ant import Ant
from physics import Physics
from error import *
from pyramid import *
def norm(v):
return np.sqrt(np.dot(v,v))
class Joint(object):
def __init__(self, at, to, num):
self.at = at
self.to = to
self.vector = np.array([at[0],at[1]]) - np.array([to[0],to[1]], dtype=np.float32)
self.vector /= norm(self.vector)
if num != -1:
self.num = num
else:
self.num = G.numJoints
if not G.jointRef.has_key(at):
G.jointRef[at] = []
G.jointRef[at].append(self)
if -1 == num and to[1] > -1:
Joint(to, at, G.numJoints)
else:
G.numJoints+=1
def force(self):
return G.jointData[self.num]
def add(self, val):
G.jointData[self.num] += val
def getAdjacent((x,y)):
neighbors = []
if x > 0:
neighbors.append((x-1, y))
if y > 0:
neighbors.append((x-1, y-1))
if y < G.numBlocksY-1:
neighbors.append((x-1, y+1))
if x < G.numBlocksX-1:
neighbors.append((x+1, y))
if y > 0:
neighbors.append((x+1, y-1))
if y < G.numBlocksY-1:
neighbors.append((x+1, y+1))
if y > 0:
neighbors.append((x, y-1))
if y < G.numBlocksY-1:
neighbors.append((x, y+1))
return neighbors
class Sim(object):
def __init__(self):
G.state = np.zeros((G.numBlocksX, G.numBlocksY), dtype=np.int)
G.weight = np.ones((G.numBlocksX, G.numBlocksY))
self.antId = 0
if G.DeterministicAnts:
self.ant = Pyramid(self.antId)
self.y = self.ant.y
self.oldy = self.y
else:
self.ant = Ant(self.antId)
self.numAnts = 1
self.maxHeight = 0
G.jointData = np.zeros((G.numBlocksX * G.numBlocksY * 3))
G.numJoints = 0
G.jointRef = {}
def step(self):
if not self.ant.settled:
try:
self.ant.move()
except Error as e:
raise e
else:
if self.ant.y > self.maxHeight:
self.maxHeight = self.ant.y
if self.checkBridge():
return False
self.addJoints(self.ant)
self.antId = self.antId + 1
self.numAnts += 1
if G.DeterministicAnts:
self.ant = Pyramid(self.antId)
self.oldy = self.y
self.y = self.ant.y
if self.y != self.oldy:
Physics.resetPhysics()
Physics.checkPhysics()
else:
self.ant = Ant(self.antId)
Physics.resetPhysics()
Physics.checkPhysics()
self.updateShaking()
return True
def addJoints(self, ant):
for adjacent in getAdjacent(ant.pos):
if G.state[adjacent]:
Joint(ant.pos, adjacent, -1)
# attach anchor joints
if ant.y == 0:
Joint(ant.pos, (ant.x, ant.y-1), -1)
Joint(ant.pos, (ant.x-1, ant.y-1), -1)
Joint(ant.pos, (ant.x+1, ant.y-1), -1)
def getForces(self, (x,y)):
return [f.force() for f in G.jointRef[(x,y)]]
def updateShaking(self):
for coord in G.jointRef.keys():
forces = self.getForces(coord)
maxForce = max(map(abs, forces))
if maxForce > G.killThreshold - G.EPS:
G.state[coord] = G.DEAD
elif maxForce > G.shakeThreshold - 2*G.EPS:
G.state[coord] = G.SHAKING
else:
G.state[coord] = G.NORMAL
def checkBridge(self):
deadAnts = [(x,y) for x in range(G.state.shape[0]) for y in range(G.state.shape[1]) if G.state[(x,y)] == G.DEAD]
if deadAnts:
raise BridgeFailure("Bridge collapsed at coordinate(s) %s" % " ".join(map(repr, deadAnts)))
if len(filter(lambda coord: G.state[coord] != G.NOANT, [(x,G.numBlocksY-1) for x in range(G.state.shape[0])])) > 0:
raise Success("Congratulations! Success has been raised!")
return False