HexDecimal /
python-tdl
| 1 | """ |
||
| 2 | |||
| 3 | Example:: |
||
| 4 | |||
| 5 | >>> import numpy as np |
||
| 6 | >>> import tcod.path |
||
| 7 | >>> dungeon = np.array( |
||
| 8 | ... [ |
||
| 9 | ... [1, 0, 1, 1, 1], |
||
| 10 | ... [1, 0, 1, 0, 1], |
||
| 11 | ... [1, 1, 1, 0, 1], |
||
| 12 | ... ], |
||
| 13 | ... dtype=np.int8, |
||
| 14 | ... ) |
||
| 15 | ... |
||
| 16 | >>> height, width = dungeon.shape |
||
| 17 | |||
| 18 | # Create a pathfinder from a numpy array. |
||
| 19 | # This is the recommended way to use the tcod.path module. |
||
| 20 | >>> astar = tcod.path.AStar(dungeon) |
||
| 21 | >>> print(astar.get_path(0, 0, 4, 2)) |
||
| 22 | [(0, 1), (1, 2), (2, 1), (3, 0), (4, 1), (4, 2)] |
||
| 23 | >>> astar.cost[0, 1] = 1 # You can access the map array via this attribute. |
||
| 24 | >>> print(astar.get_path(0, 0, 4, 2)) |
||
| 25 | [(1, 0), (2, 0), (3, 0), (4, 1), (4, 2)] |
||
| 26 | |||
| 27 | # Create a pathfinder from an edge_cost function. |
||
| 28 | # Calling Python functions from C is known to be very slow. |
||
| 29 | >>> def edge_cost(my_x, my_y, dest_x, dest_y): |
||
| 30 | ... return dungeon[dest_y, dest_x] |
||
| 31 | ... |
||
| 32 | >>> dijkstra = tcod.path.Dijkstra( |
||
| 33 | ... tcod.path.EdgeCostCallback(edge_cost, width, height), |
||
| 34 | ... ) |
||
| 35 | ... |
||
| 36 | >>> dijkstra.set_goal(0, 0) |
||
| 37 | >>> print(dijkstra.get_path(4, 2)) |
||
| 38 | [(1, 0), (2, 0), (3, 0), (4, 1), (4, 2)] |
||
| 39 | """ |
||
| 40 | |||
| 41 | from __future__ import absolute_import |
||
| 42 | |||
| 43 | import numpy as np |
||
| 44 | |||
| 45 | from tcod.libtcod import lib, ffi |
||
| 46 | |||
| 47 | |||
| 48 | @ffi.def_extern() |
||
| 49 | def _pycall_path_old(x1, y1, x2, y2, handle): |
||
|
0 ignored issues
–
show
The name
y1 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
x2 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y2 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 50 | """libtcodpy style callback, needs to preserve the old userData issue.""" |
||
| 51 | func, userData = ffi.from_handle(handle) |
||
|
0 ignored issues
–
show
The name
userData does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 52 | return func(x1, y1, x2, y2, userData) |
||
| 53 | |||
| 54 | |||
| 55 | @ffi.def_extern() |
||
| 56 | def _pycall_path_simple(x1, y1, x2, y2, handle): |
||
|
0 ignored issues
–
show
The name
x1 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y1 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
x2 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y2 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 57 | """Does less and should run faster, just calls the handle function.""" |
||
| 58 | return ffi.from_handle(handle)(x1, y1, x2, y2) |
||
| 59 | |||
| 60 | |||
| 61 | @ffi.def_extern() |
||
| 62 | def _pycall_path_swap_src_dest(x1, y1, x2, y2, handle): |
||
|
0 ignored issues
–
show
The name
x1 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y1 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
x2 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y2 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 63 | """A TDL function dest comes first to match up with a dest only call.""" |
||
| 64 | return ffi.from_handle(handle)(x2, y2, x1, y1) |
||
| 65 | |||
| 66 | |||
| 67 | @ffi.def_extern() |
||
| 68 | def _pycall_path_dest_only(x1, y1, x2, y2, handle): |
||
|
0 ignored issues
–
show
The name
x1 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y1 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
x2 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y2 does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 69 | """A TDL function which samples the dest coordinate only.""" |
||
| 70 | return ffi.from_handle(handle)(x2, y2) |
||
| 71 | |||
| 72 | def _get_pathcost_func(name): |
||
| 73 | """Return a properly cast PathCostArray callback.""" |
||
| 74 | return ffi.cast('TCOD_path_func_t', ffi.addressof(lib, name)) |
||
| 75 | |||
| 76 | |||
| 77 | class _EdgeCostFunc(object): |
||
| 78 | """ |
||
| 79 | Args: |
||
| 80 | userdata (Any): Custom userdata to send to the C call. |
||
| 81 | width (int): The maximum width of this callback. |
||
| 82 | height (int): The maximum height of this callback. |
||
| 83 | """ |
||
| 84 | _CALLBACK_P = lib._pycall_path_old |
||
| 85 | |||
| 86 | def __init__(self, userdata, width, height): |
||
| 87 | self._userdata = userdata |
||
| 88 | self.width = width |
||
| 89 | self.height = height |
||
| 90 | |||
| 91 | def get_tcod_path_ffi(self): |
||
| 92 | """ |
||
| 93 | |||
| 94 | Returns: |
||
| 95 | Tuple[CData, CData]: A cffi (callback, userdata) pair. |
||
| 96 | |||
| 97 | |||
| 98 | """ |
||
| 99 | return (self._CALLBACK_P, ffi.new_handle(self._userdata), |
||
| 100 | self.width, self.height) |
||
| 101 | |||
| 102 | def __repr__(self): |
||
| 103 | return '%s(%r, width=%r, height=%r)' % ( |
||
| 104 | self.__class__.__name__, |
||
| 105 | self._userdata, self.width, self.height, |
||
| 106 | ) |
||
| 107 | |||
| 108 | |||
| 109 | class EdgeCostCallback(_EdgeCostFunc): |
||
| 110 | """Calculate cost from an edge-cost callback. |
||
| 111 | |||
| 112 | Args: |
||
| 113 | callback (Callable[[int, int, int, int], float]): |
||
| 114 | A callback which can handle the following parameters: |
||
| 115 | `(source_x:int, source_y:int, dest_x:int, dest_y:int) -> float` |
||
| 116 | width (int): The maximum width of this callback. |
||
| 117 | height (int): The maximum height of this callback. |
||
| 118 | """ |
||
| 119 | _CALLBACK_P = lib._pycall_path_simple |
||
| 120 | |||
| 121 | def __init__(self, callback, width, height): |
||
| 122 | self.callback = callback |
||
| 123 | super(EdgeCostCallback, self).__init__(callback, width, height) |
||
| 124 | |||
| 125 | class NodeCostArray(np.ndarray): |
||
| 126 | """Calculate cost from a numpy array of nodes. |
||
| 127 | |||
| 128 | Args: |
||
| 129 | array (numpy.ndarray): A numpy array with the cost of each node. |
||
| 130 | """ |
||
| 131 | |||
| 132 | _C_ARRAY_CALLBACKS = { |
||
| 133 | np.float32: ('float*', _get_pathcost_func('PathCostArrayFloat32')), |
||
| 134 | np.bool_: ('int8_t*', _get_pathcost_func('PathCostArrayInt8')), |
||
| 135 | np.int8: ('int8_t*', _get_pathcost_func('PathCostArrayInt8')), |
||
| 136 | np.uint8: ('uint8_t*', _get_pathcost_func('PathCostArrayUInt8')), |
||
| 137 | np.int16: ('int16_t*', _get_pathcost_func('PathCostArrayInt16')), |
||
| 138 | np.uint16: ('uint16_t*', _get_pathcost_func('PathCostArrayUInt16')), |
||
| 139 | np.int32: ('int32_t*', _get_pathcost_func('PathCostArrayInt32')), |
||
| 140 | np.uint32: ('uint32_t*', _get_pathcost_func('PathCostArrayUInt32')), |
||
| 141 | } |
||
| 142 | |||
| 143 | def __new__(cls, array): |
||
| 144 | """Validate a numpy array and setup a C callback.""" |
||
| 145 | self = np.ascontiguousarray(array).view(cls) |
||
| 146 | return self |
||
| 147 | |||
| 148 | @property |
||
| 149 | def width(self): |
||
|
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. Loading history...
|
|||
| 150 | return self.shape[1] |
||
| 151 | |||
| 152 | @property |
||
| 153 | def height(self): |
||
|
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. Loading history...
|
|||
| 154 | return self.shape[0] |
||
| 155 | |||
| 156 | def __repr__(self): |
||
| 157 | return '%s(%r)' % (self.__class__.__name__, |
||
| 158 | repr(self.view(np.ndarray))) |
||
| 159 | |||
| 160 | def get_tcod_path_ffi(self): |
||
|
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. Loading history...
|
|||
| 161 | if len(self.shape) != 2: |
||
| 162 | raise ValueError('Array must have a 2d shape, shape is %r' % |
||
| 163 | (self.shape,)) |
||
| 164 | if self.dtype.type not in self._C_ARRAY_CALLBACKS: |
||
| 165 | raise ValueError('dtype must be one of %r, dtype is %r' % |
||
| 166 | (self._C_ARRAY_CALLBACKS.keys(), self.dtype.type)) |
||
| 167 | |||
| 168 | array_type, callback = \ |
||
| 169 | self._C_ARRAY_CALLBACKS[self.dtype.type] |
||
| 170 | userdata = ffi.new( |
||
| 171 | 'PathCostArray*', |
||
| 172 | (self.width, ffi.cast(array_type, self.ctypes.data)), |
||
| 173 | ) |
||
| 174 | return callback, userdata, self.width, self.height |
||
| 175 | |||
| 176 | |||
| 177 | class _PathFinder(object): |
||
| 178 | """A class sharing methods used by AStar and Dijkstra.""" |
||
| 179 | |||
| 180 | def __init__(self, cost, diagonal=1.41): |
||
| 181 | self.cost = cost |
||
| 182 | self.diagonal = diagonal |
||
| 183 | self._path_c = None |
||
| 184 | self._callback = self._userdata = None |
||
| 185 | |||
| 186 | if hasattr(self.cost, 'map_c'): |
||
| 187 | self.width, self.height = self.cost.width, self.cost.height |
||
| 188 | self._path_c = ffi.gc( |
||
| 189 | self._path_new_using_map(self.cost.map_c, diagonal), |
||
| 190 | self._path_delete, |
||
| 191 | ) |
||
| 192 | return |
||
| 193 | |||
| 194 | if not hasattr(self.cost, 'get_tcod_path_ffi'): |
||
| 195 | assert not callable(self.cost), \ |
||
| 196 | "Any callback alone is missing width & height information. " \ |
||
| 197 | "Wrap your callback in tcod.path.EdgeCostCallback" |
||
| 198 | self.cost = NodeCostArray(self.cost) |
||
| 199 | |||
| 200 | self._callback, self._userdata, self.width, self.height = \ |
||
| 201 | self.cost.get_tcod_path_ffi() |
||
| 202 | self._path_c = ffi.gc( |
||
| 203 | self._path_new_using_function( |
||
| 204 | self.width, |
||
| 205 | self.height, |
||
| 206 | self._callback, |
||
| 207 | self._userdata, |
||
| 208 | diagonal |
||
| 209 | ), |
||
| 210 | self._path_delete, |
||
| 211 | ) |
||
| 212 | |||
| 213 | def __repr__(self): |
||
| 214 | return '%s(cost=%r, diagonal=%r)' % (self.__class__.__name__, |
||
| 215 | self.cost, self.diagonal) |
||
| 216 | |||
| 217 | def __getstate__(self): |
||
| 218 | state = self.__dict__.copy() |
||
| 219 | del state['_path_c'] |
||
| 220 | del state['width'] |
||
| 221 | del state['height'] |
||
| 222 | del state['_callback'] |
||
| 223 | del state['_userdata'] |
||
| 224 | return state |
||
| 225 | |||
| 226 | def __setstate__(self, state): |
||
| 227 | self.__dict__.update(state) |
||
| 228 | self.__init__(self.cost, self.diagonal) |
||
| 229 | |||
| 230 | _path_new_using_map = lib.TCOD_path_new_using_map |
||
| 231 | _path_new_using_function = lib.TCOD_path_new_using_function |
||
| 232 | _path_delete = lib.TCOD_path_delete |
||
| 233 | |||
| 234 | |||
| 235 | class AStar(_PathFinder): |
||
| 236 | """ |
||
| 237 | Args: |
||
| 238 | cost (Union[tcod.map.Map, numpy.ndarray, Any]): |
||
| 239 | diagonal (float): Multiplier for diagonal movement. |
||
| 240 | A value of 0 will disable diagonal movement entirely. |
||
| 241 | """ |
||
| 242 | |||
| 243 | def get_path(self, start_x, start_y, goal_x, goal_y): |
||
| 244 | """Return a list of (x, y) steps to reach the goal point, if possible. |
||
| 245 | |||
| 246 | Args: |
||
| 247 | start_x (int): Starting X position. |
||
| 248 | start_y (int): Starting Y position. |
||
| 249 | goal_x (int): Destination X position. |
||
| 250 | goal_y (int): Destination Y position. |
||
| 251 | Returns: |
||
| 252 | List[Tuple[int, int]]: |
||
| 253 | A list of points, or an empty list if there is no valid path. |
||
| 254 | """ |
||
| 255 | lib.TCOD_path_compute(self._path_c, start_x, start_y, goal_x, goal_y) |
||
| 256 | path = [] |
||
| 257 | x = ffi.new('int[2]') |
||
|
0 ignored issues
–
show
The name
x does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 258 | y = x + 1 |
||
|
0 ignored issues
–
show
The name
y does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 259 | while lib.TCOD_path_walk(self._path_c, x, y, False): |
||
| 260 | path.append((x[0], y[0])) |
||
| 261 | return path |
||
| 262 | |||
| 263 | |||
| 264 | class Dijkstra(_PathFinder): |
||
| 265 | """ |
||
| 266 | Args: |
||
| 267 | cost (Union[tcod.map.Map, numpy.ndarray, Any]): |
||
| 268 | diagonal (float): Multiplier for diagonal movement. |
||
| 269 | A value of 0 will disable diagonal movement entirely. |
||
| 270 | """ |
||
| 271 | |||
| 272 | _path_new_using_map = lib.TCOD_dijkstra_new |
||
| 273 | _path_new_using_function = lib.TCOD_dijkstra_new_using_function |
||
| 274 | _path_delete = lib.TCOD_dijkstra_delete |
||
| 275 | |||
| 276 | def set_goal(self, x, y): |
||
|
0 ignored issues
–
show
The name
x does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 277 | """Set the goal point and recompute the Dijkstra path-finder. |
||
| 278 | """ |
||
| 279 | lib.TCOD_dijkstra_compute(self._path_c, x, y) |
||
| 280 | |||
| 281 | def get_path(self, x, y): |
||
|
0 ignored issues
–
show
The name
x does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
The name
y does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).
This check looks for invalid names for a range of different identifiers. You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements. If your project includes a Pylint configuration file, the settings contained in that file take precedence. To find out more about Pylint, please refer to their site. Loading history...
|
|||
| 282 | """Return a list of (x, y) steps to reach the goal point, if possible. |
||
| 283 | """ |
||
| 284 | lib.TCOD_dijkstra_path_set(self._path_c, x, y) |
||
| 285 | path = [] |
||
| 286 | pointer_x = ffi.new('int[2]') |
||
| 287 | pointer_y = pointer_x + 1 |
||
| 288 | while lib.TCOD_dijkstra_path_walk(self._path_c, pointer_x, pointer_y): |
||
| 289 | path.append((pointer_x[0], pointer_y[0])) |
||
| 290 | return path |
||
| 291 |
This check looks for invalid names for a range of different identifiers.
You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.
If your project includes a Pylint configuration file, the settings contained in that file take precedence.
To find out more about Pylint, please refer to their site.