Skip to content

Commit a9530ed

Browse files
authored
Merge pull request #36 from graille/Thibault
Update
2 parents 1bd8bb1 + 43978df commit a9530ed

File tree

195 files changed

+2275
-1846
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

195 files changed

+2275
-1846
lines changed

Glouton.py

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
import sys
5+
import os
6+
import numpy as np
7+
import heapq
8+
9+
# Set the syspath
10+
f_name = "main.py"
11+
a_path = str(os.path.abspath(__file__))
12+
new_sys_entry = a_path[0:len(a_path) - len(f_name)]
13+
14+
print("Add " + new_sys_entry + "to sys path")
15+
sys.path.insert(0, new_sys_entry)
16+
17+
# Initialize vars
18+
TEAM_NAME = "JoJo Le Glouton"
19+
maze = None
20+
21+
class PriorityQueue(object):
22+
def __init__(self, heap = []):
23+
heapq.heapify(heap)
24+
self.heap = heap
25+
26+
def insert(self, node, priority = 0):
27+
heapq.heappush(self.heap, (priority, node))
28+
29+
def pop(self):
30+
return heapq.heappop(self.heap)[1]
31+
32+
33+
class Dijkstra:
34+
def __init__(self, maze, origin = None, goal = None):
35+
self.graph = maze
36+
self.setOrigin(origin)
37+
self.setGoal(goal)
38+
39+
def setOrigin(self, n):
40+
if n:
41+
self.origin = n
42+
43+
def setGoal(self, n):
44+
if isinstance(n, list):
45+
self.goal = n.copy()
46+
else:
47+
self.goal = n
48+
49+
def clear(self):
50+
self.pathArray = {}
51+
self.dist = {}
52+
self.Q = PriorityQueue()
53+
54+
self.dist[self.origin] = 0
55+
56+
for node in self.graph.nodes:
57+
if node != self.origin:
58+
self.pathArray[node] = None
59+
self.dist[node] = np.inf
60+
61+
self.Q.insert(self.origin, self.dist[self.origin])
62+
63+
def process(self):
64+
self.algorithm()
65+
66+
def algorithm(self):
67+
if self.origin != self.goal:
68+
self.clear()
69+
70+
while self.Q.heap:
71+
u = self.Q.pop()
72+
for v in self.graph.getNeighbors(u):
73+
alt = self.dist[u] + self.graph.getDistance(u, v)
74+
if alt < self.dist[v]:
75+
self.dist[v] = alt
76+
self.pathArray[v] = u
77+
self.Q.insert(v, alt)
78+
else:
79+
pass
80+
81+
def reconstructPath(self, node):
82+
#litteral_path = ""
83+
total_distance = 0
84+
current = node
85+
real_path = []
86+
while current != self.origin:
87+
new = self.pathArray[current]
88+
89+
#litteral_path += self.graph.getMove(new, current)
90+
total_distance += self.graph.getDistance(current, new)
91+
real_path.append(current)
92+
93+
current = new
94+
95+
real_path.append(current)
96+
return (total_distance, real_path[::-1])
97+
98+
def getResult(self, node = None):
99+
if self.goal != self.origin:
100+
if (not node) and (self.goal):
101+
return self.reconstructPath(self.goal)
102+
else:
103+
return self.reconstructPath(node)
104+
else:
105+
return (0, [])
106+
107+
108+
class Maze:
109+
def __init__(self, mazeMap, mazeWidth, mazeHeight):
110+
self.mazeMap = mazeMap
111+
self.mazeWidth = mazeWidth
112+
self.mazeHeight = mazeHeight
113+
114+
self.NB_NODES = self.mazeWidth * self.mazeHeight
115+
self.nodes = list(self.mazeMap.keys())
116+
117+
# Init matrixMap
118+
self.matrixMap = {}
119+
120+
# Init metagraph
121+
self.distanceMetagraph = {} # matrice des distances du métagraph sous forme de dictionnaire
122+
self.pathMetagraph = {} # matrice des chemins du métagraph sous forme de dictionnaire
123+
124+
def convertToMatrix(self):
125+
"""
126+
Prend en argument
127+
Renvoie une un dictionnaire où les clefs sont les clefs sont des cases et où
128+
np.inf signifie qu'il n'y a pas de passage direct entre les deux cases,
129+
n>0 signifie qu'il y a passage en n coups et 0 que l'on reste sur la même case
130+
"""
131+
for n in self.nodes:
132+
self.matrixMap[n] = {}
133+
134+
for n1 in self.nodes:
135+
for n2 in self.nodes:
136+
if n1 == n2:
137+
self.matrixMap[n1][n1] = 0
138+
elif n2 in self.mazeMap[n1]:
139+
self.matrixMap[n1][n2] = self.mazeMap[n1][n2]
140+
self.matrixMap[n2][n1] = self.mazeMap[n2][n1]
141+
else:
142+
self.matrixMap[n1][n2] = np.inf
143+
self.matrixMap[n2][n1] = np.inf
144+
145+
def reversePath(self, path):
146+
"""
147+
Inverse un chemin symétriquement par rapport a la diagonale
148+
:param path:
149+
:return:
150+
"""
151+
r = ""
152+
for l in path:
153+
if l == 'D':
154+
r += 'U'
155+
if l == 'U':
156+
r += 'D'
157+
if l == 'R':
158+
r += 'L'
159+
if l == 'L':
160+
r += 'R'
161+
162+
return r
163+
164+
def getDistance(self, from_location, to_location):
165+
try:
166+
return self.mazeMap[from_location][to_location]
167+
except KeyError:
168+
if to_location == from_location:
169+
return 0
170+
else:
171+
return np.inf
172+
173+
def getMove(self, origin, goal):
174+
"""
175+
Retourne le mouvement à effectuer pour aller de origin à goal,
176+
qui doivent être adjacentes
177+
:param origin:
178+
:param goal:
179+
:return: bool
180+
"""
181+
if origin != goal:
182+
i1, j1 = origin
183+
i2, j2 = goal
184+
185+
if i1 - i2 == -1:
186+
return 'D'
187+
elif i1 - i2 == 1:
188+
return 'U'
189+
elif j1 - j2 == -1:
190+
return 'R'
191+
elif j1 - j2 == 1:
192+
return 'L'
193+
else:
194+
return False
195+
else:
196+
return False
197+
198+
def getNeighbors(self, position):
199+
return self.mazeMap[position].keys()
200+
201+
def convertMetaPathToRealPaths(self, pathMeta):
202+
path = []
203+
for k in range(len(pathMeta) - 1):
204+
path.append(self.pathMetagraph[pathMeta[k]][pathMeta[k+1]])
205+
206+
return path
207+
208+
def convertToRealPath(self, origin, pathNodes):
209+
L = [origin]
210+
211+
x, y = origin
212+
for elt in pathNodes:
213+
if elt == 'L':
214+
y -= 1
215+
if elt == 'U':
216+
x -= 1
217+
if elt == 'D':
218+
x += 1
219+
if elt == 'R':
220+
y += 1
221+
L.append((x, y))
222+
223+
return L
224+
225+
def concatPaths(self, paths):
226+
r = ""
227+
for path in paths:
228+
r += path
229+
230+
return r
231+
232+
def createMetaGraph(self, cheeses_list):
233+
"""
234+
Create the pattern of the metagraph(distance between cheeses
235+
:param nodes_list: List of currents cheeses
236+
:return:
237+
"""
238+
cheeses_list = cheeses_list.copy()
239+
dij = Dijkstra(self)
240+
241+
while cheeses_list:
242+
n1 = cheeses_list[0]
243+
# Calculate path and distance with Dijkstra
244+
dij.setOrigin(n1)
245+
dij.setGoal(cheeses_list)
246+
dij.process()
247+
248+
for n2 in cheeses_list:
249+
d, p = dij.getResult(n2)
250+
self.coupleNodesInMetagraph(n1, n2, d, p)
251+
252+
cheeses_list.remove(n1) # On supprime le node en cours, pour accelerer le programme
253+
cheeses_list.remove(self.getOpposite(n1)) if self.getOpposite(n1) != n1 else () # Par symetrie, on supprime l'opposé
254+
255+
#print(repr(len(self.distanceMetagraph[(12, 13)]))+ repr(self.distanceMetagraph[(12, 13)]))
256+
257+
def addNodeToMetagraph(self, node, nodes_list):
258+
"""
259+
Ajoute le noeud "node" par rapports aux nodes "nodes_list" qui doivent déja exister dans le metaGraph
260+
:param node: noeud a ajouter ou uploader
261+
:param nodes_list:
262+
:return:
263+
"""
264+
265+
# Create the list of unChecked nodes
266+
checked_list = []
267+
268+
if node in self.distanceMetagraph:
269+
for n in nodes_list:
270+
if n not in self.distanceMetagraph[node]:
271+
checked_list.append(n)
272+
else:
273+
checked_list = nodes_list
274+
275+
# Environ 10^-6 sec pour arriver là
276+
if checked_list:
277+
dij = Dijkstra(self, node, checked_list)
278+
dij.process()
279+
# Environ 0.02 sec pour un 25x25
280+
281+
for n in checked_list:
282+
d, p = dij.getResult(n)
283+
self.coupleNodesInMetagraph(node, n, d, p)
284+
285+
def coupleNodesInMetagraph(self, n1, n2, d, p, recurse = True):
286+
"""
287+
:param d: distance from n1 to n2
288+
:param p: path from n1 to n2
289+
"""
290+
291+
if n1 not in self.distanceMetagraph:
292+
self.distanceMetagraph[n1] = {}
293+
self.pathMetagraph[n1] = {}
294+
295+
self.distanceMetagraph[n1][n2] = d
296+
self.pathMetagraph[n1][n2] = p
297+
298+
if n2 not in self.distanceMetagraph:
299+
self.distanceMetagraph[n2] = {}
300+
self.pathMetagraph[n2] = {}
301+
302+
self.distanceMetagraph[n2][n1] = d
303+
self.pathMetagraph[n2][n1] = p[::-1] # Path from n2 to n1 is the opposite of the path from n1 to n2
304+
305+
# Add opposite
306+
if recurse:
307+
self.coupleNodesInMetagraph(self.getOpposite(n1), self.getOpposite(n2), d, list(map(self.getOpposite, p)), False)
308+
309+
def getOpposite(self, n):
310+
x, y = n
311+
return (self.mazeHeight - x - 1, self.mazeWidth - y - 1)
312+
313+
# Algoritms application
314+
def getFastestPath(self, origin, goal):
315+
try:
316+
return (self.distanceMetagraph[origin][goal], self.pathMetagraph[origin][goal])
317+
except KeyError:
318+
print("## Need to calculate the fastest path from " + repr(origin) + " to " + repr(goal))
319+
320+
# Calculate path and distance with Astar
321+
dij = Astar(self, origin, goal)
322+
dij.process()
323+
324+
d, p = dij.getResult()
325+
326+
# Addto metagraph for a next time
327+
self.coupleNodesInMetagraph(origin, goal, d, p)
328+
329+
return (d, p)
330+
331+
def getNearestNode(self, origin, nodes):
332+
dij = Dijkstra(self)
333+
dij.setOrigin(origin)
334+
dij.setGoal(None)
335+
336+
dij.process()
337+
338+
n_list = [dij.getResult(n) for n in nodes]
339+
n_list.sort()
340+
341+
#print(n_list)
342+
343+
return n_list[0] if len(n_list) > 0 else (0, [])
344+
345+
346+
347+
def preprocessing(mazeMap, mazeWidth, mazeHeight, playerLocation, opponentLocation, piecesOfCheese, timeAllowed):
348+
global maze
349+
350+
print("Start preprocessing (" + str(timeAllowed) + ")")
351+
352+
maze = Maze(mazeMap, mazeWidth, mazeHeight)
353+
354+
print("")
355+
356+
def turn(mazeMap, mazeWidth, mazeHeight, playerLocation, opponentLocation, playerScore, opponentScore, piecesOfCheese, timeAllowed):
357+
global maze
358+
359+
path = maze.getNearestNode(playerLocation, piecesOfCheese)[1]
360+
action = maze.getMove(path[0], path[1])
361+
print('[' + repr(action) + ']')
362+
363+
return action

Test.py

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)