Package horizons :: Package util :: Package pathfinding :: Module pathnodes
[hide private]
[frames] | no frames]

Source Code for Module horizons.util.pathfinding.pathnodes

  1  # ################################################### 
  2  # Copyright (C) 2008-2017 The Unknown Horizons Team 
  3  # team@unknown-horizons.org 
  4  # This file is part of Unknown Horizons. 
  5  # 
  6  # Unknown Horizons is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the 
 18  # Free Software Foundation, Inc., 
 19  # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 20  # ################################################### 
 21   
 22  import logging 
 23   
 24   
25 -class PathNodes:
26 """ 27 Abstract class; used to derive list of path nodes from, which is used for pathfinding. 28 We encapsulate this code here to keep it centralized. 29 """ 30 log = logging.getLogger("world.pathfinding") 31 32 # TODO: currently all paths have speed 1, since we don't have a real velocity-system yet. 33 NODE_DEFAULT_SPEED = 1.0 34
35 - def __init__(self):
36 # store a collection of path_nodes here. the type of this var has to be supported 37 # by the pathfinding algo 38 pass
39 40
41 -class ConsumerBuildingPathNodes(PathNodes):
42 """List of path nodes for a consumer, that is a building 43 Interface: 44 self.nodes: {(x, y): speed, ...} of the home_building, where the collectors can walk 45 """
46 - def __init__(self, consumerbuilding):
47 super().__init__() 48 ground_map = consumerbuilding.island.ground_map 49 self.nodes = {} 50 for coords in consumerbuilding.position.get_radius_coordinates(consumerbuilding.radius, include_self=False): 51 if coords in ground_map and 'coastline' not in ground_map[coords].classes: 52 self.nodes[coords] = self.NODE_DEFAULT_SPEED
53 54
55 -class IslandPathNodes(PathNodes):
56 """List of path nodes for island 57 Interface: 58 self.nodes: List of nodes on island, where the terrain allows to be walked on 59 self.road_nodes: dictionary of nodes, where a road is built on 60 61 (un)register_road has to be called for each coord, where a road is built on (destroyed) 62 reset_tile_walkablity has to be called when the terrain changes the walkability 63 (e.g. building construction, a flood, or whatever) 64 is_walkable rechecks the walkability status of a coordinate 65 """
66 - def __init__(self, island):
67 super().__init__() 68 69 self.island = island 70 71 # generate list of walkable tiles 72 # we keep this up to date, so that path finding can use it and we don't have 73 # to calculate it every time (rather expensive!). 74 self.nodes = {} 75 for coord in self.island: 76 if self.is_walkable(coord): 77 self.nodes[coord] = self.NODE_DEFAULT_SPEED 78 79 # nodes where a real road is built on. 80 self.road_nodes = {}
81
82 - def register_road(self, road):
83 for i in road.position: 84 self.road_nodes[(i.x, i.y)] = self.NODE_DEFAULT_SPEED
85
86 - def unregister_road(self, road):
87 for i in road.position: 88 del self.road_nodes[(i.x, i.y)]
89
90 - def is_road(self, x, y):
91 """Return if there is a road on (x, y)""" 92 return (x, y) in self.road_nodes
93
94 - def is_walkable(self, coord):
95 """Check if a unit may walk on the tile specified by coord on land 96 NOTE: nature tiles (trees..) are considered to be walkable (or else they could be used as 97 walls against enemies) 98 @param coord: tuple: (x, y) 99 """ 100 tile_object = self.island.get_tile_tuple(coord) 101 102 if tile_object is None: 103 # tile is water 104 return False 105 106 # if it's not constructable, it is usually also not walkable 107 # NOTE: this isn't really a clean implementation, but it works for now 108 # it eliminates e.g. water and beaches, that shouldn't be walked on 109 if "constructible" not in tile_object.classes: 110 return False 111 if tile_object.blocked and not tile_object.object.walkable: 112 return False 113 # every test is passed, tile is walkable 114 return True
115
116 - def reset_tile_walkability(self, coord):
117 """Reset the status of the walkability of a coordinate in the list of walkable tiles 118 of the island. Does not change the tile itself. 119 You need to call this when a tile changes, e.g. when a building is built on it. this 120 is currently done in add/remove_building 121 @param coord: tuple: (x, y)""" 122 actually_walkable = self.is_walkable(coord) 123 # TODO: this lookup on a list is O(n), use different data structure here 124 in_list = (coord in self.nodes) 125 if not in_list and actually_walkable: 126 self.nodes[coord] = self.NODE_DEFAULT_SPEED 127 if in_list and not actually_walkable: 128 del self.nodes[coord]
129 130
131 -class IslandBarrierNodes(PathNodes):
132 """ 133 List of barriers on an island. Used for pathfinding when constructing barriers by 134 dragging. 135 """
136 - def __init__(self, island):
137 super().__init__() 138 139 self.island = island 140 141 # nodes where a barrier is built on. 142 self.nodes = set()
143
144 - def register(self, barrier):
145 for i in barrier.position: 146 self.nodes.add((i.x, i.y))
147
148 - def unregister(self, barrier):
149 for i in barrier.position: 150 self.nodes.remove((i.x, i.y))
151