-
Notifications
You must be signed in to change notification settings - Fork 0
/
common_algorithms.py
129 lines (109 loc) · 4.28 KB
/
common_algorithms.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
import tron, time, sys
from collections import deque
class Floodfill:
"""
Implementation of the floodfill algorithm to fill the free area of the board
as efficiently as possible.
"""
def execute(self, board, origin, exclude=[]):
start = time.clock()
visited = []
queue = deque()
queue.append(origin)
while queue:
node = queue.popleft()
if node in visited:
continue
west = self.findFurthestNodeInDirection(board, node, tron.WEST, exclude)
east = self.findFurthestNodeInDirection(board, node, tron.EAST, exclude)
westToEast = west
northInterrupted = True
southInterrupted = True
while westToEast != board.rel(tron.EAST, east):
north = board.rel(tron.NORTH, westToEast)
if not northInterrupted and (not board.passable(north) or north in exclude or north in visited):
northInterrupted = True
elif northInterrupted and board.passable(north) and north not in exclude and north not in visited:
queue.append(north)
northInterrupted = False
south = board.rel(tron.SOUTH, westToEast)
if not southInterrupted and (not board.passable(south) or south in exclude or south in visited):
southInterrupted = True
elif southInterrupted and board.passable(south) and south not in exclude and south not in visited:
queue.append(south)
southInterrupted = False
visited.append(westToEast)
westToEast = board.rel(tron.EAST, westToEast)
tron.log("FLOODFILL TOOK: " + str(time.clock() - start))
return visited
def floodfillScore(self, board, origin, exclude=[]):
floodfilled = self.execute(board, origin, exclude)
deadCorners = [node for node in floodfilled if len(board.adjacentImpassable(node)) == 3]
return len(floodfilled) - len(deadCorners) + min(len(deadCorners), 1)
def findFurthestNodeInDirection(self, board, start, dir, exclude=[]):
loc = start
newLoc = board.rel(dir, loc)
while board.passable(newLoc) and newLoc not in exclude:
loc = newLoc
newLoc = board.rel(dir, loc)
return loc
class Dijkstra:
'''
Implementation of Dijkstra's shortest path algorithm for this application.
'''
def computeDistances(self, board, origin, exclude=[]):
'''
Compute the distances to all points on the board from point origin,
including the distance to origin itself (always 0).
Optionally, an exclude parameter can be given to exclude certain points
on the board.
'''
start = time.clock()
vertices = []
distances = dict()
for y in xrange(board.height):
for x in xrange(board.width):
coords = (y, x)
if board.passable(coords) and coords not in exclude:
distances[coords] = sys.maxint
vertices.append(coords)
distances[origin] = 0
vertices.append(origin)
while vertices:
minScore = sys.maxint
vertex = None
for v in vertices:
if distances[v] < minScore:
minScore = distances[v]
vertex = v
if vertex is None:
break
vertices.remove(vertex)
neighbours = [dest for dest in board.moveableDestinations(vertex) if dest in vertices and dest not in exclude]
newScore = distances[vertex] + 1
for neighbour in neighbours:
if newScore < distances[neighbour]:
distances[neighbour] = newScore
tron.log("Dijkstra took: " + str(float(time.clock() - start)))
tron.log(distances)
return distances
def meThemDifference(self, board, me, them, exclude=[]):
'''
Computes the difference between the number of nodes I can reach and they
can reach (positive means me > them). This is used in computing weights
for moves.
'''
meDistances = self.computeDistances(board, me, exclude)
# Remove ourselves from distance computation
del meDistances[me]
themDistances = self.computeDistances(board, them, exclude)
# Remove them from their distance computation
del themDistances[them]
meNodes = []
themNodes = []
for vertex in meDistances:
if meDistances[vertex] < themDistances[vertex]:
meNodes.append(vertex)
elif themDistances[vertex] < meDistances[vertex]:
themNodes.append(vertex)
return len(meNodes) - len(themNodes)