123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- import numpy as np
- def suppr (t, a) : # Elric et Baptiste 09/2016
- """ On supprime tout les elements valant a dans le tableau t """
- for i in t :
- if i == a :
- t.remove(i)
- def cases_voisines(plateau, x, y) : # Elric et Baptiste 09/2016
- """ Retourne les cases adjacentes à la case (x,y) """
-
- # On commence par tester les valeurs de x, puis on fait de même sur y.
- if x == 0 :
- if y == 0 :
- return [(0, 1), (1, 0)]
- elif y == plateau.ht - 1 :
- return [(1, y), (0, y-1)]
- else :
- return [(0, y-1), (0, y+1), (1, y)]
- elif x == plateau.lg - 1 :
- if y == 0 :
- return [(x, 1), (x-1, 0)]
- elif y == plateau.ht - 1 :
- return [(x-1, y), (x, y-1)]
- else :
- return [(x, y-1), (x, y+1), (x-1, y)]
- else :
- if y == 0 :
- return [(x-1, y), (x+1, y), (x, 1)]
- elif y == plateau.ht - 1 :
- return [(x-1, y), (x+1, y), (x, y-1)]
- else :
- return [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]
- def cases_accessibles(plateau, x, y) : # Elric et Baptiste 09/2016
- """ Prend en compte les barrières """
- t = cases_voisines ( plateau, x , y )
- n = len(plateau.liste_barrieres)
- b = plateau.liste_barrieres
- for bar in b :
- if bar.x == x :
- if bar.y == y :
- if bar.orientation == "v" :
- suppr (t, (x+1, y))
- else:
- suppr (t, (x, y+1))
- elif bar.y == y-1 :
- if bar.orientation == "v" :
- suppr (t, (x+1, y))
- else:
- suppr (t, (x, y-1))
- elif bar.x == x-1 :
- if bar.y == y :
- if bar.orientation == "v" :
- suppr (t, (x-1, y))
- else:
- suppr (t, (x, y+1))
- elif bar.y == y-1 :
- if bar.orientation == "v" :
- suppr (t, (x-1, y))
- else:
- suppr (t, (x, y-1))
- return (t)
- def path_finding_mapping( plateau, xi, yi, yf ) : # Jovian : 4 octobre 2016
- """
- Calcule le chemin le plus court pour gagner.
- Argument plateau : argument self de python.
- Argument xi : abscisse de départ.
- Argument yi : ordonnée de départ.
- Argument yf : ordonnée qui désigne la ligne d'arrivée.
- Retour :
- Une liste des couples (x, y) des positions successives.
- Position de départ inclue.
- Liste vide si aucun chemin possible.
- """
- # Cartographie les cases accessibles
- carte = map_distance( plateau, xi, yi )
- w = plateau.lg
- h = plateau.ht
- # Position variable
- x = -1
- y = yf
- # Détermination du point d'arrivée
- dist = -1
- for k in range( w ) :
- if carte[ k ][ yf ] > 0 :
- if x == -1 or carte[ k ][ yf ] < dist :
- x = k
- dist = carte[ x ][ yf ]
- # Arrivée non joignable
- if x == -1 :
- return []
- # Reconstitution du chemin
- rep = [(x, y)]
- while x != xi or y != yi :
- # Case actuelle
- x, y = rep[ len(rep) - 1 ]
- dist = carte[ x ][ y ]
- # Récupère les cases accessibles
- access = cases_accessibles( plateau, x, y )
- # Recherche de la case la plus proche
- while len( access ) > 0 :
- u, v = access.pop(0)
- if carte[ u ][ v ] < dist :
- x = u
- y = v
- rep.append( (x, y) )
- break
- # Renvoie le chemin
- return rep
-
- def map_distance( plateau, xi, yi ) : # Jovian : 4 octobre 2016
- """
- Calcule un tableau contenant la distance de chaque case par rapport au joueur.
- Tient compte de l'éloignement dû aux barrières.
- La case contient 0 si inaccessible.
- Argument plateau : argument self de python.
- Argument xi : abscisse de départ.
- Argument yi : ordonnée de départ.
- Retour : un tableau d'entiers indexé (x, y).
- """
- # Création du tableau
- w = plateau.lg
- h = plateau.ht
- rep = np.zeros( (w, h) )
- rep[ xi ][ yi ] = 1
- # Création de la file
- fifo = [(xi, yi)]
- # Balayage du plateau depuis la position de départ
- while len( fifo ) > 0 :
- # Point sur un bord
- x, y = fifo.pop(0)
- dist = rep[ x ][ y ]
- # Récupère les cases accessibles
- access = cases_accessibles( plateau, x, y )
- # Traitement des cases adjacentes
- while len( access ) > 0 :
- u, v = access.pop(0)
- if rep[ u ][ v ] == 0 :
- rep[ u ][ v ] = dist + 1
- fifo.append( (u, v ) )
- # Retourne le tableau
- return rep
-
- ## Version A*
- from heapq import *
- def get_path(start, target, parent) : # Jovian : 25 novembre 2016
- """ Construit et retourne le chemin solution.
- """
- path = [target]
- x, y = target
- while (x, y) != start:
- x, y = parent[x, y]
- path.append((x, y))
- return list( reversed(path) )
- def path_finding_a_star( plateau, xi, yi, yf, hcap = 0 ) : # Jovian : 7 décembre 2016 : éviter le contact barrières
- """
- Calcule le chemin le plus court pour gagner.
- Argument plateau : argument self de python.
- Argument xi : abscisse de départ.
- Argument yi : ordonnée de départ.
- Argument yf : ordonnée qui désigne la ligne d'arrivée.
- Argument hcap : valeur malus ajoutée si le pion est en contact avec une barrière.
- Retour :
- Une liste des couples (x, y) des positions successives.
- Position de départ inclue.
- Liste vide si aucun chemin possible.
- """
- # Variables
- open_set = []
- closed = np.zeros( (plateau.lg, plateau.ht), dtype = bool )
- parent = np.zeros( (plateau.lg, plateau.ht, 2), dtype = int )
- cost_so_far = np.ones((plateau.lg, plateau.ht)) * np.inf
-
- # Estimation distance restante
- def heuristic( z ):
- # Distance directe
- x, y = z
- dist = abs(y - yf)
- return dist
- # Malus si contact avec une barrière
- def malus( z ):
- x , y = z
- if plateau.contact( x, y ) :
- return hcap
- else :
- return 0
- # Ajoute un élément qui sera traité plus tard
- def push(open_set, z):
- priority = cost_so_far[z] + heuristic(z) + malus(z)
- heappush(open_set, (priority, z) )
- # Retire la case potentiellement la plus proche
- def pop(open_set):
- _, current = heappop(open_set)
- return current
- # Initialisation
- start = xi, yi
- cost_so_far[start] = 0
- push(open_set, start)
- current = (0, 0)
- # Parcours
- while open_set != []:
-
- # Case (x, y) en cours de traitement
- current = pop(open_set)
- x, y = current
- # Si on a atteint l'arrivée
- if current[1] == yf :
- break
- # Si la case a déjà été vue
- if closed[current] :
- continue
-
- # On dit qu'on a traité cette case
- closed[current] = True
- # Parcours des voisins
- for neighbor in cases_accessibles( plateau, x, y ):
-
- # Voisin déjà traité
- if closed[neighbor]:
- continue
-
- new_cost_neighbor = cost_so_far[current] + malus(neighbor) + 1
-
- # Si notre chemin est plus court pour accéder à cette case
- if new_cost_neighbor < cost_so_far[neighbor]:
- cost_so_far[neighbor] = new_cost_neighbor
- push(open_set, neighbor)
- parent[neighbor] = current
-
- # Fin de parcours
- if current[1] == yf :
- # Chemin abouti
- return get_path(start, current, parent)
- else :
- # Chemin inexistant
- return []
- ## Alias du pathfinding
- def path_finding( plateau, xi, yi, yf ) : # Jovian : 7 décembre 2016 : éviter le contact barrières
- """
- Pour éviter le contact avec les barrières : mettez hcap = 0.05
- Sinon hcap = 0.0
- """
- return path_finding_a_star( plateau, xi, yi, yf, hcap = 0.05 )
|