浏览代码

add pathfinder (ongoing)

olinox 9 年之前
父节点
当前提交
b1679ae53a
共有 3 个文件被更改,包括 140 次插入2 次删除
  1. 5 0
      core/Cell.py
  2. 20 2
      core/Grid.py
  3. 115 0
      core/pathfinder.py

+ 5 - 0
core/Cell.py

@@ -14,6 +14,7 @@ class Cell(object):
         self._x = x
         self._y = y
         self._z = z
+        self._neighbours = ()
         self.__update_neighbours()
 
     @property
@@ -39,6 +40,10 @@ class Cell(object):
     def __repr__(self):
         return "Cell {}".format(self.coord)
     
+    @property
+    def neighbours(self):
+        return self._neighbours
+    
     def __update_neighbours(self):
         """update the tuple of neighbours cells"""
         x, y = self._x, self._y

+ 20 - 2
core/Grid.py

@@ -3,9 +3,10 @@ Created on 7 nov. 2016
     Game Grid
 @author: olinox
 '''
-from core import bresenham, triangle, rectangle
+from core import bresenham, triangle, rectangle, pathfinder
 from core.constants import GRID_GEOMETRIES
 from core.triangle import ANGLES
+from core.Cell import Cell
 
 
 class Grid(object):
@@ -13,6 +14,7 @@ class Grid(object):
         self._geometry = geometry
         self._width = width
         self._height = height
+        self._cells = {}
         
     # properties
     @property
@@ -45,6 +47,16 @@ class Grid(object):
             raise ValueError("'width' has to be a strictly positive integer")
         self._height = height    
     
+    def cell(self, coord):
+        # temporary
+        try:
+            return self._cells[coord]
+        except KeyError:
+            x, y = coord
+            cell = Cell(self._geometry, x, y)
+            self._cells[coord] = cell
+            return cell
+    
     # methods
     def cases_number(self):
         return self.height * self.width
@@ -71,7 +83,11 @@ class Grid(object):
     def hollow_rect(self, x1, y1, x2, y2):
         return rectangle.hollow_rect(x1, y1, x2, y2)
 
-
+    def path(self, x1, y1, x2, y2):
+        return pathfinder.path( self, (x1, y1), (x2,y2) )
+    
+    
+    
     
 if __name__ == '__main__':
     gr = Grid(5, 100, 100)
@@ -83,6 +99,8 @@ if __name__ == '__main__':
     print(gr.triangle(1,1,5,10,ANGLES[1]))
     print(gr.triangle3d(1,1,1,5,10,10, ANGLES[1]))
     
+    print(gr.path(1,1,5,10))
+    
     
     
     

+ 115 - 0
core/pathfinder.py

@@ -0,0 +1,115 @@
+'''
+Created on 17 déc. 2015
+   Implement the A* algorithm
+@author: olivier.massot
+'''
+from core import cube_coords, Cell
+
+
+def distance(coord1, coord2):
+    """distance between 1 and 2"""
+    x1, y1 = coord1
+    xu1, yu1, zu1 = cube_coords.cv_off_cube(x1, y1)
+    x2, y2 = coord2
+    xu2, yu2, zu2 = cube_coords.cv_off_cube(x2, y2)
+    return max(abs(xu1 - xu2), abs(yu1 - yu2), abs(zu1 - zu2))
+
+def square_distance(coord1, coord2):
+    """distance between 1 and 2 (quicker than distance)"""
+    return (coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2
+
+class Path(object):
+    def __init__(self):
+        self._cells = []
+        self._costs = []
+        self._modes = []
+        self._val = []
+
+class Node():
+    def __init__(self, coord):
+        self.parent = None    # coords of the previous node
+        self.coord = coord
+        self.k_dep = 1
+        self.g_cost = 0
+        self.h_cost = 0
+        self.cost = 0
+ 
+    def create(self, parent, target, k_dep):
+        self.parent = parent
+        self.k_dep = k_dep
+        self.h_cost = self.distance(self.coord, target)
+        self.g_cost = self.parent.g_cost + self.k_dep
+        self.cout =  self.g_cost + self.h_cost
+    
+    def parent(self):
+        return self.parent
+    
+    def distance(self, coord1, coord2):
+        """distance (en cases) entre deux coordonnees"""
+        x1, y1 = coord1
+        x2, y2 = coord2
+        return cube_coords.distance_off(x1, y1, x2, y2)
+    
+
+def path(grid, origin, target, abilities = None):
+    """return the shorter path from origin to target on the Grid object
+    the path is estimated following:
+    - geometry of the grid
+    - altitudes of the cells
+    - land use of the cells
+    - type of moves allowed on the cells
+    - moving abilities
+    
+    origin and target should be Cell objects
+    """
+    nodes = {}  # coord: node
+
+    nO = Node(origin)
+    nO.parent = None
+    nO.cost = 0
+
+#     kept = [nO]
+    path = []
+    position = nO
+    
+    while position.coord != target:
+
+        # we could avoid the re-computing
+        neighbours = grid.cell(position.coord).neighbours
+        
+        for coord in [coord for coord in neighbours if not coord in nodes.keys()]:
+
+                # !!! need a calculate cost function !!!
+                cost = 1
+                if cost < 0:
+                    continue
+                
+                node = Node(coord)
+                
+                node.create(position, target, cost)
+
+                try:
+                    existing = nodes[coord]
+                    if existing.cout <= node.cout:
+                        continue
+                except KeyError:
+                    pass
+                
+                nodes[coord] = node
+
+        if len(nodes) == 0:
+            print("No path found")
+            return []
+        
+        best = min(nodes.values(), key=lambda x: x.cout)
+#         retenus.append(meilleur)
+        del nodes[best.coord]
+        position = best
+    
+    else:
+        # build the result
+        while position.coord != origin:
+            path.insert(0, (position.coord, position.k_dep))
+            position = position.parent
+    
+    return path