1 | ''' |
||
2 | The following example shows how to travrse the BSP tree using Python. This |
||
3 | assumes `create_room` and `connect_rooms` will be replaced by custom code. |
||
4 | |||
5 | Example:: |
||
6 | |||
7 | import tcod.bsp |
||
8 | |||
9 | def create_room(node): |
||
10 | """Initialize the room at this current node.""" |
||
11 | print('Create a room for %s.' % node) |
||
12 | |||
13 | def connect_rooms(node): |
||
14 | """Connect two fully initialized rooms.""" |
||
15 | node1, node2 = node.children |
||
16 | print('Connect the rooms:\\n%s\\n%s' % (node1, node2)) |
||
17 | |||
18 | def traverse(node): |
||
19 | """Traverse a BSP tree dispatching nodes to the correct calls.""" |
||
20 | # For nodes without children, node.children is an empty tuple. |
||
21 | for child in node.children: |
||
22 | traverse(child) |
||
23 | |||
24 | if node.children: |
||
25 | connect_rooms(node) |
||
26 | else: |
||
27 | create_room(node) |
||
28 | |||
29 | bsp = tcod.bsp.BSP(x=0, y=0, width=80, height=60) |
||
30 | bsp.split_recursive( |
||
31 | depth=5, |
||
32 | min_width=3, |
||
33 | min_height=3, |
||
34 | max_horizontal_ratio=1.5, |
||
35 | max_vertical_ratio=1.5, |
||
36 | ) |
||
37 | traverse(bsp) |
||
38 | ''' |
||
39 | from __future__ import absolute_import as _ |
||
40 | |||
41 | from tcod.libtcod import lib, ffi |
||
42 | |||
43 | |||
44 | class BSP(object): |
||
45 | """A binary space partitioning tree which can be used for simple dungeon |
||
46 | generation. |
||
47 | |||
48 | Attributes: |
||
49 | x (int): Rectangle left coordinate. |
||
50 | y (int): Rectangle top coordinate. |
||
51 | width (int): Rectangle width. |
||
52 | height (int): Rectangle height. |
||
53 | level (int): This nodes depth. |
||
54 | position (int): The integer of where the node was split. |
||
55 | horizontal (bool): This nodes split orientation. |
||
56 | parent (Optional[BSP]): This nodes parent or None |
||
57 | children (Optional[Tuple[BSP, BSP]]): |
||
58 | A tuple of (left, right) BSP instances, or |
||
59 | None if this BSP has no children. |
||
60 | |||
61 | Args: |
||
62 | x (int): Rectangle left coordinate. |
||
63 | y (int): Rectangle top coordinate. |
||
64 | width (int): Rectangle width. |
||
65 | height (int): Rectangle height. |
||
66 | """ |
||
67 | |||
68 | def __init__(self, x, y, width, height): |
||
69 | self.x = x |
||
0 ignored issues
–
show
|
|||
70 | self.y = y |
||
0 ignored issues
–
show
The name
y does not conform to the attribute 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. ![]() |
|||
71 | self.width = width |
||
72 | self.height = height |
||
73 | |||
74 | self.level = 0 |
||
75 | self.position = 0 |
||
76 | self.horizontal = False |
||
77 | |||
78 | self.parent = None |
||
79 | self.children = () |
||
80 | |||
81 | @property |
||
82 | def w(self): |
||
0 ignored issues
–
show
The name
w does not conform to the attribute 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. ![]() |
|||
83 | return self.width |
||
84 | @w.setter |
||
85 | def w(self, value): |
||
0 ignored issues
–
show
The name
w does not conform to the attribute 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. ![]() |
|||
86 | self.width = value |
||
87 | |||
88 | @property |
||
89 | def h(self): |
||
0 ignored issues
–
show
The name
h does not conform to the attribute 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. ![]() |
|||
90 | return self.height |
||
91 | @h.setter |
||
92 | def h(self, value): |
||
0 ignored issues
–
show
The name
h does not conform to the attribute 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. ![]() |
|||
93 | self.height = value |
||
94 | |||
95 | def _as_cdata(self): |
||
96 | cdata = ffi.gc(lib.TCOD_bsp_new_with_size(self.x, self.y, |
||
97 | self.width, self.height), |
||
98 | lib.TCOD_bsp_delete) |
||
99 | cdata.level = self.level |
||
100 | return cdata |
||
101 | |||
102 | def __str__(self): |
||
103 | """Provide a useful readout when printed.""" |
||
104 | status = 'leaf' |
||
105 | if self.children: |
||
106 | status = ('split at position=%i,horizontal=%r' % |
||
107 | (self.position, self.horizontal)) |
||
108 | |||
109 | return ('<%s(x=%i,y=%i,width=%i,height=%i)level=%i,%s>' % |
||
110 | (self.__class__.__name__, |
||
111 | self.x, self.y, self.width, self.height, self.level, status)) |
||
112 | |||
113 | def _unpack_bsp_tree(self, cdata): |
||
114 | self.x = cdata.x |
||
115 | self.y = cdata.y |
||
116 | self.width = cdata.w |
||
117 | self.height = cdata.h |
||
118 | self.level = cdata.level |
||
119 | self.position = cdata.position |
||
120 | self.horizontal = bool(cdata.horizontal) |
||
121 | if lib.TCOD_bsp_is_leaf(cdata): |
||
122 | return |
||
123 | self.children = (BSP(0, 0, 0, 0), BSP(0, 0, 0, 0)) |
||
124 | self.children[0].parent = self |
||
125 | self.children[0]._unpack_bsp_tree(lib.TCOD_bsp_left(cdata)) |
||
126 | self.children[1].parent = self |
||
127 | self.children[1]._unpack_bsp_tree(lib.TCOD_bsp_right(cdata)) |
||
128 | |||
129 | def split_once(self, horizontal, position): |
||
130 | """Split this partition into 2 sub-partitions. |
||
131 | |||
132 | Args: |
||
133 | horizontal (bool): |
||
134 | position (int): |
||
135 | """ |
||
136 | cdata = self._as_cdata() |
||
137 | lib.TCOD_bsp_split_once(cdata, horizontal, position) |
||
138 | self._unpack_bsp_tree(cdata) |
||
139 | |||
140 | def split_recursive(self, depth, min_width, min_height, |
||
141 | max_horizontal_ratio, max_vertical_ratio, seed=None): |
||
142 | """Divide this partition recursively. |
||
143 | |||
144 | Args: |
||
145 | depth (int): The maximum depth to divide this object recursively. |
||
146 | min_width (int): The minimum width of any individual partition. |
||
147 | min_height (int): The minimum height of any individual partition. |
||
148 | max_horizontal_ratio (float): |
||
149 | Prevent creating a horizontal ratio more extreme than this. |
||
150 | max_vertical_ratio (float): |
||
151 | Prevent creating a vertical ratio more extreme than this. |
||
152 | seed (Optional[tcod.random.Random]): |
||
153 | The random number generator to use. |
||
154 | """ |
||
155 | cdata = self._as_cdata() |
||
156 | lib.TCOD_bsp_split_recursive( |
||
157 | cdata, |
||
158 | seed or ffi.NULL, |
||
159 | depth, |
||
160 | min_width, min_height, |
||
161 | max_horizontal_ratio, max_vertical_ratio, |
||
162 | ) |
||
163 | self._unpack_bsp_tree(cdata) |
||
164 | |||
165 | def walk(self): |
||
166 | """Iterate over this BSP's hieracrhy. |
||
167 | |||
168 | The iterator will include the instance which called it. |
||
169 | It will traverse its own children and grandchildren, in no particular |
||
170 | order. |
||
171 | |||
172 | Returns: |
||
173 | Iterator[BSP]: An iterator of BSP nodes. |
||
174 | |||
175 | .. deprecated:: 2.3 |
||
176 | See the module example for how to iterate over a BSP tree. |
||
177 | """ |
||
178 | return self._iter_post_order() |
||
179 | |||
180 | def _iter_pre_order(self): |
||
181 | yield self |
||
182 | for child in self.children: |
||
183 | for grandchild in child._iter_pre_order(): |
||
184 | yield grandchild |
||
185 | |||
186 | def _iter_in_order(self): |
||
187 | if self.children: |
||
188 | for grandchild in self.children[0]._iter_in_order(): |
||
189 | yield grandchild |
||
190 | yield self |
||
191 | for grandchild in self.children[1]._iter_in_order(): |
||
192 | yield grandchild |
||
193 | else: |
||
194 | yield self |
||
195 | |||
196 | def _iter_post_order(self): |
||
197 | for child in self.children: |
||
198 | for grandchild in child._iter_post_order(): |
||
199 | yield grandchild |
||
200 | yield self |
||
201 | |||
202 | def _iter_level_order(self): |
||
203 | return sorted(self._iter_pre_order(), key=lambda n:n.level) |
||
204 | |||
205 | def _iter_inverted_level_order(self): |
||
206 | return reversed(self._iter_level_order()) |
||
207 | |||
208 | def contains(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. ![]() 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. ![]() |
|||
209 | """Returns True if this node contains these coordinates. |
||
210 | |||
211 | Args: |
||
212 | x (int): X position to check. |
||
213 | y (int): Y position to check. |
||
214 | |||
215 | Returns: |
||
216 | bool: True if this node contains these coordinates. |
||
217 | Otherwise False. |
||
218 | """ |
||
219 | return (self.x <= x < self.x + self.width and |
||
220 | self.y <= y < self.y + self.height) |
||
221 | |||
222 | def find_node(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. ![]() 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. ![]() |
|||
223 | """Return the deepest node which contains these coordinates. |
||
224 | |||
225 | Returns: |
||
226 | Optional[BSP]: BSP object or None. |
||
227 | """ |
||
228 | if not self.contains(x, y): |
||
229 | return None |
||
230 | for child in self.children: |
||
231 | found = child.find_node(x, y) |
||
232 | if found: |
||
233 | return found |
||
234 | return self |
||
235 |
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.