· 6 years ago · Dec 21, 2019, 07:08 AM
1from copy import copy
2import itertools
3import numpy as np
4
5"""
6
7- This script does NOT handle spawners (except for rupee clusters)
8- This script does NOT handle scarecrow memory leak
9
10- This script does not account for ISoT memory leak for solution options
11
12
13FOR DEKU PALACE, THIS DOES NOT ACCOUNT FOR SOME ROOMS BEING ABLE TO SPAWN SIGNS
14ALSO DOES NOT ACCOUNT FOR POTENTIALLY NEEDING TO BREAK A POT FOR THE SUPERSLIDE
15
16THIS SCRIPT DOES NOT ACCOUNT FOR SKULLTULA TOKENS OR SPAWNING GOLD SKULLTULAS BY
17SHOOTING OCEANSIDE SKULLKID PAINTINGS... IF IT SAYS YOU DEALLOCATE A GOLD SKULLTULA,
18THEN IT ASSUMES YOU PICKED UP THE TOKEN
19
20
21"""
22
23
24
25"""
26
27Note: Node size is 0x10 = 16 on English and 0x30 = 48 on JP
28
29"""
30
31version = 'English'
32
33if version == 'English':
34 node_size = 0x10
35elif version == 'JP':
36 nodesize = 0x30
37else:
38 print('Error: Invalid Version (choose "English" or "JP" )')
39
40
41
42class Actor:
43
44 """
45
46 name: name of the actor, some string
47
48 Id: Actor id, string of 4 integers
49
50 size: the size of an actor instance for this actor (number of bytes, in decimal)
51
52 category: the actor category (category 5 is treated differently than others)
53 For now, giving everything not category 5 a category of 0
54
55 overlay_type: determines where the AF loads in the heap
56
57 unloadable: a boolean for whether or not it is possible to deallocate this actor without changing rooms
58
59 address: the memory address of the actor in decimal (can convert to a hex string for output)
60 Note: The earliest address we handle is 0x40B150 = 4239696. All addresses must be multiples of 16
61
62 room_number: the number of the room these actors are associated with; if the actor is a transition (i..e Plane
63 or Door), then set room_numer = False
64
65
66 priority: an index to differentiate copies of the same instance
67
68 from_spawner: True or False (True if it is from a spawner, like rupees from a cluster; False otherwise)
69
70 transition: False is the actor is not a Loading Plane or a Door. Otherwise, it is a list of the rooms that the transition actor connects, ordered from least to greatest room number
71
72 clearable: True if it is possible to set a flag to make this actor not respawn upon reloading the room (though, unless it it Category 5, it will attempt to reload and then immediately deallocate), False otherwise
73
74 cleared: True if the flag was set to clear this actor, False otherwise
75
76 """
77
78 def __init__(self, name, Id, size, category, overlay_type, unloadable, address, room_number, priority, from_spawner, transition, clearable, cleared):
79 self.name = name
80 self.Id = Id
81 self.size = size
82 self.category = category
83 self.overlay_type = overlay_type
84 self.unloadable = unloadable
85 self.address = address
86 self.room_number = room_number
87 self.priority = priority
88 self.from_spawner = from_spawner
89 self.transition = transition
90 self.clearable = clearable
91 self.cleared = cleared
92
93class Room:
94
95 """
96
97 number: the room number (i.e. Room 0 has number 0)
98
99 priority_queue: this will be the list of actor instances of the room, in order
100
101 clock_exists: boolean for whether or not the clock is an actor in the queue
102
103 clock_priority: if clock_exists == False, then clock_priority will be a number
104 to determine where in the queue the clock should be loaded, for
105 example, if clock_priority is 2, then it means that the clock
106 should be the 3rd actor to appear in the queue (first index is 0)
107
108 """
109
110 def __init__(self, number, priority_queue, clock_exists, clock_priority):
111 self.number = number
112 self.priority_queue = priority_queue
113 self.clock_exists = clock_exists
114 self.clock_priority = clock_priority
115
116class Node:
117
118 """
119 address: which address in memory the node is at (as a base-10 integer for now)
120
121 size: nodes should be 16 bytes (english), so input 16
122
123 """
124
125 def __init__(self, address, size):
126 self.address = address
127 self.size = size
128
129class Overlay:
130
131 def __init__(self, address, Id, size):
132 self.address = address
133 self.Id = Id
134 self.size = size
135
136
137"""
138
139We define the Clock actor ahead of time as it is not necessarily present in each room
140
141"""
142
143
144Clock = Actor(name='Clock', Id='015A', size=340, category=0, overlay_type='A', unloadable=False, address=0, room_number=False, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
145
146###############################################################################
147
148Oceanside_Room3_queue = [
149 Actor(name='Loading Plane', Id='0018', size=332, category=0, overlay_type='B', unloadable=False, address=0, room_number=False, priority=0, from_spawner=False, transition=[3,4], clearable=False, cleared=False),
150 Actor(name='Wooden Door', Id='0005', size=0x1CC, category=0, overlay_type='B', unloadable=False, address=0, room_number=False, priority=0, from_spawner=False, transition=[2,3], clearable=False, cleared=False),
151 Actor(name='Stalchild (Oceanside Spider House)', Id='02A5', size=0x3EC, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
152 Actor(name='Stalchild (Oceanside Spider House)', Id='02A5', size=0x3EC, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=1, from_spawner=False, transition=False, clearable=False, cleared=False),
153 Actor(name='Stalchild (Oceanside Spider House)', Id='02A5', size=0x3EC, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=2, from_spawner=False, transition=False, clearable=False, cleared=False),
154 Actor(name='Stalchild (Oceanside Spider House)', Id='02A5', size=0x3EC, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=3, from_spawner=False, transition=False, clearable=False, cleared=False),
155 Actor(name='Pot', Id='0082', size=0x19C, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
156 Actor(name='Pot', Id='0082', size=0x19C, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=1, from_spawner=False, transition=False, clearable=False, cleared=False),
157 Actor(name='Oceanside Spider House Skull Kid Painting', Id='0210', size=0x244, category=0, overlay_type='A', unloadable=False, address=0, room_number=3, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
158 Actor(name='Oceanside Spider House Skull Kid Painting', Id='0210', size=0x244, category=0, overlay_type='A', unloadable=False, address=0, room_number=3, priority=1, from_spawner=False, transition=False, clearable=False, cleared=False),
159 Actor(name='Oceanside Spider House Skull Kid Painting', Id='0210', size=0x244, category=0, overlay_type='A', unloadable=False, address=0, room_number=3, priority=2, from_spawner=False, transition=False, clearable=False, cleared=False),
160 Actor(name='Oceanside Spider House Skull Kid Painting', Id='0210', size=0x244, category=0, overlay_type='A', unloadable=False, address=0, room_number=3, priority=3, from_spawner=False, transition=False, clearable=False, cleared=False),
161 Actor(name='Gold Skulltula', Id='0050', size=0x4A4, category=5, overlay_type='A', unloadable=True, address=0, room_number=3, priority=0, from_spawner=False, transition=False, clearable=True, cleared=False),
162 Actor(name='Spiderweb', Id='0125', size=0x2FC, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=0, from_spawner=False, transition=False, clearable=True, cleared=False),
163 Actor(name='Gold Skulltula', Id='0050', size=0x4A4, category=5, overlay_type='A', unloadable=True, address=0, room_number=3, priority=1, from_spawner=False, transition=False, clearable=True, cleared=False),
164 Actor(name='Bonk Actor (01E7)', Id='01E7', size=0x148, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
165 Actor(name='Gold Skulltula', Id='0050', size=0x4A4, category=5, overlay_type='A', unloadable=True, address=0, room_number=3, priority=2, from_spawner=False, transition=False, clearable=True, cleared=False),
166 Actor(name='Bonk Actor (01E7)', Id='01E7', size=0x148, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=1, from_spawner=False, transition=False, clearable=False, cleared=False),
167 Actor(name='Gold Skulltula', Id='0050', size=0x4A4, category=5, overlay_type='A', unloadable=True, address=0, room_number=3, priority=3, from_spawner=False, transition=False, clearable=True, cleared=False),
168 Actor(name='Bonk Actor (01E7)', Id='01E7', size=0x148, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=2, from_spawner=False, transition=False, clearable=False, cleared=False),
169 Actor(name='Tent-Shaped Spider Web', Id='01F4', size=0x3CC, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=0, from_spawner=False, transition=False, clearable=True, cleared=False),
170 Actor(name='Oceanside Spider House Fireplace Grate', Id='020F', size=0x284, category=0, overlay_type='A', unloadable=False, address=0, room_number=3, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
171 Actor(name='Gold Skulltula', Id='0050', size=0x4A4, category=5, overlay_type='A', unloadable=True, address=0, room_number=3, priority=4, from_spawner=False, transition=False, clearable=True, cleared=False),
172 Actor(name='Bonk Actor (01E7)', Id='01E7', size=0x148, category=0, overlay_type='A', unloadable=True, address=0, room_number=3, priority=3, from_spawner=False, transition=False, clearable=False, cleared=False)
173 ]
174
175
176Oceanside_Room4_queue = [
177 Oceanside_Room3_queue[0],
178 Actor(name='Skulltula', Id='0024', size=0x550, category=5, overlay_type='A', unloadable=True, address=0, room_number=4, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
179 Actor(name='Chest', Id='0006', size=548, category=0, overlay_type='A', unloadable=False, address=0, room_number=4, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
180 ]
181
182
183
184
185
186###############################################################################
187
188Room0_queue = [
189 Actor(name='Wooden Door', Id='0005', size=460, category=0, overlay_type='B', unloadable=False, address=0, room_number=False, priority=0, from_spawner=False, transition=[0,3], clearable=False, cleared=False),
190 Actor(name='Loading Plane', Id='0018', size=332, category=0, overlay_type='B', unloadable=False, address=0, room_number=False, priority=0, from_spawner=False, transition=[0,1], clearable=False, cleared=False),
191 Actor(name='Rupee Cluster', Id='00E8', size=360, category=0, overlay_type='A', unloadable=True, address=0, room_number=0, priority=0, from_spawner=False, transition=False, clearable=True, cleared=False),
192 Actor(name='Dripping Water Effect', Id='0170', size=3644, category=0, overlay_type='A', unloadable=False, address=0, room_number=0, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
193 Actor(name='Dripping Water Effect', Id='0170', size=3644, category=0, overlay_type='A', unloadable=False, address=0, room_number=0, priority=1, from_spawner=False, transition=False, clearable=False, cleared=False),
194 Actor(name='Torch Stand (Generic)', Id='0039', size=500, category=0, overlay_type='A', unloadable=False, address=0, room_number=0, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
195 Actor(name='Pot', Id='0082', size=412, category=0, overlay_type='A', unloadable=True, address=0, room_number=0, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
196 Actor(name='Pot', Id='0082', size=412, category=0, overlay_type='A', unloadable=True, address=0, room_number=0, priority=1, from_spawner=False, transition=False, clearable=False, cleared=False),
197 Actor(name='Pot', Id='0082', size=412, category=0, overlay_type='A', unloadable=True, address=0, room_number=0, priority=2, from_spawner=False, transition=False, clearable=False, cleared=False),
198 Actor(name='???0158', Id='0158', size=328, category=0, overlay_type='A', unloadable=False, address=0, room_number=0, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
199 ]
200
201
202Room1_queue = [
203 Actor(name='Door Shutter', Id='001E', size=360, category=0, overlay_type='B', unloadable=False, address=0, room_number=False, priority=0, from_spawner=False, transition=[1,2], clearable=False, cleared=False),
204 Room0_queue[1],
205 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=0, from_spawner=False, transition=False, clearable=True, cleared=False),
206 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=1, from_spawner=False, transition=False, clearable=True, cleared=False),
207 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=2, from_spawner=False, transition=False, clearable=True, cleared=False),
208 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=3, from_spawner=False, transition=False, clearable=True, cleared=False),
209 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=4, from_spawner=False, transition=False, clearable=True, cleared=False),
210 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=5, from_spawner=False, transition=False, clearable=True, cleared=False),
211 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=6, from_spawner=False, transition=False, clearable=True, cleared=False),
212 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=7, from_spawner=False, transition=False, clearable=True, cleared=False),
213 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=8, from_spawner=False, transition=False, clearable=True, cleared=False),
214 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=9, from_spawner=False, transition=False, clearable=True, cleared=False),
215 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=10, from_spawner=False, transition=False, clearable=True, cleared=False),
216 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=11, from_spawner=False, transition=False, clearable=True, cleared=False),
217 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=12, from_spawner=False, transition=False, clearable=True, cleared=False),
218 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=13, from_spawner=False, transition=False, clearable=True, cleared=False),
219 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=14, from_spawner=False, transition=False, clearable=True, cleared=False),
220 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=15, from_spawner=False, transition=False, clearable=True, cleared=False),
221 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=16, from_spawner=False, transition=False, clearable=True, cleared=False),
222 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=17, from_spawner=False, transition=False, clearable=True, cleared=False),
223 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=18, from_spawner=False, transition=False, clearable=True, cleared=False),
224 Actor(name='Bad Bat', Id='015B', size=476, category=5, overlay_type='A', unloadable=True, address=0, room_number=1, priority=19, from_spawner=False, transition=False, clearable=True, cleared=False),
225 Actor(name='Torch Stand (Generic)', Id='0039', size=500, category=0, overlay_type='A', unloadable=False, address=0, room_number=1, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
226 Actor(name='Torch Stand (Generic)', Id='0039', size=500, category=0, overlay_type='A', unloadable=False, address=0, room_number=1, priority=1, from_spawner=False, transition=False, clearable=False, cleared=False),
227 Actor(name='Torch Stand (Generic)', Id='0039', size=500, category=0, overlay_type='A', unloadable=False, address=0, room_number=1, priority=2, from_spawner=False, transition=False, clearable=False, cleared=False),
228 Actor(name='Pot', Id='0082', size=412, category=0, overlay_type='A', unloadable=True, address=0, room_number=1, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False),
229 Actor(name='Pot', Id='0082', size=412, category=0, overlay_type='A', unloadable=True, address=0, room_number=1, priority=1, from_spawner=False, transition=False, clearable=False, cleared=False),
230 Actor(name='Pot', Id='0082', size=412, category=0, overlay_type='A', unloadable=True, address=0, room_number=1, priority=2, from_spawner=False, transition=False, clearable=False, cleared=False),
231 Actor(name='Chest', Id='0006', size=548, category=0, overlay_type='A', unloadable=False, address=0, room_number=1, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
232 ]
233
234###############################################################################
235
236Room0 = Room(0, Room0_queue, False, 2)
237Room1 = Room(1, Room1_queue, False, 2)
238
239
240Oceanside_Room3 = Room(3, Oceanside_Room3_queue, False, 2)
241Oceanside_Room4 = Room(4, Oceanside_Room4_queue, False, 1)
242
243"""
244
245Define the list of Rooms that we consider
246
247"""
248
249Room_List = [Room0, Room1]
250
251Oceanside_Room_List = [Oceanside_Room3, Oceanside_Room4]
252
253
254"""
255
256In Overlay_dict we collect all of the Overlays of Type A, where the keys are
257the corresponding actor ids
258
259"""
260
261# NOTE: This must be named "Overlay_dict" because it is hardcoded in some functions, like the Deallocate() function
262Overlay_dict = {
263 '015A' : Overlay(address=0, Id='015A', size=6000),
264 '00E8' : Overlay(address=0, Id='00E8', size=1984),
265 '0170' : Overlay(address=0, Id='0170', size=10688),
266 '0039' : Overlay(address=0, Id='0039', size=3552),
267 '0082' : Overlay(address=0, Id='0082', size=9040),
268 '0158' : Overlay(address=0, Id='0158', size=1104),
269 '015B' : Overlay(address=0, Id='015B', size=6048),
270 '0006' : Overlay(address=0, Id='0006', size=8640),
271 '0017' : Overlay(address=0, Id='0017', size=10432),
272 '017B' : Overlay(address=0, Id='017B', size=14320),
273 '007B' : Overlay(address=0, Id='007B', size=5104),
274 '00A2' : Overlay(address=0, Id='00A2', size=24448),
275 '02A5' : Overlay(address=0, Id='02A5', size=0x2660),
276 '0210' : Overlay(address=0, Id='0210', size=0xB90),
277 '0050' : Overlay(address=0, Id='0050', size=0x3540),
278 '0125' : Overlay(address=0, Id='0125', size=0x1490),
279 '01E7' : Overlay(address=0, Id='01E7', size=0x450),
280 '01F4' : Overlay(address=0, Id='01F4', size=0x1A80),
281 '020F' : Overlay(address=0, Id='020F', size=0x780),
282 '0024' : Overlay(address=0, Id='0024', size=0x28E0)
283 }
284
285"""
286
287Here we collect a list of the actors that we allow ourselves to spawn
288
289Notes:
290 'Zora Fins' means 2 fins
291 'Bugs' means a set of 3 bugs
292
293
294"""
295
296Allocation_List = [
297 'Nothing',
298 'Bomb',
299 'Smoke',
300 'Arrow',
301 'Hookshot',
302 'Charged Spin Attack',
303 'Chu',
304 'Zora Fins',
305 'Fish',
306 'Bugs'
307 ]
308
309######
310
311
312"""
313
314NOTE: We NEED to have 'Hookshot' and 'Charged Spin Attack' as the last two options
315in order to consider all cases
316
317Don't have 'Bomb' before 'Smoke' to ensure that the Smoke always gets allocated first
318
319maybe in the future you could jumble/randomize the order of things in this list at each step
320of the solver
321
322"""
323Hardcoded_Allocation_List = [
324 'Smoke',
325 'Smoke',
326 'Smoke',
327 'Chu',
328 'Chu',
329 'Chu',
330 'Arrow',
331 'Arrow',
332 'Arrow',
333 'Arrow',
334 'Arrow',
335 'Bomb',
336 'Bomb',
337 'Bomb',
338 'Zora Fins',
339 'Fish',
340 'Fish',
341 'Bugs',
342 'Bugs',
343 'Hookshot',
344 'Charged Spin Attack'
345 ]
346
347"""
348
349Here we collect a list of the Ids grabbable actors that we can use for superslide SRM
350So far this includes:
351
352 0082: Pot
353
354"""
355
356Grabbable_Actors = ['0082']
357
358
359"""
360
361Here we collect a list of Actor Ids for spawners. So far this includes:
362
363 00E8: Rupee Cluster
364
365"""
366
367Spawner_Ids = ['00E8']
368
369
370"""
371
372We initialize the Heap as a list, putting a node with address 0x40B140 in the 0th entry
373and we place a dummy node at the end of the Heap so that there will always exist two
374consecutive nodes for us to define a condition for which free space in the Heap exists
375
376Keep in mind that the 0x5FFFFF address in the dummy node will not reflect the actual
377address of the corresponding node in-game, but it also isn't relevant to heap manipulation
378since it is so far down
379
380"""
381
382
383Heap = [Node(0x40B140, node_size), Node(0x5FFFFF, node_size)]
384
385
386
387def Overlay_In_Heap(Heap, overlay):
388
389 """
390
391 Overlay is the overlay that we want to check whether or not it is in the Heap
392
393 This function will return True if Overlay is in the Heap and False otherwise
394
395 """
396
397 overlay_in_heap = False
398
399 for entry in Heap:
400
401 if type(entry) == Overlay and entry.Id == overlay.Id:
402
403 overlay_in_heap = True
404
405 return overlay_in_heap
406
407
408def Actor_Id_In_Heap(Heap, actor_id):
409
410 """
411
412 actor_id is the Id that we want to check for
413
414 This function will return True if there exists an Actor in the Heap that
415 has actor_id as its Id and it will return False otherwise
416
417 """
418
419 actor_id_in_heap = False
420
421 for entry in Heap:
422
423 if type(entry) == Actor and entry.Id == actor_id:
424
425 actor_id_in_heap = True
426
427 return actor_id_in_heap
428
429
430def Find_Gaps(Heap):
431
432 """
433
434 This function will find all consecutive nodes and output a list of 4-tuples
435 where the first two entries correspond to the indices of each node in the list
436 and the last two entries correspond to the addresses of each node
437
438 The list should be in order, from the start of the Heap to the end of the Heap
439
440 """
441
442 consecutive_node_count = 0
443
444 node_1_address = 0
445 node_2_address = 0
446 node_1_index = 0
447 node_2_index = 0
448
449 consecutive_node_list = []
450 for entry in Heap:
451 if type(entry) == Node and consecutive_node_count == 0:
452 node_1_address = entry.address
453 node_1_index = Heap.index(entry)
454 consecutive_node_count += 1
455 elif type(entry) == Node and consecutive_node_count == 1:
456 node_2_address = entry.address
457 node_2_index = Heap.index(entry)
458
459 consecutive_node_list.append((node_1_index, node_2_index, node_1_address, node_2_address))
460
461 consecutive_node_count += 1
462 elif type(entry) != Node:
463 consecutive_node_count = 0
464 elif type(entry) == Node and consecutive_node_count > 1:
465 consecutive_node_count += 1
466 print("ERROR: More than 2 consecutive nodes!! (Find_Gaps() Error Message)")
467
468
469 return consecutive_node_list
470
471
472
473
474def Allocate(Heap, actor, Overlay_Dict):
475
476 """
477
478 actor is the actor that we want to allocate into the Heap
479
480 Overlay_Dict is a dictionary where the keys are the actor ids which point to the corresponding Overlays
481
482 This function will account for placing nodes and overlays
483
484 """
485
486
487 #Overlay = Overlay_Dict[actor.Id]
488
489 #Overlay_Allocated = False
490
491 #if Overlay_In_Heap(Heap, Overlay) == True:
492 # Overlay_Allocated = True
493
494 Actor_Allocated = False
495
496 """
497 ##### Not yet defined, not sure if I will bother; not really necessary. Probably should for debugging
498 if Actor_In_Heap == True:
499 print('Error: This Actor is already allocated!! (Error message from Allocate() function)')
500 """
501
502 gap_list = Find_Gaps(Heap)
503
504 # Because we initialize the Heap with 2 nodes, there should always be at least one gap
505 if len(gap_list) < 1:
506 print('ERROR: len(gap_list) < 1 in Allocate() function')
507
508
509 # If the Overlay is type A and the Overlay is not already in the Heap, then we want to allocate the overlay first
510 if actor.overlay_type == 'A':
511
512 ##### We only define Overlay for Type A overlays because Overlay_Dict only has Type A overlays
513 Overlay = Overlay_Dict[actor.Id]
514 Overlay_Allocated = False
515
516 if Overlay_In_Heap(Heap, Overlay) == True:
517 Overlay_Allocated = True
518
519
520 if Overlay_In_Heap(Heap, Overlay) == False:
521
522 for gap in gap_list:
523
524 if Overlay_Allocated == True:
525 break ##### This ensures we don't add in the same Overlay multiple times
526
527 node_2_index = gap[1]
528 node_1_address = gap[2]
529 node_2_address = gap[3]
530
531 gap_size = node_2_address - node_1_address - node_size
532
533 ##### Case 1: the Overlay can fit, but there is NOT enough space for an extra node
534 # Note that gap_size is always a multiple of 16
535
536 if Overlay.size <= gap_size and Overlay.size > gap_size - 2*node_size:
537
538 Overlay.address = node_1_address + node_size
539 Heap.insert(node_2_index, Overlay)
540 Overlay_Allocated = True
541
542
543 ##### Case 2: the Overlay can fit and a new node can also fit
544
545 elif Overlay.size <= gap_size and Overlay.size <= gap_size - 2*node_size:
546
547 Overlay.address = node_1_address + node_size
548 Heap.insert(node_2_index, Overlay)
549
550 ########### ADD IN THE NODE HERE
551 if Overlay.size%16 > 0:
552 Heap.insert(node_2_index + 1, Node(address=Overlay.address + Overlay.size + (16 - Overlay.size%16), size=node_size))
553 elif Overlay.size%16 == 0:
554 Heap.insert(node_2_index + 1, Node(address=Overlay.address + Overlay.size, size=node_size))
555
556 Overlay_Allocated = True
557
558 ############ Now the overlay (if applicable) has been allocated. Now we need to allocate the actor.
559
560 ##### We need to update the gaps_list to account for the overlay being allocated in the Heap already
561 gap_list = Find_Gaps(Heap)
562
563 for gap in gap_list:
564
565 if Actor_Allocated == True:
566 break ##### This ensures we don't add in the same Actor multiple times
567
568 node_2_index = gap[1]
569 node_1_address = gap[2]
570 node_2_address = gap[3]
571
572 gap_size = node_2_address - node_1_address - node_size
573
574 ##### Case 1: the Actor can fit, but there is NOT enough space for an extra node
575 # Note that gap_size is always a multiple of 16
576
577 if actor.size <= gap_size and actor.size > gap_size - 2*node_size:
578
579 actor.address = node_1_address + node_size
580 Heap.insert(node_2_index, actor)
581 Actor_Allocated = True
582
583
584 ##### Case 2: the Actor can fit and a new node can also fit
585
586 elif actor.size <= gap_size and actor.size <= gap_size - 2*node_size:
587
588 actor.address = node_1_address + node_size
589 Heap.insert(node_2_index, actor)
590
591 ########### ADD IN THE NODE HERE
592 if actor.size%16 > 0:
593 Heap.insert(node_2_index + 1, Node(address=actor.address + actor.size + (16 - actor.size%16), size=node_size))
594 elif actor.size%16 == 0:
595 Heap.insert(node_2_index + 1, Node(address=actor.address + actor.size, size=node_size))
596
597 Actor_Allocated = True
598
599def Borders_Node(Heap, entry):
600
601 """
602
603 This function takes an entry of the Heap as input and determines whether or
604 not this entry is adjacent to a node in the heap (the purpose of this is to
605 check if a node is bordering another node since actors and overlays should
606 be bordering two nodes under every circumstance)
607
608 Returns True if the entry is bordering a node, returns False otherwise
609
610 """
611
612 borders_node = False
613
614 entry_index = Heap.index(entry)
615
616 border_1_is_node = False
617 border_2_is_node = False
618
619 if entry_index != 0:
620 border_1 = Heap[entry_index - 1]
621 if type(border_1) == Node:
622 border_1_is_node = True
623
624 if entry_index != len(Heap) - 1:
625 border_2 = Heap[entry_index + 1]
626 if type(border_2) == Node:
627 border_2_is_node = True
628
629 if border_1_is_node == True or border_2_is_node == True:
630 borders_node = True
631
632 return borders_node
633
634
635
636def Deallocate(Heap, actor, Overlay_dict):
637
638
639 """
640
641 actor is the actor that we want to be deallocated from the Heap
642
643 This function will account for removing nodes and overlays
644
645 ##### Remove the actor AND node if applicable
646 ##### Check if any actors with the same Id are still in the Heap
647 ##### if not (and the actor has overlay Type A), then remove the overlay
648
649 We only remove a node if it is part of a gap before deallocating the actor
650 That is, we only remove a node if it borders another node before the actor is deallocated
651
652 """
653
654 if type(actor) != Actor:
655 print("ERROR: Attempted to deallocate something other than an Actor (Deallocate() function error message)")
656
657 # The index of where the actor is in the Heap before being deallocated; this will change after we remove the first node
658 actor_index = Heap.index(actor)
659
660 ##### First check the node above the actor in the Heap
661 node_1 = Heap[actor_index - 1]
662 if type(node_1) != Node:
663 print("ERROR: One of the nodes is not actually a node! (Deallocate() function error message)")
664
665 if Borders_Node(Heap, node_1) == True:
666 Heap.remove(node_1)
667
668 ########## Now the first node has been removed and the indices of the Heap shift
669
670 ##### Now we check the node below the actor in the Heap
671
672 # The index of where the actor is in the Heap before being deallocated; this will change after we remove the first node
673 actor_index = Heap.index(actor)
674
675 node_2 = Heap[actor_index + 1]
676 if type(node_2) != Node:
677 print("ERROR: One of the nodes is not actually a node! (Deallocate() function error message)")
678
679 if Borders_Node(Heap, node_2) == True:
680 Heap.remove(node_2)
681
682 ###########################################################################
683 ##### Now we have removed both of the nodes, if applicable and we must remove the actor itself
684
685 Heap.remove(actor)
686
687 """
688
689 Now if the actor has a Type A overlay, then we must check if the Heap contains
690 any other actors that have the same Id as actor and if not, then we must also
691 remove its overlay from the Heap
692
693 We must also account for removing the nodes around the overlay, if applicable
694
695 """
696
697 if actor.overlay_type == 'A' and Actor_Id_In_Heap(Heap, actor.Id) == False:
698
699 ##### First check the node above the overlay
700 overlay_index = Heap.index(Overlay_dict[actor.Id])
701 node1 = Heap[overlay_index - 1]
702
703 if type(node1) != Node:
704 print("ERROR: One of the nodes is not actually a node! (Deallocate() function error message)")
705
706 if Borders_Node(Heap, node1) == True:
707 Heap.remove(node1)
708
709
710 ##### Now we check the node below the overlay
711 overlay_index = Heap.index(Overlay_dict[actor.Id])
712 node2 = Heap[overlay_index + 1]
713
714 if type(node2) != Node:
715 print("ERROR: One of the nodes is not actually a node! (Deallocate() function error message)")
716
717 if Borders_Node(Heap, node2) == True:
718 Heap.remove(node2)
719
720 ###########################################################################
721 ##### Now we have removed both of the nodes, if applicable and we must remove the overlay itself
722
723 Heap.remove(Overlay_dict[actor.Id])
724
725
726
727def Load_Scene(Heap, room, Overlay_dict):
728
729 if len(Heap) != 2:
730 print("ERROR: Attempted to use Load_Scene() with an inappropriate Heap")
731
732 entry_count = 0
733 for entry in room.priority_queue:
734
735 ##### If the clock is not in the room's set of actors, then we must allocate the clock at the appropriate time when we load the scene
736 if entry_count == room.clock_priority and room.clock_exists == False:
737
738 ##### Allocate the 3-Day Clock actor
739 Allocate(Heap, Clock, Overlay_dict)
740 entry_count += 1
741
742 ##### Allocate the entry in the room's priority queue
743 Allocate(Heap, entry, Overlay_dict)
744
745 entry_count += 1
746
747 ##### Now that all of the actors have been allocated, we want to add in all of the actors that the spawners spawn
748
749 """
750
751 NOTE: THIS DOES NOT HANDLE SPAWNERS OTHER THAN RUPEE CLUSTERS AT THE MOMENT
752
753 In the future, it will need to be considered how the actors created by spawners
754 prioritize over each other... Spring MV is maybe the only place where this really matters
755
756 """
757
758 ##### Check for Rupee Cluster
759 if Overlay_In_Heap(Heap, Overlay_dict['00E8']) == True:
760
761 for j in range(7):
762 rupee = Actor(name='Collectible (Rupee from Rupee Cluster)', Id='000E', size=424, category=0, overlay_type='B', unloadable=True, address=0, room_number=room.number, priority=j, from_spawner=True, transition=False, clearable=True, cleared=False)
763
764 Allocate(Heap, rupee, Overlay_dict)
765
766
767
768def Actor_From_Room_In_Heap(Heap, Room_Number):
769
770 """
771
772 This function takes the Heap and the number of the Room in question as input
773 It returns True if there exists an Actor in the Heap with the inputted Room_Number and False otherwise
774
775 """
776
777 actor_from_room_in_heap = False
778
779 for entry in Heap:
780
781 if type(entry) == Actor and entry.room_number is Room_Number:
782
783 actor_from_room_in_heap = True
784
785 return actor_from_room_in_heap
786
787def Cleared_Actor_In_Heap(Heap):
788
789 """
790
791 This function returns True if there is a cleared actor in the Heap and False otherwise
792
793 """
794
795 cleared_actor_in_heap = False
796
797 for entry in Heap:
798
799 if type(entry) == Actor and entry.cleared == True:
800
801 cleared_actor_in_heap = True
802
803 return cleared_actor_in_heap
804
805
806def Shared_Transition_Count(Heap, Room_Number_1, Room_Number_2):
807
808 """
809
810 This function returns the number of transitions (Planes/Doors) that are shared between
811 the two rooms with room numbers Room_Number_1 and Room_Number_2
812
813 """
814
815 shared_transition_count = 0
816
817 for entry in Heap:
818
819 if type(entry) == Actor and entry.transition != False:
820
821 if (entry.transition[0] == Room_Number_1 and entry.transition[1] == Room_Number_2) or (entry.transition[0] == Room_Number_2 and entry.transition[1] == Room_Number_1):
822
823 shared_transition_count += 1
824
825 return shared_transition_count
826
827def Is_Shared_Transition(actor, Room_Number_1, Room_Number_2):
828
829 """
830
831 If actor is a transition shared between Rooms with numbers Room_Number_1 and Room_Number_2,
832 then this function returns True. Otherwise it returns False
833
834 """
835
836 is_shared_transition = False
837
838 if type(actor) == Actor and actor.transition != False:
839
840 if (actor.transition[0] == Room_Number_1 and actor.transition[1] == Room_Number_2) or (actor.transition[0] == Room_Number_2 and actor.transition[1] == Room_Number_1):
841
842 is_shared_transition = True
843
844 return is_shared_transition
845
846
847def Transition_Is_In_Room(actor, Room_Number):
848
849 transition_is_in_room = False
850
851 if type(actor) == Actor and actor.transition != False:
852
853 if actor.transition[0] == Room_Number or actor.transition[1] == Room_Number:
854
855 transition_is_in_room = True
856
857 return transition_is_in_room
858
859
860def Find_Clock_List(Heap):
861
862 """
863
864 This function finds all clock actor instances in the Heap and returns a list of them, in order
865
866 """
867
868 clock_list = []
869
870 for entry in Heap:
871
872 if type(entry) == Actor and entry.Id == '015A':
873
874 clock_list.append(entry)
875
876 return clock_list
877
878
879def Load_Room(Heap, room, transition, Overlay_dict):
880
881
882 """
883
884 This function updates the Heap after you enter room through transition
885 For example, you might enter Room0 through Plane1 or Door3
886
887 Before executing the script, should probably define Plane1, Plane2, ...
888 Door1, Door2, ..., etc. as the corresponding entries from the room queues.
889 This will make the code more readable when looking for solutions
890
891
892 * First we load all of the actors from the new room
893 * Next, we deallocate everything (well, not literally everything...) from the previous room
894
895
896 Things that this function needs to handle:
897
898 - make sure that you check if each actor was cleared or not (if clearable == True, otherwise it isn't applicable)
899 and then check if it is Category 5 to determine if it loads and immediately deallocates or not
900
901 - checking which clock to deallocate (i.e. deallocate the one that comes later
902 on in the Heap if there are more than one). Maybe define a Find_Clocks function
903
904 - make sure transition never deallocates and never attempts to allocate
905
906 - make sure that the other Transitions unload and then reload (if applicable) after all of
907 the stuff from the previous room deallocated
908
909 - when deallocating stuff from the room that isn't the room you're entering, be sure
910 not to deallocate the clock. Also be careful of relevant Transitions as they don't have
911 actual room numbers (replaced with False)
912
913 - allocate stuff from spawners after the fact (even after planes)
914
915
916 """
917
918 if transition not in Heap:
919 print('2222222222')
920
921 if transition not in room.priority_queue:
922 print('44444444')
923
924 if (transition not in Heap) or (transition not in room.priority_queue):
925 print("ERROR: Attempted to use Load_Room() with an invalid transition")
926
927 current_room_number = -1
928 new_room_number = room.number
929
930 if transition.transition[0] == room.number:
931 current_room_number = transition.transition[1]
932 elif transition.transition[1] == room.number:
933 current_room_number = transition.transition[0]
934 else:
935 print("ERROR: Error with transition list (Load_Room() error message)")
936
937 """
938 First we load all of the actors from the new room, EXCEPT for: the plane/door
939 we pass through AND any other shared transitions AND any actors with both
940 cleared == True and Category == 5 (these ones never attempt to load)
941 """
942
943 for actor in room.priority_queue:
944
945 ### If the actor is not a Transition OR if the actor is a transition but doesn't connect to the current room
946 if (actor.transition == False) or (actor.transition != False and actor.transition[0] != current_room_number and actor.transition[1] != current_room_number):
947
948 ### If the actor is Category 5, then only attempt to load it if it has not been cleared
949 if actor.category != 5 or actor.cleared == False:
950
951 Allocate(Heap, actor, Overlay_dict)
952
953 """
954 - Now all of the relevant actors from the new room have been allocated
955 - Now we need to immediately deallocate any actors with Clearable == True and Cleared == True
956 - We also need to deallocate any transitions which are shared between the current room and the new room
957 EXCEPT for transition itself (the transition that we passed through to get to the new room)
958 - We also need to deallocate the second clock actor in the Heap if it exists (do this after everything else for simplicity)
959
960 Note that "current_room_number" is the room number of the room we were in before loading the new room
961 """
962
963 while Actor_From_Room_In_Heap(Heap, current_room_number) == True or Cleared_Actor_In_Heap(Heap) == True or Shared_Transition_Count(Heap, current_room_number, new_room_number) > 1:
964
965 for entry in Heap:
966
967 if (type(entry) == Actor) and (entry.room_number is current_room_number or entry.cleared == True or Is_Shared_Transition(entry, current_room_number, new_room_number) == True or (entry.transition != False and Transition_Is_In_Room(entry, new_room_number) == False ) ) and (entry != transition):
968
969 Deallocate(Heap, entry, Overlay_dict)
970
971 ########## Now we will find all of the clocks and deallocate the second clock if it exists (and report error if more than two clocks)
972
973 Clock_List = Find_Clock_List(Heap)
974
975 if len(Clock_List) > 2:
976 print("ERROR: More than 2 Clocks in the Actor Heap (Load_Room() Error Message)")
977 elif len(Clock_List) < 1:
978 print("ERROR: No Clock Actor Instance in the Actor Heap (Load_Room() Error Message)")
979
980 ##### If there are two clocks, then we deallocate the second clock that appears in the Heap
981 if len(Clock_List) > 1:
982
983 Deallocate(Heap, Clock_List[1], Overlay_dict)
984
985
986 ##### Now we allocate any shared transitions EXCEPT for transition itself (the door/plane we entered to get into this room)
987
988 for entry in room.priority_queue:
989
990 # If entry is a shared transition and is NOT the transition that we passed through
991 if (type(entry) == Actor) and (entry.transition != False) and Is_Shared_Transition(entry, current_room_number, new_room_number) == True and (entry != transition):
992
993 Allocate(Heap, entry, Overlay_dict)
994
995 ###################################### Now we only have to account for allocating things from spawners
996
997
998 """
999
1000 NOTE: THIS DOES NOT HANDLE SPAWNERS OTHER THAN RUPEE CLUSTERS AT THE MOMENT
1001
1002 In the future, it will need to be considered how the actors created by spawners
1003 prioritize over each other... Spring MV is maybe the only place where this really matters
1004
1005 """
1006
1007 ##### Check for Rupee Cluster
1008 if Overlay_In_Heap(Heap, Overlay_dict['00E8']) == True:
1009
1010 for j in range(7):
1011 rupee = Actor(name='Collectible (Rupee from Rupee Cluster)', Id='000E', size=424, category=0, overlay_type='B', unloadable=True, address=0, room_number=room.number, priority=j, from_spawner=True, transition=False, clearable=True, cleared=False)
1012
1013 Allocate(Heap, rupee, Overlay_dict)
1014
1015
1016
1017
1018
1019def Display_Heap(Heap):
1020
1021 for entry in Heap:
1022
1023 if type(entry) == Node:
1024
1025 print(hex(entry.address) + '-----' + 'NODE-----------------')
1026
1027 elif type(entry) == Overlay:
1028
1029 print(hex(entry.address) + ' ' + entry.Id + ' ' + 'OVERLAY')
1030
1031 elif type(entry) == Actor:
1032
1033 print(hex(entry.address) + ' ' + entry.Id + ' ' + 'INSTANCE')
1034
1035 else:
1036 print("ERROR!!! Unexpected Entry Type in Heap!!!!!!!!!")
1037
1038
1039###############################################################################
1040###############################################################################
1041###############################################################################
1042###############################################################################
1043###############################################################################
1044###############################################################################
1045
1046def Allocate_Fish(Heap, Room_Number, Overlay_dict):
1047
1048 Fish = Actor(name='Fish', Id='0017', size=636, category=0, overlay_type='A', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1049
1050 Allocate(Heap, Fish, Overlay_dict)
1051
1052
1053def Allocate_Bugs(Heap, Room_Number, Overlay_dict):
1054
1055 """
1056
1057 This function allocates a set of 3 bugs to the Heap
1058
1059 """
1060
1061 for i in range(3):
1062 Bug = Actor(name='Bug', Id='017B', size=884, category=0, overlay_type='A', unloadable=True, address=0, room_number=Room_Number, priority=i, from_spawner=False, transition=False, clearable=False, cleared=False)
1063
1064 Allocate(Heap, Bug, Overlay_dict)
1065
1066
1067def Allocate_Bomb(Heap, Room_Number, Overlay_dict):
1068
1069 Bomb = Actor(name='Bomb', Id='0009', size=516, category=0, overlay_type='B', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1070
1071 Allocate(Heap, Bomb, Overlay_dict)
1072
1073
1074def Allocate_Smoke(Heap, Room_Number, Overlay_dict):
1075
1076 """
1077
1078 This function allocates a bomb, then allocates smoke (this happens when the bomb explodes)
1079 and then deallocates the bomb (we bothered allocating the bomb to ensure that the smoke
1080 appears in the right spot in the Heap)
1081
1082 Note that we should never allow ourselves to allocate smoke AFTER calling Allocate_Bomb()
1083 because in reality the first bomb would explode first (this isn't strictly true, but we should
1084 do it this way at least in the simple script)
1085
1086 """
1087
1088 Bomb = Actor(name='Bomb', Id='0009', size=516, category=0, overlay_type='B', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1089
1090 Allocate(Heap, Bomb, Overlay_dict)
1091
1092 Smoke = Actor(name='Smoke', Id='00A2', size=11908, category=0, overlay_type='A', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1093
1094 Allocate(Heap, Smoke, Overlay_dict)
1095
1096 Deallocate(Heap, Bomb, Overlay_dict)
1097
1098def Allocate_Arrow(Heap, Room_Number, Overlay_dict):
1099
1100 """
1101
1102 This function allocates an arrow into the heap. Note that Deku Bubbles are
1103 the same actor as arrows (in that they're both 000F)
1104
1105 """
1106
1107 Arrow = Actor(name='Arrow', Id='000F', size=632, category=0, overlay_type='B', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1108
1109 Allocate(Heap, Arrow, Overlay_dict)
1110
1111
1112def Allocate_Hookshot(Heap, Room_Number, Overlay_dict):
1113
1114 Hookshot = Actor(name='Hookshot', Id='003D', size=528, category=0, overlay_type='B', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1115
1116 Allocate(Heap, Hookshot, Overlay_dict)
1117
1118
1119def Allocate_Chu(Heap, Room_Number, Overlay_dict):
1120
1121 Chu = Actor(name='Chu', Id='006A', size=480, category=0, overlay_type='B', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1122
1123 Allocate(Heap, Chu, Overlay_dict)
1124
1125
1126def Allocate_Zora_Fins(Heap, Room_Number, Overlay_dict):
1127
1128 """
1129
1130 This function allocates 2 Zora Fin actor instances
1131
1132 """
1133
1134 for i in range(2):
1135
1136 Zora_Fin = Actor(name='Zora Fin', Id='0020', size=500, category=0, overlay_type='B', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1137
1138 Allocate(Heap, Zora_Fin, Overlay_dict)
1139
1140
1141def Allocate_Charged_Spin_Attack(Heap, Room_Number, Overlay_dict):
1142
1143 """
1144
1145 This functions allocates the Spin Attack & Sword Beam Effects and then the
1146 Spin Attack Charge Particles (This is the order they get allocated in when
1147 you charge a spin attack)
1148
1149 """
1150
1151 Spin_Attack_and_Sword_Beam_Effects = Actor(name='Spin Attack & Sword Beam Effects', Id='0035', size=452, category=0, overlay_type='B', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1152
1153 Allocate(Heap, Spin_Attack_and_Sword_Beam_Effects, Overlay_dict)
1154
1155 Spin_Attack_Charge_Particles = Actor(name='Spin Attack Charge Particles', Id='007B', size=1367, category=0, overlay_type='A', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
1156
1157 Allocate(Heap, Spin_Attack_Charge_Particles, Overlay_dict)
1158
1159
1160
1161"""
1162
1163Before proceeding, we should define all of the transitions we plan on passing through
1164
1165Since "Beneath the Graveyard" is relatively simple and I currently only want to consider
1166passing through a single plane, I will just define Plane_1 to be the plane shared between
1167Room0 and Room1
1168
1169This loading plane happens the be the second element in Room0_queue, so I will define it based on that
1170
1171"""
1172
1173Plane_1 = Room0_queue[1]
1174
1175
1176Transition_List= [Plane_1]
1177
1178
1179"""
1180
1181 Grabbable_dict is a dictionary of the grabbable actors (such as pots) that
1182 we want to attempt to use for superslide SRM where the keys are the grabbable
1183 actors and the values are lists with 3-bit strings where each bit means:
1184
1185 100 : Possible to enter Plane with both Bomb and Smoke loaded
1186 010 : Possible to enter Plane with Smoke loaded, but no Bomb loaded
1187 001 : Possible to enter Plane with no Smoke loaded
1188
1189 and Transitions, where the transitions are the ones you can superslide through
1190
1191
1192
1193"""
1194
1195Grabbable_dict = {
1196 Room0_queue[6] : ['100', Plane_1],
1197 Room0_queue[7] : ['100', Plane_1],
1198 Room1_queue[25] : ['110', Plane_1],
1199 Room1_queue[26] : ['100', Plane_1],
1200 Room1_queue[27] : ['011', Plane_1]
1201 }
1202
1203
1204"""
1205
1206Below this we can consider a sequence of Room loads and then display the Heap
1207
1208"""
1209
1210
1211#Load_Scene(Heap, Room0)
1212
1213
1214#Load_Room(Heap, Room1, Plane_1, Overlay_dict)
1215
1216#Load_Room(Heap, Room0, Plane_1, Overlay_dict)
1217
1218#Load_Room(Heap, Room1, Plane_1, Overlay_dict)
1219
1220#Load_Room(Heap, Room0, Plane_1, Overlay_dict)
1221
1222
1223#Display_Heap(Heap)
1224
1225###############################################################################
1226###############################################################################
1227###############################################################################
1228###############################################################################
1229###############################################################################
1230###############################################################################
1231
1232
1233def Grabbable_In_Room(room, grabbable_actor_list):
1234
1235 """
1236
1237 This function checks the inputted room to see if it contains a grabbale actor
1238 that we can use for the superslide for SRM (in theory at least...)
1239
1240 """
1241
1242 grabbable_in_room = False
1243
1244 for actor in room.priority_queue:
1245
1246 if type(actor) == Actor and actor.Id in grabbable_actor_list:
1247
1248 grabbable_in_room = True
1249
1250 return grabbable_in_room
1251
1252
1253def Valid_Grabbable_In_Room(room, grabbable_actor_dict):
1254
1255 """
1256
1257 This function checks the inputted room to see if it contains a grabbale actor
1258 that we can use for the superslide for SRM
1259
1260 """
1261
1262 valid_grabbable_in_room = False
1263
1264 for actor in room.priority_queue:
1265
1266 if actor in grabbable_actor_dict.keys():
1267
1268 valid_grabbable_in_room = True
1269
1270 return valid_grabbable_in_room
1271
1272
1273def Chest_In_Room(room):
1274
1275 """
1276
1277 This function checks the inputted room to see if it contains a chest
1278
1279 """
1280
1281 chest_in_room = False
1282
1283 for actor in room.priority_queue:
1284
1285 if type(actor) == Actor and actor.Id == '0006':
1286
1287 chest_in_room = True
1288
1289 return chest_in_room
1290
1291
1292def Deku_Guard_In_Room(room):
1293
1294 """
1295
1296 This function checks the inputted room to see if it contains a Deku Guard
1297
1298 """
1299
1300 deku_guard_in_room = False
1301
1302 for actor in room.priority_queue:
1303
1304 if type(actor) == Actor and actor.Id == '017A':
1305
1306 deku_guard_in_room = True
1307
1308 return deku_guard_in_room
1309
1310
1311def Transition_List(room):
1312
1313 """
1314
1315 This function takes a room as input and returns a list of all of its transitions
1316 (i.e. doors/loading planes that lead to other rooms)
1317
1318 """
1319
1320 transition_list = []
1321
1322 for actor in room.priority_queue:
1323
1324 if actor.transition != False:
1325
1326 transition_list.append(actor)
1327
1328 return transition_list
1329
1330
1331def Shared_Transitions(room1, room2):
1332
1333 """
1334
1335 This function takes two Rooms as input and returns a list of their shared transitions
1336 (essentially returns the edges connecting these rooms if we view the rooms are nodes
1337 in a graph)
1338
1339 """
1340
1341 shared_transitions = []
1342
1343 for transition in Transition_List(room1):
1344
1345 if Is_Shared_Transition(transition, room1.number, room2.number) == True:
1346
1347 shared_transitions.append(transition)
1348
1349 return shared_transitions
1350
1351
1352def Shared_Transition_Exists(room1, room2):
1353
1354 """
1355
1356 This function takes two Rooms as input and returns True if they share a transition
1357 and False otherwise
1358
1359 """
1360
1361 shared_transition_exists = False
1362
1363 for transition in Transition_List(room1):
1364
1365 if Is_Shared_Transition(transition, room1.number, room2.number) == True:
1366
1367 shared_transition_exists = True
1368
1369 return shared_transition_exists
1370
1371
1372def Neighbors(room, Room_List):
1373
1374 """
1375
1376 This function takes a room as input along with a list of all potential rooms
1377 and returns a list of all rooms that share a transition with this room (excluding itself)
1378
1379 """
1380
1381 neighbors = []
1382
1383 for ROOM in Room_List:
1384
1385 if ROOM != room and Shared_Transition_Exists(room, ROOM) == True:
1386
1387 neighbors.append(ROOM)
1388
1389 return neighbors
1390
1391
1392def New_Room(room, transition, Room_List):
1393
1394 """
1395
1396 This function takes a room, a transition, and a list of all available rooms
1397 as input and returns the room that you would be in if you started in room
1398 and passed through transition
1399
1400 """
1401
1402 if transition not in Transition_List(room):
1403 print("ERROR: Invalid input into New_Room() function; transition is not in room")
1404
1405 for ROOM in Room_List:
1406
1407 if ROOM != room and (transition.transition[0] == ROOM.number or transition.transition[1] == ROOM.number) and ROOM.number != room.number:
1408
1409 new_room = ROOM
1410
1411 return new_room
1412
1413
1414def Current_Room(Room_Load_Permutation, Room_List):
1415
1416 """
1417
1418 Room_Load_Permutation is a list whose first element is the initial room that is started at
1419
1420 All subsequent entries are transitions (Actor class objects with transition != False)
1421
1422
1423 Room_List is a list of all available Rooms
1424
1425
1426 This function returns what Room you would be in after entering every transition listed in
1427 the permutation, assuming that you start in the initial room
1428
1429 """
1430
1431 if type(Room_Load_Permutation[0]) != Room:
1432 print("ERROR: no initial room in permutation (Current_Room() function error message)")
1433
1434 current_room = Room_Load_Permutation[0]
1435
1436 if len(Room_Load_Permutation) > 1:
1437
1438 for transition in Room_Load_Permutation[1:len(Room_Load_Permutation)]:
1439
1440 current_room = New_Room(current_room, transition, Room_List)
1441
1442 return current_room
1443
1444
1445def Room_Order_List(Room_Load_Permutation, Room_List):
1446
1447 """
1448
1449 Room_Load_Permutation is a list whose first element is the initial room that is started at
1450
1451 All subsequent entries are transitions (Actor class objects with transition != False)
1452
1453
1454 Room_List is a list of all available Rooms
1455
1456
1457 This function returns a list of what Room you would be in at each step of
1458 entering transitions
1459
1460 """
1461
1462 if type(Room_Load_Permutation[0]) != Room:
1463 print("ERROR: no initial room in permutation (Get_Room_Load_List() function error message)")
1464
1465 room_order_list = []
1466
1467 for i in range(0, len(Room_Load_Permutation)):
1468
1469 current_room = Current_Room(Room_Load_Permutation[0:i+1], Room_List)
1470
1471 room_order_list.append(current_room)
1472
1473 return room_order_list
1474
1475
1476def Generate_Room_Load_Permutations(Initial_Room, Room_List, Max_Transition_Count):
1477
1478 """
1479
1480 TODO: Debug this function... try calling: Generate_Room_Load_Permutations(Room0, Room_List, 1)
1481
1482
1483 This function seems to run for now, but it is untested for when we have multiple planes
1484 I will test this once I do Deku Palace input
1485
1486 """
1487
1488 """
1489
1490 This function takes as input the initial room (Initial_Room) that the scene was loaded in
1491 the list of all Rooms we want to consider visiting (Room_List), and Max_Transition_Count
1492 which is the maximum number of times we want to allow ourselves to load a new room
1493
1494 This function returns a list of all permutations of ways to enter new rooms after starting
1495 from the initial room (while limiting the number of room loads we do to be exactly Max_Transition_Count)
1496 where each permutation is a list in the form [Initial_Room, Transition1, Transition2, Transition3, ..., TransitionX]
1497 for X = Max_Transition_Count (so to get all permutations for X <= Max_Transition_Count, just
1498 use a for loop and call this function in each iteration of the foor loop and concatenate the lists)
1499
1500 """
1501
1502 if Max_Transition_Count == 0:
1503
1504 new_permutation_list = [[Initial_Room]]
1505
1506 return new_permutation_list
1507
1508
1509 else:
1510
1511 new_permutation_list = []
1512 permutation_list = Generate_Room_Load_Permutations(Initial_Room, Room_List, Max_Transition_Count - 1)
1513
1514 for permutation in permutation_list:
1515 for room in Neighbors(Current_Room(permutation, Room_List), Room_List):
1516 for transition in Shared_Transitions(Current_Room(permutation, Room_List), room):
1517 new_permutation = copy(permutation)
1518 new_permutation.append(transition)
1519 #permutation_list.append(new_permutation)
1520 new_permutation_list.append(new_permutation)
1521
1522 return new_permutation_list
1523
1524
1525def Generate_All_Room_Load_Permutations(Initial_Room, Room_List, Max_Transition_Count):
1526
1527 """
1528
1529 This function returns all permutations of ways to load a room starting from the initial room
1530 where the number of room loads is <= Max_Transition_Count
1531
1532 """
1533
1534 permutation_list = []
1535
1536 for N in range(Max_Transition_Count):
1537
1538 new_permutation_list = Generate_Room_Load_Permutations(Initial_Room, Room_List, N)
1539 permutation_list = permutation_list + new_permutation_list
1540
1541 return permutation_list
1542
1543
1544def Generate_Almost_All_Room_Load_Permutations(Initial_Room, Room_List, Max_Transition_Count):
1545
1546 """
1547
1548 This function returns all permutations of ways to load a room starting from the initial room
1549 where the number of room loads is <= Max_Transition_Count
1550
1551 this will always output a list with length at least 2, which is why it is different
1552 from Generate_All_Room_Load_Permutations
1553
1554 """
1555
1556 permutation_list = []
1557
1558 for N in range(1, Max_Transition_Count):
1559
1560 new_permutation_list = Generate_Room_Load_Permutations(Initial_Room, Room_List, N)
1561 permutation_list = permutation_list + new_permutation_list
1562
1563 return permutation_list
1564
1565
1566def Generate_All_Room_Order_Lists(Initial_Room, Room_List, Max_Transition_Count):
1567
1568 """
1569
1570 This function returns all permutations of ways to traverse through rooms, starting
1571 from the initial room where the number of room loads is <= Max_Transition_Count
1572
1573 The distinction between this and Generate_All_Room_Load_Permutations is that
1574 this will, instead of listing transitions, list the Room you're currently in
1575 at each step
1576
1577 """
1578
1579 room_order_permutation_list = []
1580
1581 room_load_permutation_list = Generate_All_Room_Load_Permutations(Initial_Room, Room_List, Max_Transition_Count)
1582
1583
1584 iteration_count = 0
1585 for room_load_permutation in room_load_permutation_list:
1586
1587 print("Generate_All_Room_Order_Lists: %d out of %d" %(iteration_count, len(room_load_permutation_list)))
1588 iteration_count += 1
1589
1590 room_order_list = Room_Order_List(room_load_permutation, Room_List)
1591
1592 room_order_permutation_list.append(room_order_list)
1593
1594 return room_order_permutation_list
1595
1596
1597def Generate_Allocation_Permutations(allocation_list):
1598
1599 """
1600
1601 Whatever, I'm just hardcoding a list of all of the actor names I want to allow
1602 and then using itertools to make a list of all of the permutations
1603
1604 """
1605
1606 """
1607
1608 TODO: Finish this function, also generalize it in the future
1609
1610 """
1611
1612 """
1613
1614 THIS FUNCTION IS SIMPLIFIED AT THE MOMENT AND COULD BE IMPROVED TO GENERATE
1615 EVEN MORE POSSIBLE PERMUTATIONS
1616
1617 allocation_list is a list of strings of things to allocate
1618
1619 for example:
1620
1621 allocation_list = [
1622 'Nothing',
1623 'Bomb',
1624 'Smoke',
1625 'Arrow',
1626 'Hookshot',
1627 'Charged Spin Attack',
1628 'Chu',
1629 'Zora Fins',
1630 'Fish',
1631 'Bugs'
1632 ]
1633
1634 """
1635
1636 allocation_permutation_list = []
1637
1638
1639 for i in range(len(allocation_list) + 1):
1640
1641 print("Generate_Allocation_Permutations: %d out of %d" %(i, len(allocation_list)))
1642
1643
1644 Permutations = list(itertools.permutations(allocation_list, i))
1645
1646 allocation_permutation_list = allocation_permutation_list + Permutations
1647
1648 return allocation_permutation_list
1649
1650
1651def Clear_Instances(actor_id, room):
1652
1653 """
1654
1655 This function takes an actor_id and room as input and sets actor.cleared = True
1656 for all actors with actor.id == actor_id in room
1657
1658 Call this before loading the scene or anything if you want some specific
1659 actor cleared already. For example, I'd call Clear_Instances('015B', Room1)
1660 to clear all of the bad bats in Beneath the Graveyard
1661
1662 """
1663
1664 for actor in room.priority_queue:
1665
1666 if actor.Id == actor_id and actor.clearable == True:
1667
1668 actor.cleared = True
1669
1670
1671def Clear_Instance(actor, room):
1672
1673 """
1674
1675 This function takes a specific actor in a room as input and sets
1676 actor.cleared = True
1677
1678 """
1679
1680 if actor.clearable == True:
1681
1682 actor.cleared = True
1683
1684
1685def Generate_Deallocation_Combinations(room):
1686
1687 """
1688 ##### Note: we actually get combinations instead of permutations because
1689 the order in which we deallocate actors doesn't matter
1690
1691 This function returns a list of combinations (stored as tuples of Actors)
1692
1693
1694
1695 Some things this (or maybe some other) function needs to account for:
1696
1697 if any rupee from a rupee cluster is deallocated in a deallocation step,
1698 then clear the rupee cluster actor instance (00E8) [note that there is
1699 at most one rupee cluster instance in every room in the game, so there is
1700 no need to check which cluster the rupees are associated with]
1701
1702 if all bad bats are deallocated on the same deallocation step, then they
1703 must all be cleared... actually, stronger: if all Category 5 actors with
1704 the same Id in a given room are deallocated on the same deallocation step,
1705 then clear all instances... actually this isn't good enough (need to add
1706 this into the input I believe or just treat bad bats as a special case)
1707
1708
1709 """
1710
1711 deallocation_list = []
1712
1713 for actor in room.priority_queue:
1714
1715 if actor.cleared == False and actor.unloadable == True:
1716
1717 deallocation_list.append(actor)
1718
1719 ##### Now we have a list of all actors in room that we have the option of deallocationg
1720
1721 ##### Now want want to generate a list of permutations
1722 ########## ACTUALLY, order doesn't matter for deallocation, so all combinations suffices
1723
1724 combination_list = []
1725
1726 for i in range(len(deallocation_list) + 1):
1727
1728 Combinations = list(itertools.combinations(deallocation_list, i))
1729
1730 combination_list = combination_list + Combinations
1731
1732 return combination_list
1733
1734
1735
1736
1737def Build_Room_Deallocation_Combination_Graph(room_order_list):
1738
1739
1740 """
1741
1742 This function takes a room_order_list as input (that is, a list in the form
1743 [initial_room, Room1, Room2, Room3, ..., RoomN] which describes the order we
1744 visit rooms in (note that Roomi could be equal to Roomj even for i =/= j)) and
1745 returns a dictionary where the keys are vertices whose values are lists of the
1746 other vertices that they are connected to. Each vertex represents a deallocation
1747 combination for the room that it corresponds to.
1748
1749 If the edges are directed, then this can be viewed as a multitree with some
1750 dummy root vertex and then each generation corresponds to a Room.
1751
1752 """
1753
1754 room_count = 0
1755
1756 #### Encode a dummy root node to make finding paths easier
1757 graph = {('root', room_count - 1) : []}
1758
1759
1760 iteration_count = 0
1761 ### for all rooms except for the last one
1762 for room in room_order_list[0:len(room_order_list)-1]:
1763
1764 print("Build_Room_Deallocation_Combination_Graph: %d out of %d" %(iteration_count, len(room_order_list) - 1))
1765 iteration_count += 1
1766
1767 combination_list = Generate_Deallocation_Combinations(room)
1768
1769 for combination in combination_list:
1770
1771 for key in graph.keys():
1772
1773 ### If the key is from the previous generation, then append every combination to its list
1774 if key[1] == room_count - 1:
1775
1776 graph[key].append(combination)
1777
1778 graph[(combination, room_count)] = []
1779
1780 room_count += 1
1781
1782 return graph
1783
1784
1785def Find_Leaves(graph):
1786
1787 """
1788
1789 This function takes a graph (really a dictionary) created by Build_Room_Deallocation_Combination_Graph()
1790 and returns a list of all of its leaves
1791
1792 """
1793
1794 leaf_list = []
1795
1796 for key in graph:
1797 # only leaves will point to empty lists
1798 if graph[key] == []:
1799 leaf_list.append(key)
1800
1801 return leaf_list
1802
1803
1804def Find_All_Paths(graph, start, end, path=[]):
1805
1806 """
1807
1808 This function takes a graph (really a dictionary) and start and end vertices
1809 as input and returns a list of all paths from start to end
1810
1811 TODO: maybe don't rely on hardcoding what the root's key is and instead write
1812 a function to find it (though hardcode is prob faster if you don't make mistakes)
1813
1814 I will use this to find all paths from ('root', -1) [note that I am hardcoding
1815 this instead of just finding a root without any parent] to a given lead, and
1816 I will do this for all leafs (which I can get by doing Find_Leaves(graph))
1817
1818 """
1819
1820
1821 path = path + [start]
1822 if start == end:
1823 return [path]
1824 if not (start in graph):
1825 return []
1826 paths = []
1827 for vertex in graph[start]:
1828 if vertex not in path:
1829 newpaths = Find_All_Paths(graph, vertex, end, path)
1830 for newpath in newpaths:
1831 paths.append(newpath)
1832 return paths
1833
1834
1835def Find_All_Deallocation_Combination_Paths(graph):
1836
1837 """
1838
1839 TODO: Note that I hardcode what the key of the root vertex is: ('root', -1)
1840
1841 This returns a list of all (n-1)-permutations of deallocation combinations
1842 for a given room_order_list (where we assume there are n rooms we travel to
1843 including the initial room). This gives us the thing we called D1
1844
1845 """
1846
1847 all_deallocation_combination_paths = []
1848
1849 leaf_list = Find_Leaves(graph)
1850
1851 iteration_count = 0
1852 for leaf in leaf_list:
1853
1854 print("Find_All_Deallocation_Combination_Paths: %d out of %d" %(iteration_count, len(leaf_list)))
1855 iteration_count += 1
1856
1857 # I hardcode the root key to be ('root', -1)
1858 path_to_leaf = Find_All_Paths(graph, ('root', -1), leaf)
1859
1860 all_deallocation_combination_paths = all_deallocation_combination_paths + path_to_leaf
1861
1862
1863 ##### Since every key is a tuple in the form (combination, number), get rid of number part
1864 for path in all_deallocation_combination_paths:
1865 for vertex in path:
1866 path[path.index(vertex)] = vertex[0]
1867
1868 return all_deallocation_combination_paths
1869
1870
1871
1872
1873def Generate_Action_Permutations(room_order_list, allocation_list):
1874
1875 """
1876
1877 THIS IS THE FUNCTION THAT FINALLY GIVES US ALL OF THE PERMUTATIONS OF THINGS
1878 TO DO FOR A GIVEN room_order_list and the allocation_list.
1879
1880
1881
1882 WE WILL RUN THIS FUNCTION ON EVERY PERMUTATION OF ROOM ORDER LISTS USING
1883 Generate_All_Room_Order_Lists(Initial_Room, Room_List, Max_Transition_Count)
1884
1885
1886 ONCE WE DO THAT WE WILL HAVE EVERY SINGLE PERMUTATION THAT WE WANT TO TEST
1887
1888 """
1889
1890 allocation_permutations = Generate_Allocation_Permutations(allocation_list)
1891
1892 ##### Now we want all (n-1)-permutations of allocation permutations
1893 A1 = list(itertools.permutations(allocation_permutations, len(room_order_list) - 1))
1894
1895 #### deallocation combination graph
1896 graph = Build_Room_Deallocation_Combination_Graph(room_order_list)
1897
1898 D1 = Find_All_Deallocation_Combination_Paths(graph)
1899
1900 ###########################################################################
1901
1902 # create output list o
1903 o = []
1904 for i in range(len(A1)):
1905
1906 print("Generate_Action_Permutations: %d out of %d" %(i, len(A1)))
1907
1908 for j in range(len(D1)):
1909 for b in range(2**(len(room_order_list) - 1)):
1910 # create new empty list p
1911 p = []
1912 for k in range(len(room_order_list) - 1):
1913 p.append(room_order_list[k])
1914
1915 if bin(b)[2:].zfill(len(room_order_list)-1) == 1:
1916
1917 # add each element of A1[i][k] to p
1918 for element in A1[i][k]:
1919 p.append(element)
1920 # add each element of D1[j][k] to p
1921 for element in D1[j][k]:
1922 p.append(element)
1923
1924 elif bin(b)[2:].zfill(len(room_order_list)-1) == 0:
1925
1926 # add each element of D1[j][k] to p
1927 for element in D1[j][k]:
1928 p.append(element)
1929 # add each element of A1[i][k] to p
1930 for element in A1[i][k]:
1931 p.append(element)
1932
1933 # Add the last room to p
1934 p.append(room_order_list[len(room_order_list)-1])
1935 # append p to o
1936 o = o + p
1937
1938 return o
1939
1940
1941
1942def Generate_Heap_Permutations(Initial_Room, Room_List, Max_Transition_Count, allocation_list):
1943
1944 """
1945
1946 This function takes the initial room, the Room List, the Maximum Number of Transitions
1947 that we want to allow, and the allocation list as input and returns every permutation
1948 for heap manip setups to try (possibilities currently mostly limited by allocation_list)
1949
1950 WE WILL USE THIS FUNCTION IN THE HEAP MANIP SOLVER
1951
1952 """
1953
1954 heap_permutations = []
1955
1956 All_Room_Order_Lists = Generate_All_Room_Order_Lists(Initial_Room, Room_List, Max_Transition_Count)
1957
1958 iteration_count= 0
1959 for room_order_list in All_Room_Order_Lists:
1960
1961 print("Iteration %d out of %d" %(iteration_count, len(All_Room_Order_Lists)))
1962
1963 action_permutations = Generate_Action_Permutations(room_order_list, allocation_list)
1964
1965 heap_permutations = heap_permutations + action_permutations
1966
1967 iteration_count += 1
1968
1969
1970 print("HEAP PERMUTATION GENERATION COMPLETE")
1971
1972 return heap_permutations
1973
1974
1975
1976###############################################################################
1977###############################################################################
1978###############################################################################
1979###############################################################################
1980###############################################################################
1981###############################################################################
1982###############################################################################
1983
1984def Actor_Is_In_Heap(Heap, actor):
1985
1986 """
1987
1988 actor is the Actor that we want to check for
1989
1990 This function will return True if this Actor is in the Heap and False otherwise
1991
1992 """
1993
1994 actor_is_in_heap = False
1995
1996 for entry in Heap:
1997
1998 if type(entry) == Actor and entry == actor:
1999
2000 actor_is_in_heap = True
2001
2002 return actor_is_in_heap
2003
2004def Actor_Is_In_Room(room, actor):
2005
2006 """
2007
2008 actor is the Actor that we want to check for
2009
2010 This function will return True if this Actor is in the room and False otherwise
2011
2012 """
2013
2014 actor_is_in_room = False
2015
2016 for entry in room.priority_queue:
2017
2018 if type(entry) == Actor and entry == actor:
2019
2020 actor_is_in_room = True
2021
2022 return actor_is_in_room
2023
2024
2025
2026def Bomb_And_Smoke_Superslide(Heap, Room_Number, Overlay_dict):
2027
2028 """
2029
2030 This function allocates a bomb, then allocates smoke (this happens when the bomb explodes)
2031
2032 """
2033
2034 Bomb = Actor(name='Bomb', Id='0009', size=516, category=0, overlay_type='B', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
2035
2036 Allocate(Heap, Bomb, Overlay_dict)
2037
2038 Smoke = Actor(name='Smoke', Id='00A2', size=11908, category=0, overlay_type='A', unloadable=True, address=0, room_number=Room_Number, priority=0, from_spawner=False, transition=False, clearable=False, cleared=False)
2039
2040 Allocate(Heap, Smoke, Overlay_dict)
2041
2042
2043
2044
2045
2046def Copy_Room_List(Room_List):
2047
2048 """
2049
2050 This function takes a list of all Rooms, Room_List, as input
2051 and returns a list of copies of all of the Rooms in Room_List
2052
2053 """
2054
2055 ##### First we want a list of all shared entries between the Room priority queues
2056
2057 shared_actor_list = []
2058
2059 for room1 in Room_List:
2060 for room2 in Room_List:
2061
2062 if room2 != room1:
2063
2064 for actor1 in room1.priority_queue:
2065 for actor2 in room2.priority_queue:
2066 if (actor1 == actor2) and (actor1 not in shared_actor_list):
2067
2068 shared_actor_list.append(actor1)
2069
2070 ##### Now make a list of copies of each entry of the above list
2071
2072 shared_actor_copy_list = []
2073 for actor in shared_actor_list:
2074 shared_actor_copy_list.append(copy(actor))
2075
2076 Room_List_Copy = []
2077
2078 for room in Room_List:
2079
2080 priority_queue_copy = []
2081
2082 for actor in room.priority_queue:
2083
2084 if actor not in shared_actor_list:
2085
2086 priority_queue_copy.append(copy(actor))
2087
2088 elif actor in shared_actor_list:
2089 append_count = 0
2090 for actor2 in shared_actor_copy_list:
2091
2092 # If all attributes of the actor and the copy are the same, then assume they are copies of each other
2093 if actor2.name == actor.name and actor2.Id == actor.Id and actor2.size == actor.size and actor2.category == actor.category and actor2.overlay_type == actor.overlay_type and actor2.unloadable == actor.unloadable and actor2.address == actor.address and actor2.room_number == actor.room_number and actor2.priority == actor.priority and actor2.from_spawner == actor.from_spawner and actor2.transition == actor.transition and actor2.clearable == actor.clearable and actor2.cleared == actor.cleared:
2094 # append the copy
2095 priority_queue_copy.append(actor2)
2096 append_count += 1
2097
2098 if append_count > 1:
2099 print("ERROR: There were two or more copies of the same Actor in shared_actor_copy_list (Copy_Room_List() error message)")
2100
2101
2102 room_copy = Room(number=room.number, priority_queue=priority_queue_copy, clock_exists=room.clock_exists, clock_priority=room.clock_priority)
2103
2104 Room_List_Copy.append(room_copy)
2105
2106 return Room_List_Copy
2107
2108
2109
2110
2111def Main_Actor_Attributes_Match(actor1, actor2):
2112
2113 """
2114
2115 This function returns True is the two Actors taken as input have the same
2116 values for all of their main attributes and False otherwise
2117
2118 the main attributes do not include things like "address" and such that can
2119 change as the state updates
2120
2121 """
2122
2123 main_actor_attributes_match = False
2124
2125 if actor1.name == actor2.name and actor1.Id == actor2.Id and actor1.size == actor2.size and actor1.category == actor2.category and actor1.overlay_type == actor2.overlay_type and actor1.unloadable == actor2.unloadable and actor1.room_number is actor2.room_number and actor1.priority is actor2.priority and actor1.from_spawner == actor2.from_spawner and actor1.transition == actor2.transition and actor1.clearable == actor2.clearable:
2126 main_actor_attributes_match = True
2127
2128 return main_actor_attributes_match
2129
2130
2131def Main_Overlay_Attributes_Match(overlay1, overlay2):
2132
2133 main_overlay_attributes_match = False
2134
2135 if overlay1.Id == overlay2.Id and overlay1.size == overlay2.size:
2136 main_overlay_attributes_match = True
2137
2138 return main_overlay_attributes_match
2139
2140
2141def Copy_Overlay_Dict(Overlay_Dict):
2142
2143 overlay_dict_copy = {}
2144
2145 for key in Overlay_Dict:
2146 overlay_dict_copy[key] = copy(Overlay_Dict[key])
2147
2148 return overlay_dict_copy
2149
2150
2151def Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy):
2152
2153 """
2154
2155 This function takes the Heap as input and returns a copy of the Heap where
2156 every actor copy in the Heap copy is the same class instance as each corresponding
2157 actor in the room list copy priority queues (same for Overlay_Dict_Copy)
2158
2159 """
2160
2161 Heap_Copy = []
2162
2163 for entry in Heap:
2164
2165 entry_allocated = False
2166 not_allocated_count = 0
2167 while entry_allocated is False:
2168
2169 if not_allocated_count > 4:
2170 print("UHHHHHHHHHHHHHHHHHHHHHHHH (Copy_Heap() Error Message)")
2171
2172 if type(entry) == Node:
2173
2174 Heap_Copy.append(copy(entry))
2175 entry_allocated = True
2176
2177 elif type(entry) == Overlay:
2178
2179 for key in Overlay_Dict_Copy:
2180 if Main_Overlay_Attributes_Match(Overlay_Dict_Copy[key], entry) == True:
2181 Heap_Copy.append(Overlay_Dict_Copy[key])
2182 entry_allocated = True
2183
2184 elif type(entry) == Actor:
2185
2186 allocated_count = 0
2187 for room in Room_List_Copy:
2188
2189 if entry_allocated == True:
2190 break
2191
2192 for actor in room.priority_queue:
2193
2194 if allocated_count > 1:
2195 print("ERROR: tried to allocate multiple copies (Copy_Heap() Error Message)")
2196
2197 if Main_Actor_Attributes_Match(entry, actor) == True:
2198 Heap_Copy.append(actor)
2199 allocated_count += 1
2200 entry_allocated = True
2201 break
2202
2203 # If it isn't in any of the priority queues, then it must be something you spawned
2204 if entry_allocated == False:
2205 Heap_Copy.append(copy(entry))
2206 entry_allocated = True
2207
2208 else:
2209 print("ERROR: entry in Heap is not an Actor, Node, or Overlay (Copy_Heap() error message)")
2210
2211 not_allocated_count += 1
2212 return Heap_Copy
2213
2214
2215def Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy):
2216
2217 """
2218
2219 This function takes the Grabbable_Dict as input and returns a copy of the it where
2220 each transition in it is a the same Actor class instance copy as the ones used in
2221 the priority queues of the Rooms in Room_List_Copy
2222
2223 """
2224
2225 grabbable_dict_copy = {}
2226
2227 for pot in Grabbable_Dict:
2228
2229 pot_in_dict = False
2230
2231
2232 for room in Room_List_Copy:
2233 if pot_in_dict == True:
2234 break
2235 for actor in room.priority_queue:
2236 if Main_Actor_Attributes_Match(pot, actor) == True:
2237
2238 key = actor
2239
2240 for room1 in Room_List_Copy:
2241 if pot_in_dict == True:
2242 break
2243 for actor1 in room1.priority_queue:
2244
2245 # Finding the transition
2246 if Main_Actor_Attributes_Match(Grabbable_Dict[pot][1], actor1):
2247
2248 grabbable_dict_copy[key] = [Grabbable_Dict[pot][0], actor1]
2249 pot_in_dict = True
2250
2251 return grabbable_dict_copy
2252
2253
2254def Find_Actor_Copy(actor, Room_List_Copy):
2255
2256 """
2257
2258 This function takes an Actor as input (actor) and a copy of the list of rooms
2259 (Room_List_Copy) and returns the copy of the inputted actor that is found in
2260 the priority queue of a Room in Room_List_Copy
2261
2262 """
2263
2264 actor_copy = None
2265
2266 copy_found = False
2267 for room in Room_List_Copy:
2268 if copy_found == True:
2269 break
2270 for actor1 in room.priority_queue:
2271 if Main_Actor_Attributes_Match(actor1, actor):
2272 actor_copy = actor1
2273 copy_found = True
2274 break
2275
2276 return actor_copy
2277
2278
2279"""
2280
2281TODO: Make the solver take the initial heap layout as input so that it is easy
2282to test successive heap manip setups in the future
2283
2284DO NOT FORGET TO CLEAR ALL OF THE BAD BATS IF YOU THINK THAT THAT IS SOMETHING
2285THAT YOU WANT TO DO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2286
2287ALSO IGNORE THAT FUNCTION BELOW, COMPLETELY REWRITE FROM SCRATCH BUT MAYBE READ
2288IT FIRST TO SEE IF IT REMINDS YOU OF ANY IDEAS YOU HAD
2289
2290"""
2291
2292
2293def Randomized_Solver(Initial_Room, Room_List, Max_Transition_Count, allocation_list, Grabbable_Dict, Overlay_Dict, filename, Offset_List, Initial_Heap):
2294
2295 """
2296
2297 This function does not currently account for the possibility that you might need to break
2298 another pot in order to superslide off of a given pot. While this might not be strictly
2299 true for the pot we currently use in deku palace, it would be good at add more information
2300 to Grabbable_Dict to account for this
2301
2302 """
2303
2304 """
2305
2306 Okay, the Initial_Heap argument will not work as I initially intended because of things
2307 like rupee clusters being cleared, etc. So if I want to test a Heap from an initial Heap
2308 distribution, then I will have to hardcode it to perform the necessary steps to get to it each time
2309
2310 """
2311
2312 """
2313
2314 filename is the complete name (i.e. including the path) that we want to write to
2315
2316 This function will randomly choose solutions to test (it may have repeats)
2317
2318 Offset_List is a list of offsets that we want to check for. The grabbable object (e.g. a pot)
2319 will be first when calculating the offset. So if doing chest SRM, we want
2320 pot - chest = 0x160 or pot - chest = 0x1F0, so we want Offset_List = [0x160, 0x1F0]
2321 We make this Offset_List by default
2322
2323 Grabbable_dict is a dictionary of the grabbable actors (such as pots) that
2324 we want to attempt to use for superslide SRM where the keys are the grabbable
2325 actors and the values are 3-bit strings where each bit means:
2326
2327 100 : Possible to enter Plane with both Bomb and Smoke loaded
2328 010 : Possible to enter Plane with Smoke loaded, but no Bomb loaded
2329 001 : Possible to enter Plane with no Smoke loaded
2330
2331 """
2332
2333 angle_solution_count = 0
2334 position_solution_count = 0
2335 permutation_count = 0
2336
2337 ### Keep doing this forever (infinite loop so we keep trying new permutations)
2338 while True:
2339
2340 all_room_load_lists = Generate_Almost_All_Room_Load_Permutations(Initial_Room, Room_List, Max_Transition_Count)
2341
2342 for room_load_list in all_room_load_lists:
2343
2344 if permutation_count%500 == 0:
2345 print("%d Permutations Tested %d Angle Solutions %d Position Solutions" %(permutation_count, angle_solution_count, position_solution_count))
2346 permutation_count += 1
2347
2348 Heap = copy(Initial_Heap)
2349
2350 ##### Initialize the actor addresses and other attributes each time
2351
2352 for room in Room_List:
2353
2354 for actor in room.priority_queue:
2355
2356 actor.address = 0
2357 actor.cleared = False
2358
2359 ##### Clear all bad bats (optional, but I want to do this for beneath the graveyard)
2360 Clear_Instances('015B', room)
2361 ###################################################################
2362
2363 #####
2364 ##### Perform seuqence of steps here if you want to initialize your heap to something
2365 #####
2366
2367 # We will use this to collect things we do in the permutation to help output the solution
2368 action_list = []
2369
2370 room_count = 0
2371 # NOTE: the first "transition" is actually not a transition; it is the initial room
2372 for transition in room_load_list[0:len(room_load_list)-1]:
2373
2374 room = Current_Room(room_load_list[0:room_count + 1], Room_List)
2375
2376 # If this is the Initial_Room AND the Heap is empty, then we want to load the scene
2377 if (room_count is 0) and (len(Heap) == 2):
2378
2379 if room != Initial_Room:
2380 print("ERROR: first entry in room_load_list is not Initial_Room (Randomnized_Solver() Error Message)")
2381
2382 Load_Scene(Heap, Initial_Room, Overlay_Dict)
2383 action_list.append("Load Scene: Room %d" %(Initial_Room.number))
2384
2385 else:
2386
2387 Load_Room(Heap, room, transition, Overlay_Dict)
2388
2389 action_list.append("Load Room: Room %d" %(room.number) + " with " + transition.name + " %d" %(transition.priority))
2390
2391 """
2392
2393 Now randomly (with some chosen distribution) choose things to allocate
2394 and/or things to deallocate (in your current room). Make it so that
2395 you can only choose a specific action once. For example, if allocation_list
2396 has ['bomb', 'bomb, 'bomb', 'fish'] in it, then make it so you can only use
2397 fish once, but you can use bomb 3 times
2398
2399 Somehow try to encode that hookshot/charged spin are mutually exclusive
2400 and that if either of them exist then they must be the last action
2401
2402 Allow yourself to deallocate things before allocating things even
2403 though it might be impossible or slow in some cases
2404
2405 """
2406
2407 # Do a coinflip to decide between allocating or deallocating first
2408 decision_coin_flip = np.random.uniform(0,1)
2409
2410 # With probability 1/2, we allocate first and deallocate second
2411 # if we allocate first, don't allow 'Charged Spin Attack'
2412 if decision_coin_flip > .5:
2413
2414 explosive_count = 0
2415 droppable_count = 0
2416
2417 ##### ALLOCATION
2418 for action in allocation_list:
2419
2420 # whether or not we add an action is based off of this
2421 coin_flip = decision_coin_flip = np.random.uniform(0,1)
2422
2423 if action == 'Smoke' and coin_flip > .5:
2424
2425 Allocate_Smoke(Heap, room.number, Overlay_Dict)
2426 action_list.append("Allocate: Smoke")
2427
2428 elif action == 'Chu' and coin_flip > .5 and explosive_count < 3:
2429
2430 Allocate_Chu(Heap, room.number, Overlay_Dict)
2431 action_list.append("Allocate: Chu")
2432 explosive_count += 1
2433
2434 elif action == 'Arrow' and coin_flip > .5:
2435
2436 Allocate_Arrow(Heap, room.number, Overlay_Dict)
2437 action_list.append("Allocate: Arrow")
2438
2439 elif action == 'Bomb' and coin_flip > .5 and explosive_count < 3:
2440
2441 Allocate_Bomb(Heap, room.number, Overlay_Dict)
2442 action_list.append("Allocate: Bomb")
2443 explosive_count += 1
2444
2445 elif action == 'Zora Fins' and coin_flip > .5:
2446
2447 Allocate_Zora_Fins(Heap, room.number, Overlay_Dict)
2448 action_list.append("Allocate: Zora Fins")
2449
2450 elif action == 'Fish' and coin_flip > .5 and droppable_count < 2:
2451
2452 Allocate_Fish(Heap, room.number, Overlay_Dict)
2453 action_list.append("Allocate: Fish")
2454 droppable_count += 1
2455
2456 elif action == 'Bugs' and coin_flip > .5 and droppable_count < 2:
2457
2458 Allocate_Bugs(Heap, room.number, Overlay_Dict)
2459 action_list.append("Allocate: Bugs")
2460 droppable_count += 1
2461
2462 elif action == 'Hookshot' and coin_flip > .5:
2463
2464 Allocate_Hookshot(Heap, room.number, Overlay_Dict)
2465 action_list.append("Allocate: Hookshot")
2466
2467 ### We don't include 'Charged Spin Attack' in this
2468
2469 ##### DEALLOCATION
2470 for actor in room.priority_queue:
2471
2472 # whether or not we deallocate an actor is based off of this
2473 coin_flip = decision_coin_flip = np.random.uniform(0,1)
2474
2475 if actor.unloadable == True and Actor_Is_In_Heap(Heap, actor) == True and coin_flip > .5:
2476
2477
2478 if actor.Id == '00E8' or actor.name == 'Collectible (Rupee from Rupee Cluster)':
2479
2480 Deallocate(Heap, actor, Overlay_Dict)
2481 # There is at most one rupee cluster per room, so this is fine to clear it
2482 Clear_Instances('00E8', room)
2483 action_list.append("Deallocate: " + actor.name + " (Priority %d)" %(actor.priority))
2484
2485 # THESE PRIORITIES ARE HARDCODED FOR ROOM 3 OF OCEANSIDE!!!!!!!
2486 elif actor.Id == '01E7' and (actor.priority == 0 or actor.priority == 1 or actor.priority == 2):
2487
2488 table_bonk_deallocation_count = 0
2489 for entry in Heap:
2490 if type(entry) == Actor and entry.Id == '01E7' and entry.priority == 0:
2491 Deallocate(Heap, entry, Overlay_Dict)
2492 table_bonk_deallocation_count += 1
2493
2494 for entry in Heap:
2495 if type(entry) == Actor and entry.Id == '01E7' and entry.priority == 1:
2496 Deallocate(Heap, entry, Overlay_Dict)
2497 table_bonk_deallocation_count += 1
2498
2499 for entry in Heap:
2500 if type(entry) == Actor and entry.Id == '01E7' and entry.priority == 2:
2501 Deallocate(Heap, entry, Overlay_Dict)
2502 table_bonk_deallocation_count += 1
2503
2504 if table_bonk_deallocation_count != 3:
2505 print("ERROR: table_bonk_deallocation_count is not 3 (Randomized_Solver() error)")
2506
2507 action_list.append("Deallocate: " + actor.name + " (Priority 0, 1, and 2) [Bonk Oceanside Table]")
2508
2509
2510 # if the actor is clearable AND isn't a bad bat, then clear it when deallocating it if it isn't already cleared
2511 elif actor.clearable == True and actor.cleared == False and actor.Id != '015B':
2512
2513 Deallocate(Heap, actor, Overlay_Dict)
2514 action_list.append("Deallocate: " + actor.name + " (Priority %d)" %(actor.priority))
2515 # CLEAR THE ACTOR
2516 Clear_Instance(actor, room)
2517
2518 else:
2519
2520 Deallocate(Heap, actor, Overlay_Dict)
2521 action_list.append("Deallocate: " + actor.name + " (Priority %d)" %(actor.priority))
2522
2523
2524 # With probability 1/2, we deallocate first and allocate second
2525 elif decision_coin_flip <= .5:
2526
2527 explosive_count = 0
2528 droppable_count = 0
2529 hookshot_exists = False
2530
2531 ##### DEALLOCATION
2532 for actor in room.priority_queue:
2533
2534 # whether or not we deallocate an actor is based off of this
2535 coin_flip = decision_coin_flip = np.random.uniform(0,1)
2536
2537 if actor.unloadable == True and Actor_Is_In_Heap(Heap, actor) == True and coin_flip > .5:
2538
2539
2540 if actor.Id == '00E8' or actor.name == 'Collectible (Rupee from Rupee Cluster)':
2541
2542 Deallocate(Heap, actor, Overlay_Dict)
2543 # There is at most one rupee cluster per room, so this is fine to clear it
2544 Clear_Instances('00E8', room)
2545 action_list.append("Deallocate: " + actor.name + " (Priority %d)" %(actor.priority))
2546
2547 # THESE PRIORITIES ARE HARDCODED FOR ROOM 3 OF OCEANSIDE!!!!!!!
2548 elif actor.Id == '01E7' and (actor.priority == 0 or actor.priority == 1 or actor.priority == 2):
2549
2550 table_bonk_deallocation_count = 0
2551 for entry in Heap:
2552 if type(entry) == Actor and entry.Id == '01E7' and entry.priority == 0:
2553 Deallocate(Heap, entry, Overlay_Dict)
2554 table_bonk_deallocation_count += 1
2555
2556 for entry in Heap:
2557 if type(entry) == Actor and entry.Id == '01E7' and entry.priority == 1:
2558 Deallocate(Heap, entry, Overlay_Dict)
2559 table_bonk_deallocation_count += 1
2560
2561 for entry in Heap:
2562 if type(entry) == Actor and entry.Id == '01E7' and entry.priority == 2:
2563 Deallocate(Heap, entry, Overlay_Dict)
2564 table_bonk_deallocation_count += 1
2565
2566 if table_bonk_deallocation_count != 3:
2567 print("ERROR: table_bonk_deallocation_count is not 3 (Randomized_Solver() error)")
2568
2569 action_list.append("Deallocate: " + actor.name + " (Priority 0, 1, and 2) [Bonk Oceanside Table]")
2570
2571
2572 # if the actor is clearable AND isn't a bad bat, then clear it when deallocating it if it isn't already cleared
2573 elif actor.clearable == True and actor.cleared == False and actor.Id != '015B':
2574
2575 Deallocate(Heap, actor, Overlay_Dict)
2576 action_list.append("Deallocate: " + actor.name + " (Priority %d)" %(actor.priority))
2577 # CLEAR THE ACTOR
2578 Clear_Instance(actor, room)
2579
2580 else:
2581
2582 Deallocate(Heap, actor, Overlay_Dict)
2583 action_list.append("Deallocate: " + actor.name + " (Priority %d)" %(actor.priority))
2584
2585
2586 ##### ALLOCATION
2587 for action in allocation_list:
2588
2589 # whether or not we add an action is based off of this
2590 coin_flip = decision_coin_flip = np.random.uniform(0,1)
2591
2592 if action == 'Smoke' and coin_flip > .5:
2593
2594 Allocate_Smoke(Heap, room.number, Overlay_Dict)
2595 action_list.append("Allocate: Smoke")
2596
2597 elif action == 'Chu' and coin_flip > .5 and explosive_count < 3:
2598
2599 Allocate_Chu(Heap, room.number, Overlay_Dict)
2600 action_list.append("Allocate: Chu")
2601 explosive_count += 1
2602
2603 elif action == 'Arrow' and coin_flip > .5:
2604
2605 Allocate_Arrow(Heap, room.number, Overlay_Dict)
2606 action_list.append("Allocate: Arrow")
2607
2608 elif action == 'Bomb' and coin_flip > .5 and explosive_count < 3:
2609
2610 Allocate_Bomb(Heap, room.number, Overlay_Dict)
2611 action_list.append("Allocate: Bomb")
2612 explosive_count += 1
2613
2614 elif action == 'Zora Fins' and coin_flip > .5:
2615
2616 Allocate_Zora_Fins(Heap, room.number, Overlay_Dict)
2617 action_list.append("Allocate: Zora Fins")
2618
2619 elif action == 'Fish' and coin_flip > .5 and droppable_count < 2:
2620
2621 Allocate_Fish(Heap, room.number, Overlay_Dict)
2622 action_list.append("Allocate: Fish")
2623 droppable_count += 1
2624
2625 elif action == 'Bugs' and coin_flip > .5 and droppable_count < 2:
2626
2627 Allocate_Bugs(Heap, room.number, Overlay_Dict)
2628 action_list.append("Allocate: Bugs")
2629 droppable_count += 1
2630
2631 elif action == 'Hookshot' and coin_flip > .5:
2632
2633 Allocate_Hookshot(Heap, room.number, Overlay_Dict)
2634 action_list.append("Allocate: Hookshot")
2635 hookshot_exists = True
2636
2637 elif action == 'Charged Spin Attack' and hookshot_exists is False:
2638
2639 Allocate_Charged_Spin_Attack(Heap, room.number, Overlay_Dict)
2640 action_list.append("Allocate: Charged Spin Attack")
2641
2642
2643 room_count += 1
2644
2645 ##### Now we load the last room in room_order_list
2646 current_room = Current_Room(room_load_list, Room_List)
2647 most_recent_transition = room_load_list[-1]
2648 Load_Room(Heap, current_room, most_recent_transition, Overlay_Dict)
2649
2650 action_list.append("Load Room: Room %d" %(current_room.number) + " with " + most_recent_transition.name + " %d" %(most_recent_transition.priority))
2651
2652
2653 """
2654
2655 Now that we have iterated through all of the rooms, we want to check to see
2656 if we are in a room with a valid grabbale object. If so, then store the addresses
2657 of all of them and make a copy of the current Heap state. From here, we want to try
2658 every possibility in the sense that we want to check every valid grabbable object
2659 in every room that we can get to and also check every superslide case that is possible
2660 (based on the binary number associated with each valid grabbable object) and then
2661 check if either the Angle or Position (input this into the function via Offset_List)
2662 line up with the chest or deku guard
2663
2664 There aren't too many possibilities from here in practice, so we might as well check them all
2665
2666 Also encode that if we superslide into a room with a chest/deku guard, then we must
2667 exit the room and then reenter it (or enter another room with a chest/deku guard; we will
2668 test every case) and after doing that we will check the chest/deku guard addresses
2669 and see if any of them line up with any of the pots that we stored the addresses of
2670
2671 We'll eventually want to write stuff to a text file, so maybe set file as an input argument
2672 or just hardcode it, not sure
2673
2674 """
2675
2676 """
2677
2678 WE MAKE THE ASSUMPTION THAT YOU LAND IN A ROOM THAT EITHER IS A ROOM
2679 WITH A CHEST/DEKU GUARD OR A ROOM THAT NEIGHBORS A ROOM WITH A CHEST/DEKU GUARD
2680 BECAUSE I CANNOT THINK OF ANY PLACES WHERE THIS WOULDN'T HAPPEN WHEN TESTING
2681 SUPERSLIDE SRM (ZORA FIN WOULD BE DIFFERENT, BUT THIS SOLVER DOESN'T TEST IT)
2682
2683 Also, before supersliding, we assume that you're in a room that either has
2684 a valid grabbable object, or is next to a room with a valid grabbable object.
2685 Of course, this means fewer possibilities are being tested in a place like
2686 oceanside, but there are already so many possibilities to test to begin with that
2687 this probably isn't a big deal for now. This also affects deku palace, but maybe
2688 I'll change this by the time I work on deku palace (because if you end in Room2,
2689 then nothing happens)
2690
2691 """
2692
2693 """
2694
2695 Nevermind some of those other comments, here is what I'm really assuming.
2696
2697 I will be assuming that if you end in a room without a valid grabbable
2698 actor, then it will search all neighbors of that room for valid grabbable
2699 actors and if none of those have valid grabbable objects then it will
2700 search all of those neighbors and choose the first one it finds (this
2701 will allow for ending in Room 2 in Deku Palace). Otherwise it does nothing
2702 (though this will never happen for the cases I plan on checking for now)
2703
2704 (*Coded)If you are in a room with a valid grabbable actor and no chest/deku guard,
2705 then we will check the addresses of all valid grabbable actors in this room
2706 and superslide into the chest room, exit and reenter it. Then we will check the address of the
2707 chest and see if it lines up with any of the pot addresses from the previous
2708 room.
2709
2710 (*Coded)If you are in a room with a valid grabbable actor AND a chest/deku guard, then
2711 you will record the valid grabbable actor addresses then superslide to exit the
2712 room and then check all neighbors of the room you enter for having a chest/deku guard
2713 and test all of them
2714
2715
2716
2717 """
2718
2719 valid_grabbable_actor_room_list = []
2720
2721 for room in Room_List:
2722 if Valid_Grabbable_In_Room(room, Grabbable_Dict) is True:
2723 valid_grabbable_actor_room_list.append(room)
2724
2725 # This gives a list of all ways we can exit our current room
2726 #transition_list_possibilities = Generate_Room_Load_Permutations(current_room, Room_List, 1)
2727
2728 ##### Case 1: there is a valid grabbable actor in the current room, but no chest/deku guard (the guard thing doesn't matter because this never happens in palace anyway)
2729 if (current_room in valid_grabbable_actor_room_list) and (Chest_In_Room(current_room) is False) and (Deku_Guard_In_Room(current_room) is False):
2730
2731 valid_pot_list = []
2732 pot_address_list = []
2733
2734 for pot in Grabbable_Dict:
2735
2736 if Actor_Is_In_Room(current_room, pot) is True:
2737 valid_pot_list.append(pot)
2738 pot_address_list.append(pot.address)
2739
2740 """
2741
2742 Now for each pot in valid_pot_list, we want to test every applicable
2743 superslide scenario
2744
2745 Before each one, we need to copy the current state and then modify the copies
2746 to check for the solution
2747
2748 """
2749
2750 for pot in valid_pot_list:
2751
2752 # both bomb and smoke loaded on superslide
2753 if Grabbable_Dict[pot][0][0] == '1':
2754
2755 action_list100 = []
2756
2757 # COPY STATE
2758 #######################################################
2759 Room_List_Copy = Copy_Room_List(Room_List)
2760 Overlay_Dict_Copy = Copy_Overlay_Dict(Overlay_Dict)
2761
2762 room_copy_dict = {}
2763 for room in Room_List_Copy:
2764 room_copy_dict[room.number] = room
2765
2766 Heap_Copy = Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy)
2767
2768 Grabbable_Dict_Copy = Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy)
2769 #######################################################
2770
2771 Bomb_And_Smoke_Superslide(Heap_Copy, current_room.number, Overlay_Dict_Copy)
2772 action_list100.append("Superslide with Bomb and Smoke still allocated")
2773
2774 # The room we superslide into through the plane corresponding to the given pot
2775 destination_room = Current_Room([current_room, Grabbable_Dict[pot][1]], Room_List)
2776
2777 destination_room_copy = room_copy_dict[destination_room.number]
2778 current_room_copy = room_copy_dict[current_room.number]
2779
2780 pot_copy = Find_Actor_Copy(pot, Room_List_Copy)
2781 superslide_transition_copy = Grabbable_Dict_Copy[pot_copy][1]
2782
2783 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2784 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2785
2786 # Now exit the chest room
2787 Load_Room(Heap_Copy, current_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2788 action_list100.append("Load Room: Room %d" %(current_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2789
2790 # Now reenter the chest room
2791 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2792 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2793
2794 ##### Now check for chests/deku guards
2795
2796 chest_guard_list = []
2797
2798 for entry in Heap_Copy:
2799
2800 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
2801 chest_guard_list.append(entry)
2802
2803 soln_found = False
2804 for entry in chest_guard_list:
2805 if (pot.address - entry.address) in Offset_List:
2806
2807 action_list100.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
2808
2809 if (pot.address - entry.address) == 0x160:
2810 angle_solution_count += 1
2811 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
2812 elif (pot.address - entry.address) == 0x1F0:
2813 position_solution_count += 1
2814 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
2815
2816 soln_found = True
2817
2818 if soln_found is True:
2819 total_action_list = action_list + action_list100
2820
2821 # the "a" argument is important so we don't overwrite previous solutions
2822 with open(filename, "a") as file:
2823
2824 for action in total_action_list:
2825
2826 file.write(action + "\n")
2827 file.write("-----\n")
2828
2829
2830 ##### Only smoke is loaded from superslide
2831 elif Grabbable_Dict[pot][0][1] == '1':
2832
2833 action_list010 = []
2834
2835 # COPY STATE
2836 #######################################################
2837 Room_List_Copy = Copy_Room_List(Room_List)
2838 Overlay_Dict_Copy = Copy_Overlay_Dict(Overlay_Dict)
2839
2840 room_copy_dict = {}
2841 for room in Room_List_Copy:
2842 room_copy_dict[room.number] = room
2843
2844 Heap_Copy = Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy)
2845
2846 Grabbable_Dict_Copy = Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy)
2847 #######################################################
2848
2849 Allocate_Smoke(Heap_Copy, current_room.number, Overlay_Dict_Copy)
2850 action_list010.append("Superslide with Smoke still allocated")
2851
2852 # The room we superslide into through the plane corresponding to the given pot
2853 destination_room = Current_Room([current_room, Grabbable_Dict[pot][1]], Room_List)
2854
2855 destination_room_copy = room_copy_dict[destination_room.number]
2856 current_room_copy = room_copy_dict[current_room.number]
2857
2858 pot_copy = Find_Actor_Copy(pot, Room_List_Copy)
2859 superslide_transition_copy = Grabbable_Dict_Copy[pot_copy][1]
2860
2861 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2862 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2863
2864 # Now exit the chest room
2865 Load_Room(Heap_Copy, current_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2866 action_list010.append("Load Room: Room %d" %(current_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2867
2868 # Now reenter the chest room
2869 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2870 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2871
2872
2873 ##### Now check for chests/deku guards
2874
2875 chest_guard_list = []
2876
2877 for entry in Heap_Copy:
2878
2879 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
2880 chest_guard_list.append(entry)
2881
2882 soln_found = False
2883 for entry in chest_guard_list:
2884 if (pot.address - entry.address) in Offset_List:
2885
2886 action_list010.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
2887
2888 if (pot.address - entry.address) == 0x160:
2889 angle_solution_count += 1
2890 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
2891 elif (pot.address - entry.address) == 0x1F0:
2892 position_solution_count += 1
2893 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
2894
2895 soln_found = True
2896
2897 if soln_found is True:
2898 total_action_list = action_list + action_list010
2899
2900 # the "a" argument is important so we don't overwrite previous solutions
2901 with open(filename, "a") as file:
2902
2903 for action in total_action_list:
2904
2905 file.write(action + "\n")
2906 file.write("-----\n")
2907
2908
2909 #### Bomb and Smoke are both unloaded
2910 elif Grabbable_Dict[pot][0][2] == '1':
2911
2912 action_list001 = []
2913
2914 # COPY STATE
2915 #######################################################
2916 Room_List_Copy = Copy_Room_List(Room_List)
2917 Overlay_Dict_Copy = Copy_Overlay_Dict(Overlay_Dict)
2918
2919 room_copy_dict = {}
2920 for room in Room_List_Copy:
2921 room_copy_dict[room.number] = room
2922
2923 Heap_Copy = Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy)
2924
2925 Grabbable_Dict_Copy = Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy)
2926 #######################################################
2927
2928 # Do not allocate anything
2929 action_list001.append("Superslide with Bomb and Smoke unloaded when passing plane")
2930
2931 # The room we superslide into through the plane corresponding to the given pot
2932 destination_room = Current_Room([current_room, Grabbable_Dict[pot][1]], Room_List)
2933
2934 destination_room_copy = room_copy_dict[destination_room.number]
2935 current_room_copy = room_copy_dict[current_room.number]
2936
2937 pot_copy = Find_Actor_Copy(pot, Room_List_Copy)
2938 superslide_transition_copy = Grabbable_Dict_Copy[pot_copy][1]
2939
2940 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2941 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2942
2943 # Now exit the chest room
2944 Load_Room(Heap_Copy, current_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2945 action_list001.append("Load Room: Room %d" %(current_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2946
2947 # Now reenter the chest room
2948 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
2949 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
2950
2951
2952 ##### Now check for chests/deku guards
2953
2954 chest_guard_list = []
2955
2956 for entry in Heap_Copy:
2957
2958 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
2959 chest_guard_list.append(entry)
2960
2961 soln_found = False
2962 for entry in chest_guard_list:
2963 if (pot.address - entry.address) in Offset_List:
2964
2965 action_list001.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
2966
2967 if (pot.address - entry.address) == 0x160:
2968 angle_solution_count += 1
2969 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
2970 elif (pot.address - entry.address) == 0x1F0:
2971 position_solution_count += 1
2972 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
2973
2974 soln_found = True
2975
2976 if soln_found is True:
2977 total_action_list = action_list + action_list001
2978
2979 # the "a" argument is important so we don't overwrite previous solutions
2980 with open(filename, "a") as file:
2981
2982 for action in total_action_list:
2983
2984 file.write(action + "\n")
2985 file.write("-----\n")
2986
2987
2988
2989 # Case 2: there is a valid grabbable actor in the current room AND there is a chest or deku guard
2990 elif (current_room in valid_grabbable_actor_room_list) and ((Chest_In_Room(current_room) is True) or (Deku_Guard_In_Room(current_room) is True)):
2991
2992 valid_pot_list = []
2993 pot_address_list = []
2994
2995 for pot in Grabbable_Dict:
2996
2997 if Actor_Is_In_Room(current_room, pot) is True:
2998 valid_pot_list.append(pot)
2999 pot_address_list.append(pot.address)
3000
3001
3002 """
3003
3004 Now for each pot in valid_pot_list, we want to test every applicable
3005 superslide scenario
3006
3007 Before each one, we need to copy the current state and then modify the copies
3008 to check for the solution
3009
3010 Also, for every case, we need to consider every possible room that contains
3011 a chest/deku guard that neighbors the room we just entered (meaning you
3012 will need to make copies of the copies of the state)
3013
3014 """
3015
3016 for pot in valid_pot_list:
3017
3018 # both bomb and smoke loaded on superslide
3019 if Grabbable_Dict[pot][0][0] == '1':
3020
3021 action_list100 = []
3022
3023 # COPY STATE
3024 #######################################################
3025 Room_List_Copy = Copy_Room_List(Room_List)
3026 Overlay_Dict_Copy = Copy_Overlay_Dict(Overlay_Dict)
3027
3028 room_copy_dict = {}
3029 for room in Room_List_Copy:
3030 room_copy_dict[room.number] = room
3031
3032 Heap_Copy = Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy)
3033
3034 Grabbable_Dict_Copy = Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy)
3035 #######################################################
3036
3037 Bomb_And_Smoke_Superslide(Heap_Copy, current_room.number, Overlay_Dict_Copy)
3038 action_list100.append("Superslide with Bomb and Smoke still allocated")
3039
3040 # The room we superslide into through the plane corresponding to the given pot
3041 destination_room = Current_Room([current_room, Grabbable_Dict[pot][1]], Room_List)
3042
3043 destination_room_copy = room_copy_dict[destination_room.number]
3044
3045 pot_copy = Find_Actor_Copy(pot, Room_List_Copy)
3046 superslide_transition_copy = Grabbable_Dict_Copy[pot_copy][1]
3047
3048 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
3049 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3050
3051 """
3052
3053 Now we check all neighbors of our current room (destination_room) and for
3054 each neighbor that has a chest or deku guard in it, we will create a copy
3055 of our copy of the state, then enter each of them through each possible
3056 loading plane and then check the chest/guard addresses and see if anything
3057 lines up
3058
3059 """
3060
3061 for neighbor in Neighbors(destination_room, Room_List):
3062
3063 if Chest_In_Room(neighbor) == True or Deku_Guard_In_Room(neighbor) == True:
3064
3065 for transition in Shared_Transitions(destination_room, neighbor):
3066
3067 # COPY STATE
3068 #######################################################
3069 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
3070 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
3071
3072 room_copy_dict_2 = {}
3073 for room in Room_List_Copy_2:
3074 room_copy_dict_2[room.number] = room
3075
3076 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
3077
3078 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
3079 #######################################################
3080
3081 action_list_2 = []
3082
3083 transition_copy = Find_Actor_Copy(transition, Room_List_Copy_2)
3084
3085 neighbor_copy = room_copy_dict_2[neighbor.number]
3086
3087 Load_Room(Heap_Copy_2, neighbor_copy, transition_copy, Overlay_Dict_Copy_2)
3088 action_list_2.append("Load Room: Room %d" %(neighbor_copy.number) + " with " + transition_copy.name + " %d" %(transition_copy.priority))
3089
3090
3091 ##### Now check for chests/deku guards
3092
3093 chest_guard_list = []
3094
3095 for entry in Heap_Copy_2:
3096
3097 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3098 chest_guard_list.append(entry)
3099
3100 soln_found = False
3101 for entry in chest_guard_list:
3102 if (pot.address - entry.address) in Offset_List:
3103
3104 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3105
3106 if (pot.address - entry.address) == 0x160:
3107 angle_solution_count += 1
3108 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3109 elif (pot.address - entry.address) == 0x1F0:
3110 position_solution_count += 1
3111 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3112
3113 soln_found = True
3114
3115 if soln_found is True:
3116 total_action_list = action_list + action_list100 + action_list_2
3117
3118 # the "a" argument is important so we don't overwrite previous solutions
3119 with open(filename, "a") as file:
3120
3121 for action in total_action_list:
3122
3123 file.write(action + "\n")
3124 file.write("-----\n")
3125
3126
3127 ##### Only smoke is loaded from superslide
3128 elif Grabbable_Dict[pot][0][1] == '1':
3129
3130 action_list010 = []
3131
3132 # COPY STATE
3133 #######################################################
3134 Room_List_Copy = Copy_Room_List(Room_List)
3135 Overlay_Dict_Copy = Copy_Overlay_Dict(Overlay_Dict)
3136
3137 room_copy_dict = {}
3138 for room in Room_List_Copy:
3139 room_copy_dict[room.number] = room
3140
3141 Heap_Copy = Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy)
3142
3143 Grabbable_Dict_Copy = Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy)
3144 #######################################################
3145
3146 Allocate_Smoke(Heap_Copy, current_room.number, Overlay_Dict_Copy)
3147 action_list010.append("Superslide with Smoke still allocated")
3148
3149 # The room we superslide into through the plane corresponding to the given pot
3150 destination_room = Current_Room([current_room, Grabbable_Dict[pot][1]], Room_List)
3151
3152 destination_room_copy = room_copy_dict[destination_room.number]
3153
3154 pot_copy = Find_Actor_Copy(pot, Room_List_Copy)
3155 superslide_transition_copy = Grabbable_Dict_Copy[pot_copy][1]
3156
3157 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
3158 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3159
3160 """
3161
3162 Now we check all neighbors of our current room (destination_room) and for
3163 each neighbor that has a chest or deku guard in it, we will create a copy
3164 of our copy of the state, then enter each of them through each possible
3165 loading plane and then check the chest/guard addresses and see if anything
3166 lines up
3167
3168 """
3169
3170 for neighbor in Neighbors(destination_room, Room_List):
3171
3172 if Chest_In_Room(neighbor) == True or Deku_Guard_In_Room(neighbor) == True:
3173
3174 for transition in Shared_Transitions(destination_room, neighbor):
3175
3176 # COPY STATE
3177 #######################################################
3178 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
3179 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
3180
3181 room_copy_dict_2 = {}
3182 for room in Room_List_Copy_2:
3183 room_copy_dict_2[room.number] = room
3184
3185 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
3186
3187 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
3188 #######################################################
3189
3190 action_list_2 = []
3191
3192 transition_copy = Find_Actor_Copy(transition, Room_List_Copy_2)
3193
3194 neighbor_copy = room_copy_dict_2[neighbor.number]
3195
3196 Load_Room(Heap_Copy_2, neighbor_copy, transition_copy, Overlay_Dict_Copy_2)
3197 action_list_2.append("Load Room: Room %d" %(neighbor_copy.number) + " with " + transition_copy.name + " %d" %(transition_copy.priority))
3198
3199
3200 ##### Now check for chests/deku guards
3201
3202 chest_guard_list = []
3203
3204 for entry in Heap_Copy_2:
3205
3206 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3207 chest_guard_list.append(entry)
3208
3209 soln_found = False
3210 for entry in chest_guard_list:
3211 if (pot.address - entry.address) in Offset_List:
3212
3213 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3214
3215 if (pot.address - entry.address) == 0x160:
3216 angle_solution_count += 1
3217 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3218 elif (pot.address - entry.address) == 0x1F0:
3219 position_solution_count += 1
3220 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3221
3222 soln_found = True
3223
3224 if soln_found is True:
3225 total_action_list = action_list + action_list010 + action_list_2
3226
3227 # the "a" argument is important so we don't overwrite previous solutions
3228 with open(filename, "a") as file:
3229
3230 for action in total_action_list:
3231
3232 file.write(action + "\n")
3233 file.write("-----\n")
3234
3235
3236 #### Bomb and Smoke are both unloaded
3237 elif Grabbable_Dict[pot][0][2] == '1':
3238
3239 action_list001 = []
3240
3241 # COPY STATE
3242 #######################################################
3243 Room_List_Copy = Copy_Room_List(Room_List)
3244 Overlay_Dict_Copy = Copy_Overlay_Dict(Overlay_Dict)
3245
3246 room_copy_dict = {}
3247 for room in Room_List_Copy:
3248 room_copy_dict[room.number] = room
3249
3250 Heap_Copy = Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy)
3251
3252 Grabbable_Dict_Copy = Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy)
3253 #######################################################
3254
3255 # Do not allocate anything
3256 action_list001.append("Superslide with Bomb and Smoke unloaded when passing plane")
3257
3258 # The room we superslide into through the plane corresponding to the given pot
3259 destination_room = Current_Room([current_room, Grabbable_Dict[pot][1]], Room_List)
3260
3261 destination_room_copy = room_copy_dict[destination_room.number]
3262
3263 pot_copy = Find_Actor_Copy(pot, Room_List_Copy)
3264 superslide_transition_copy = Grabbable_Dict_Copy[pot_copy][1]
3265
3266 Load_Room(Heap_Copy, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy)
3267 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3268
3269 """
3270
3271 Now we check all neighbors of our current room (destination_room) and for
3272 each neighbor that has a chest or deku guard in it, we will create a copy
3273 of our copy of the state, then enter each of them through each possible
3274 loading plane and then check the chest/guard addresses and see if anything
3275 lines up
3276
3277 """
3278
3279 for neighbor in Neighbors(destination_room, Room_List):
3280
3281 if Chest_In_Room(neighbor) == True or Deku_Guard_In_Room(neighbor) == True:
3282
3283 for transition in Shared_Transitions(destination_room, neighbor):
3284
3285 # COPY STATE
3286 #######################################################
3287 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
3288 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
3289
3290 room_copy_dict_2 = {}
3291 for room in Room_List_Copy_2:
3292 room_copy_dict_2[room.number] = room
3293
3294 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
3295
3296 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
3297 #######################################################
3298
3299 action_list_2 = []
3300
3301 transition_copy = Find_Actor_Copy(transition, Room_List_Copy_2)
3302
3303 neighbor_copy = room_copy_dict_2[neighbor.number]
3304
3305 Load_Room(Heap_Copy_2, neighbor_copy, transition_copy, Overlay_Dict_Copy_2)
3306 action_list_2.append("Load Room: Room %d" %(neighbor_copy.number) + " with " + transition_copy.name + " %d" %(transition_copy.priority))
3307
3308
3309 ##### Now check for chests/deku guards
3310
3311 chest_guard_list = []
3312
3313 for entry in Heap_Copy_2:
3314
3315 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3316 chest_guard_list.append(entry)
3317
3318 soln_found = False
3319 for entry in chest_guard_list:
3320 if (pot.address - entry.address) in Offset_List:
3321
3322 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3323
3324 if (pot.address - entry.address) == 0x160:
3325 angle_solution_count += 1
3326 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3327 elif (pot.address - entry.address) == 0x1F0:
3328 position_solution_count += 1
3329 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3330
3331 soln_found = True
3332
3333 if soln_found is True:
3334 total_action_list = action_list + action_list001 + action_list_2
3335
3336 # the "a" argument is important so we don't overwrite previous solutions
3337 with open(filename, "a") as file:
3338
3339 for action in total_action_list:
3340
3341 file.write(action + "\n")
3342 file.write("-----\n")
3343
3344
3345 ##### Case 3: there is NOT a valid grabbable actor in the current room
3346 elif (current_room not in valid_grabbable_actor_room_list):
3347
3348 for neighbor in Neighbors(current_room, Room_List):
3349
3350 ##### Valid grabbable actor in neighbor
3351 if neighbor in valid_grabbable_actor_room_list:
3352
3353
3354 ##### Iterate through all pots in this room
3355
3356 valid_pot_list = []
3357 pot_address_list = []
3358
3359 for pot in Grabbable_Dict:
3360
3361 if Actor_Is_In_Room(neighbor, pot) is True:
3362 valid_pot_list.append(pot)
3363 pot_address_list.append(pot.address)
3364
3365 # For every transition in Shared_Transitions(current_room, neighbor)
3366 for transition in Shared_Transitions(current_room, neighbor):
3367
3368 action_list_transition = []
3369
3370 ##### COPY THE STATE
3371 #######################################################
3372 Room_List_Copy = Copy_Room_List(Room_List)
3373 Overlay_Dict_Copy = Copy_Overlay_Dict(Overlay_Dict)
3374
3375 room_copy_dict = {}
3376 for room in Room_List_Copy:
3377 room_copy_dict[room.number] = room
3378
3379 Heap_Copy = Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy)
3380
3381 Grabbable_Dict_Copy = Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy)
3382 #######################################################
3383
3384 ##### ENTER neighbor after copying it
3385
3386 neighbor_copy = room_copy_dict[neighbor.number]
3387 transition_copy = Find_Actor_Copy(transition, Room_List_Copy)
3388
3389 Load_Room(Heap_Copy, neighbor_copy, transition_copy, Overlay_Dict_Copy)
3390 action_list_transition.append("Load Room: Room %d" %(neighbor_copy.number) + " with " + transition_copy.name + " %d" %(transition_copy.priority))
3391
3392
3393 # If there is a chest/guard, superslide, then check neighbors for chests/guards and test all (copy state)
3394 if Chest_In_Room(neighbor) == True or Deku_Guard_In_Room(neighbor) == True:
3395
3396 for pot in valid_pot_list:
3397
3398 # both bomb and smoke loaded on superslide
3399 if Grabbable_Dict[pot][0][0] == '1':
3400
3401 action_list100 = []
3402
3403 # COPY STATE
3404 #######################################################
3405 Room_List_Copy_SS = Copy_Room_List(Room_List_Copy)
3406 Overlay_Dict_Copy_SS = Copy_Overlay_Dict(Overlay_Dict_Copy)
3407
3408 room_copy_dict_SS = {}
3409 for room in Room_List_Copy_SS:
3410 room_copy_dict_SS[room.number] = room
3411
3412 Heap_Copy_SS = Copy_Heap(Heap_Copy, Room_List_Copy_SS, Overlay_Dict_Copy_SS)
3413
3414 Grabbable_Dict_Copy_SS = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_SS)
3415 #######################################################
3416
3417 Bomb_And_Smoke_Superslide(Heap_Copy_SS, neighbor.number, Overlay_Dict_Copy_SS)
3418 action_list100.append("Superslide with Bomb and Smoke still allocated")
3419
3420 # The room we superslide into through the plane corresponding to the given pot
3421 destination_room = Current_Room([neighbor, Grabbable_Dict[pot][1]], Room_List)
3422
3423 destination_room_copy = room_copy_dict_SS[destination_room.number]
3424
3425 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_SS)
3426 superslide_transition_copy = Grabbable_Dict_Copy_SS[pot_copy][1]
3427
3428 Load_Room(Heap_Copy_SS, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_SS)
3429 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3430
3431 """
3432
3433 Now we check all neighbors of our current room (destination_room) and for
3434 each neighbor that has a chest or deku guard in it, we will create a copy
3435 of our copy of the state, then enter each of them through each possible
3436 loading plane and then check the chest/guard addresses and see if anything
3437 lines up
3438
3439 """
3440
3441 for bordering_room in Neighbors(destination_room, Room_List):
3442
3443 if Chest_In_Room(bordering_room) == True or Deku_Guard_In_Room(bordering_room) == True:
3444
3445 for loading_plane in Shared_Transitions(destination_room, bordering_room):
3446
3447 # COPY STATE
3448 #######################################################
3449 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy_SS)
3450 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy_SS)
3451
3452 room_copy_dict_2 = {}
3453 for room in Room_List_Copy_2:
3454 room_copy_dict_2[room.number] = room
3455
3456 Heap_Copy_2 = Copy_Heap(Heap_Copy_SS, Room_List_Copy_2, Overlay_Dict_Copy_2)
3457
3458 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy_SS, Room_List_Copy_2)
3459 #######################################################
3460
3461 action_list_2 = []
3462
3463 loading_plane_copy = Find_Actor_Copy(loading_plane, Room_List_Copy_2)
3464
3465 bordering_room_copy = room_copy_dict_2[bordering_room.number]
3466
3467 Load_Room(Heap_Copy_2, bordering_room_copy, loading_plane_copy, Overlay_Dict_Copy_2)
3468 action_list_2.append("Load Room: Room %d" %(bordering_room_copy.number) + " with " + loading_plane_copy.name + " %d" %(loading_plane_copy.priority))
3469
3470
3471 ##### Now check for chests/deku guards
3472
3473 chest_guard_list = []
3474
3475 for entry in Heap_Copy_2:
3476
3477 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3478 chest_guard_list.append(entry)
3479
3480 soln_found = False
3481 for entry in chest_guard_list:
3482 if (pot.address - entry.address) in Offset_List:
3483
3484 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3485
3486 if (pot.address - entry.address) == 0x160:
3487 angle_solution_count += 1
3488 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3489 elif (pot.address - entry.address) == 0x1F0:
3490 position_solution_count += 1
3491 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3492
3493 soln_found = True
3494
3495 if soln_found is True:
3496 total_action_list = action_list + action_list_transition + action_list100 + action_list_2
3497
3498 # the "a" argument is important so we don't overwrite previous solutions
3499 with open(filename, "a") as file:
3500
3501 for action in total_action_list:
3502
3503 file.write(action + "\n")
3504 file.write("-----\n")
3505
3506
3507
3508 ##### Only smoke is loaded from superslide
3509 elif Grabbable_Dict[pot][0][1] == '1':
3510
3511 action_list010 = []
3512
3513 # COPY STATE
3514 #######################################################
3515 Room_List_Copy_SS = Copy_Room_List(Room_List_Copy)
3516 Overlay_Dict_Copy_SS = Copy_Overlay_Dict(Overlay_Dict_Copy)
3517
3518 room_copy_dict_SS = {}
3519 for room in Room_List_Copy_SS:
3520 room_copy_dict_SS[room.number] = room
3521
3522 Heap_Copy_SS = Copy_Heap(Heap_Copy, Room_List_Copy_SS, Overlay_Dict_Copy_SS)
3523
3524 Grabbable_Dict_Copy_SS = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_SS)
3525 #######################################################
3526
3527 Allocate_Smoke(Heap_Copy_SS, neighbor.number, Overlay_Dict_Copy_SS)
3528 action_list010.append("Superslide with Smoke still allocated")
3529
3530 # The room we superslide into through the plane corresponding to the given pot
3531 destination_room = Current_Room([neighbor, Grabbable_Dict[pot][1]], Room_List)
3532
3533 destination_room_copy = room_copy_dict_SS[destination_room.number]
3534
3535 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_SS)
3536 superslide_transition_copy = Grabbable_Dict_Copy_SS[pot_copy][1]
3537
3538 Load_Room(Heap_Copy_SS, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_SS)
3539 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3540
3541 """
3542
3543 Now we check all neighbors of our current room (destination_room) and for
3544 each neighbor that has a chest or deku guard in it, we will create a copy
3545 of our copy of the state, then enter each of them through each possible
3546 loading plane and then check the chest/guard addresses and see if anything
3547 lines up
3548
3549 """
3550
3551 for bordering_room in Neighbors(destination_room, Room_List):
3552
3553 if Chest_In_Room(bordering_room) == True or Deku_Guard_In_Room(bordering_room) == True:
3554
3555 for loading_plane in Shared_Transitions(destination_room, bordering_room):
3556
3557 # COPY STATE
3558 #######################################################
3559 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy_SS)
3560 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy_SS)
3561
3562 room_copy_dict_2 = {}
3563 for room in Room_List_Copy_2:
3564 room_copy_dict_2[room.number] = room
3565
3566 Heap_Copy_2 = Copy_Heap(Heap_Copy_SS, Room_List_Copy_2, Overlay_Dict_Copy_2)
3567
3568 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy_SS, Room_List_Copy_2)
3569 #######################################################
3570
3571 action_list_2 = []
3572
3573 loading_plane_copy = Find_Actor_Copy(loading_plane, Room_List_Copy_2)
3574
3575 bordering_room_copy = room_copy_dict_2[bordering_room.number]
3576
3577 Load_Room(Heap_Copy_2, bordering_room_copy, loading_plane_copy, Overlay_Dict_Copy_2)
3578 action_list_2.append("Load Room: Room %d" %(bordering_room_copy.number) + " with " + loading_plane_copy.name + " %d" %(loading_plane_copy.priority))
3579
3580
3581 ##### Now check for chests/deku guards
3582
3583 chest_guard_list = []
3584
3585 for entry in Heap_Copy_2:
3586
3587 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3588 chest_guard_list.append(entry)
3589
3590 soln_found = False
3591 for entry in chest_guard_list:
3592 if (pot.address - entry.address) in Offset_List:
3593
3594 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3595
3596 if (pot.address - entry.address) == 0x160:
3597 angle_solution_count += 1
3598 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3599 elif (pot.address - entry.address) == 0x1F0:
3600 position_solution_count += 1
3601 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3602
3603 soln_found = True
3604
3605 if soln_found is True:
3606 total_action_list = action_list + action_list_transition + action_list010 + action_list_2
3607
3608 # the "a" argument is important so we don't overwrite previous solutions
3609 with open(filename, "a") as file:
3610
3611 for action in total_action_list:
3612
3613 file.write(action + "\n")
3614 file.write("-----\n")
3615
3616
3617 #### Bomb and Smoke are both unloaded
3618 elif Grabbable_Dict[pot][0][2] == '1':
3619
3620 action_list001 = []
3621
3622 # COPY STATE
3623 #######################################################
3624 Room_List_Copy_SS = Copy_Room_List(Room_List_Copy)
3625 Overlay_Dict_Copy_SS = Copy_Overlay_Dict(Overlay_Dict_Copy)
3626
3627 room_copy_dict_SS = {}
3628 for room in Room_List_Copy_SS:
3629 room_copy_dict_SS[room.number] = room
3630
3631 Heap_Copy_SS = Copy_Heap(Heap_Copy, Room_List_Copy_SS, Overlay_Dict_Copy_SS)
3632
3633 Grabbable_Dict_Copy_SS = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_SS)
3634 #######################################################
3635
3636 # Do not allocate anything
3637 action_list001.append("Superslide with Bomb and Smoke unloaded when passing plane")
3638
3639 # The room we superslide into through the plane corresponding to the given pot
3640 destination_room = Current_Room([neighbor, Grabbable_Dict[pot][1]], Room_List)
3641
3642 destination_room_copy = room_copy_dict_SS[destination_room.number]
3643
3644 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_SS)
3645 superslide_transition_copy = Grabbable_Dict_Copy_SS[pot_copy][1]
3646
3647 Load_Room(Heap_Copy_SS, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_SS)
3648 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3649
3650 """
3651
3652 Now we check all neighbors of our current room (destination_room) and for
3653 each neighbor that has a chest or deku guard in it, we will create a copy
3654 of our copy of the state, then enter each of them through each possible
3655 loading plane and then check the chest/guard addresses and see if anything
3656 lines up
3657
3658 """
3659
3660 for bordering_room in Neighbors(destination_room, Room_List):
3661
3662 if Chest_In_Room(bordering_room) == True or Deku_Guard_In_Room(bordering_room) == True:
3663
3664 for loading_plane in Shared_Transitions(destination_room, bordering_room):
3665
3666 # COPY STATE
3667 #######################################################
3668 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy_SS)
3669 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy_SS)
3670
3671 room_copy_dict_2 = {}
3672 for room in Room_List_Copy_2:
3673 room_copy_dict_2[room.number] = room
3674
3675 Heap_Copy_2 = Copy_Heap(Heap_Copy_SS, Room_List_Copy_2, Overlay_Dict_Copy_2)
3676
3677 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy_SS, Room_List_Copy_2)
3678 #######################################################
3679
3680 action_list_2 = []
3681
3682 loading_plane_copy = Find_Actor_Copy(loading_plane, Room_List_Copy_2)
3683
3684 bordering_room_copy = room_copy_dict_2[bordering_room.number]
3685
3686 Load_Room(Heap_Copy_2, bordering_room_copy, loading_plane_copy, Overlay_Dict_Copy_2)
3687 action_list_2.append("Load Room: Room %d" %(bordering_room_copy.number) + " with " + loading_plane_copy.name + " %d" %(loading_plane_copy.priority))
3688
3689
3690 ##### Now check for chests/deku guards
3691
3692 chest_guard_list = []
3693
3694 for entry in Heap_Copy_2:
3695
3696 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3697 chest_guard_list.append(entry)
3698
3699 soln_found = False
3700 for entry in chest_guard_list:
3701 if (pot.address - entry.address) in Offset_List:
3702
3703 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3704
3705 if (pot.address - entry.address) == 0x160:
3706 angle_solution_count += 1
3707 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3708 elif (pot.address - entry.address) == 0x1F0:
3709 position_solution_count += 1
3710 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3711
3712 soln_found = True
3713
3714 if soln_found is True:
3715 total_action_list = action_list + action_list_transition + action_list001 + action_list_2
3716
3717 # the "a" argument is important so we don't overwrite previous solutions
3718 with open(filename, "a") as file:
3719
3720 for action in total_action_list:
3721
3722 file.write(action + "\n")
3723 file.write("-----\n")
3724
3725
3726
3727 # If there isn't a chest/guard, superslide (into chest/guard room by assumption), then exit then reenter it (this case never happens in palace, so this is an okay assumption)
3728 elif Chest_In_Room(neighbor) == False and Deku_Guard_In_Room(neighbor) == False:
3729
3730 for pot in valid_pot_list:
3731
3732 # both bomb and smoke loaded on superslide
3733 if Grabbable_Dict[pot][0][0] == '1':
3734
3735 action_list100 = []
3736
3737 # COPY STATE
3738 #######################################################
3739 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
3740 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
3741
3742 room_copy_dict_2 = {}
3743 for room in Room_List_Copy_2:
3744 room_copy_dict_2[room.number] = room
3745
3746 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
3747
3748 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
3749 #######################################################
3750
3751 Bomb_And_Smoke_Superslide(Heap_Copy_2, neighbor_copy.number, Overlay_Dict_Copy_2)
3752 action_list100.append("Superslide with Bomb and Smoke still allocated")
3753
3754 # The room we superslide into through the plane corresponding to the given pot
3755 destination_room = Current_Room([neighbor, Grabbable_Dict[pot][1]], Room_List)
3756
3757 destination_room_copy = room_copy_dict_2[destination_room.number]
3758 neighbor_copy_2 = room_copy_dict_2[neighbor_copy.number]
3759
3760 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_2)
3761 superslide_transition_copy = Grabbable_Dict_Copy_2[pot_copy][1]
3762
3763 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
3764 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3765
3766 # Now exit the chest room
3767 Load_Room(Heap_Copy_2, neighbor_copy_2, superslide_transition_copy, Overlay_Dict_Copy_2)
3768 action_list100.append("Load Room: Room %d" %(neighbor_copy_2.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3769
3770 # Now reenter the chest room
3771 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
3772 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3773
3774 ##### Now check for chests/deku guards
3775
3776 chest_guard_list = []
3777
3778 for entry in Heap_Copy_2:
3779
3780 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3781 chest_guard_list.append(entry)
3782
3783 soln_found = False
3784 for entry in chest_guard_list:
3785 if (pot.address - entry.address) in Offset_List:
3786
3787 action_list100.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3788
3789 if (pot.address - entry.address) == 0x160:
3790 angle_solution_count += 1
3791 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3792 elif (pot.address - entry.address) == 0x1F0:
3793 position_solution_count += 1
3794 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3795
3796 soln_found = True
3797
3798 if soln_found is True:
3799 total_action_list = action_list + action_list_transition + action_list100
3800
3801 # the "a" argument is important so we don't overwrite previous solutions
3802 with open(filename, "a") as file:
3803
3804 for action in total_action_list:
3805
3806 file.write(action + "\n")
3807 file.write("-----\n")
3808
3809
3810
3811 ##### Only smoke is loaded from superslide
3812 elif Grabbable_Dict[pot][0][1] == '1':
3813
3814 action_list010 = []
3815
3816 # COPY STATE
3817 #######################################################
3818 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
3819 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
3820
3821 room_copy_dict_2 = {}
3822 for room in Room_List_Copy_2:
3823 room_copy_dict_2[room.number] = room
3824
3825 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
3826
3827 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
3828 #######################################################
3829
3830 Allocate_Smoke(Heap_Copy_2, neighbor_copy.number, Overlay_Dict_Copy_2)
3831 action_list010.append("Superslide with Smoke still allocated")
3832
3833 # The room we superslide into through the plane corresponding to the given pot
3834 destination_room = Current_Room([neighbor, Grabbable_Dict[pot][1]], Room_List)
3835
3836 destination_room_copy = room_copy_dict_2[destination_room.number]
3837 neighbor_copy_2 = room_copy_dict_2[neighbor_copy.number]
3838
3839 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_2)
3840 superslide_transition_copy = Grabbable_Dict_Copy_2[pot_copy][1]
3841
3842 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
3843 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3844
3845 # Now exit the chest room
3846 Load_Room(Heap_Copy_2, neighbor_copy_2, superslide_transition_copy, Overlay_Dict_Copy_2)
3847 action_list010.append("Load Room: Room %d" %(neighbor_copy_2.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3848
3849 # Now reenter the chest room
3850 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
3851 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3852
3853 ##### Now check for chests/deku guards
3854
3855 chest_guard_list = []
3856
3857 for entry in Heap_Copy_2:
3858
3859 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3860 chest_guard_list.append(entry)
3861
3862 soln_found = False
3863 for entry in chest_guard_list:
3864 if (pot.address - entry.address) in Offset_List:
3865
3866 action_list010.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3867
3868 if (pot.address - entry.address) == 0x160:
3869 angle_solution_count += 1
3870 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3871 elif (pot.address - entry.address) == 0x1F0:
3872 position_solution_count += 1
3873 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3874
3875 soln_found = True
3876
3877 if soln_found is True:
3878 total_action_list = action_list + action_list_transition + action_list010
3879
3880 # the "a" argument is important so we don't overwrite previous solutions
3881 with open(filename, "a") as file:
3882
3883 for action in total_action_list:
3884
3885 file.write(action + "\n")
3886 file.write("-----\n")
3887
3888
3889
3890 #### Bomb and Smoke are both unloaded
3891 elif Grabbable_Dict[pot][0][2] == '1':
3892
3893 action_list001 = []
3894
3895 # COPY STATE
3896 #######################################################
3897 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
3898 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
3899
3900 room_copy_dict_2 = {}
3901 for room in Room_List_Copy_2:
3902 room_copy_dict_2[room.number] = room
3903
3904 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
3905
3906 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
3907 #######################################################
3908
3909 # Do not allocate anything
3910 action_list001.append("Superslide with Bomb and Smoke unloaded when passing plane")
3911
3912 # The room we superslide into through the plane corresponding to the given pot
3913 destination_room = Current_Room([neighbor, Grabbable_Dict[pot][1]], Room_List)
3914
3915 destination_room_copy = room_copy_dict_2[destination_room.number]
3916 neighbor_copy_2 = room_copy_dict_2[neighbor_copy.number]
3917
3918 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_2)
3919 superslide_transition_copy = Grabbable_Dict_Copy_2[pot_copy][1]
3920
3921 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
3922 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3923
3924 # Now exit the chest room
3925 Load_Room(Heap_Copy_2, neighbor_copy_2, superslide_transition_copy, Overlay_Dict_Copy_2)
3926 action_list001.append("Load Room: Room %d" %(neighbor_copy_2.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3927
3928 # Now reenter the chest room
3929 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
3930 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
3931
3932 ##### Now check for chests/deku guards
3933
3934 chest_guard_list = []
3935
3936 for entry in Heap_Copy_2:
3937
3938 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
3939 chest_guard_list.append(entry)
3940
3941 soln_found = False
3942 for entry in chest_guard_list:
3943 if (pot.address - entry.address) in Offset_List:
3944
3945 action_list001.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
3946
3947 if (pot.address - entry.address) == 0x160:
3948 angle_solution_count += 1
3949 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3950 elif (pot.address - entry.address) == 0x1F0:
3951 position_solution_count += 1
3952 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
3953
3954 soln_found = True
3955
3956 if soln_found is True:
3957 total_action_list = action_list + action_list_transition + action_list001
3958
3959 # the "a" argument is important so we don't overwrite previous solutions
3960 with open(filename, "a") as file:
3961
3962 for action in total_action_list:
3963
3964 file.write(action + "\n")
3965 file.write("-----\n")
3966
3967
3968 ##### No valid grabbable actor in neighbor
3969 elif neighbor not in valid_grabbable_actor_room_list:
3970
3971 for new_neighbor in Neighbors(neighbor, Room_List):
3972
3973 # if new neighbor has a valid grabbable actor... (Otherwise, we do nothing)
3974 if new_neighbor in valid_grabbable_actor_room_list:
3975
3976 ##### Iterate through all pots in this room
3977
3978 valid_pot_list = []
3979 pot_address_list = []
3980
3981 for pot in Grabbable_Dict:
3982
3983 if Actor_Is_In_Room(new_neighbor, pot) is True:
3984 valid_pot_list.append(pot)
3985 pot_address_list.append(pot.address)
3986
3987 for neighbor_transition in Shared_Transitions(current_room, neighbor):
3988 for new_neighbor_transition in Shared_Transitions(neighbor, new_neighbor):
3989
3990 action_list_transition = []
3991
3992 ##### COPY THE STATE
3993 #######################################################
3994 Room_List_Copy = Copy_Room_List(Room_List)
3995 Overlay_Dict_Copy = Copy_Overlay_Dict(Overlay_Dict)
3996
3997 room_copy_dict = {}
3998 for room in Room_List_Copy:
3999 room_copy_dict[room.number] = room
4000
4001 Heap_Copy = Copy_Heap(Heap, Room_List_Copy, Overlay_Dict_Copy)
4002
4003 Grabbable_Dict_Copy = Copy_Grabbable_Dict(Grabbable_Dict, Room_List_Copy)
4004 #######################################################
4005
4006 neighbor_copy = room_copy_dict[neighbor.number]
4007 neighbor_transition_copy = Find_Actor_Copy(neighbor_transition, Room_List_Copy)
4008
4009 new_neighbor_copy = room_copy_dict[new_neighbor.number]
4010 new_neighbor_transition_copy = Find_Actor_Copy(new_neighbor_transition, Room_List_Copy)
4011
4012 ##### ENTER neighbor
4013
4014 Load_Room(Heap_Copy, neighbor_copy, neighbor_transition_copy, Overlay_Dict_Copy)
4015 action_list_transition.append("Load Room: Room %d" %(neighbor_copy.number) + " with " + neighbor_transition_copy.name + " %d" %(neighbor_transition_copy.priority))
4016
4017 ##### ENTER new_neighbor
4018
4019 Load_Room(Heap_Copy, new_neighbor_copy, new_neighbor_transition_copy, Overlay_Dict_Copy)
4020 action_list_transition.append("Load Room: Room %d" %(new_neighbor_copy.number) + " with " + new_neighbor_transition_copy.name + " %d" %(new_neighbor_transition_copy.priority))
4021
4022
4023 # If there is a chest/guard, superslide, then check neighbors for chests/guards and test all (copy state)
4024 if Chest_In_Room(new_neighbor) == True or Deku_Guard_In_Room(new_neighbor) == True:
4025
4026 for pot in valid_pot_list:
4027
4028 # both bomb and smoke loaded on superslide
4029 if Grabbable_Dict[pot][0][0] == '1':
4030
4031 action_list100 = []
4032
4033 # COPY STATE
4034 #######################################################
4035 Room_List_Copy_SS = Copy_Room_List(Room_List_Copy)
4036 Overlay_Dict_Copy_SS = Copy_Overlay_Dict(Overlay_Dict_Copy)
4037
4038 room_copy_dict_SS = {}
4039 for room in Room_List_Copy_SS:
4040 room_copy_dict_SS[room.number] = room
4041
4042 Heap_Copy_SS = Copy_Heap(Heap_Copy, Room_List_Copy_SS, Overlay_Dict_Copy_SS)
4043
4044 Grabbable_Dict_Copy_SS = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_SS)
4045 #######################################################
4046
4047 Bomb_And_Smoke_Superslide(Heap_Copy_SS, new_neighbor.number, Overlay_Dict_Copy_SS)
4048 action_list100.append("Superslide with Bomb and Smoke still allocated")
4049
4050 # The room we superslide into through the plane corresponding to the given pot
4051 destination_room = Current_Room([new_neighbor, Grabbable_Dict[pot][1]], Room_List)
4052
4053 destination_room_copy = room_copy_dict_SS[destination_room.number]
4054
4055 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_SS)
4056 superslide_transition_copy = Grabbable_Dict_Copy_SS[pot_copy][1]
4057
4058 Load_Room(Heap_Copy_SS, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_SS)
4059 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4060
4061 """
4062
4063 Now we check all neighbors of our current room (destination_room) and for
4064 each neighbor that has a chest or deku guard in it, we will create a copy
4065 of our copy of the state, then enter each of them through each possible
4066 loading plane and then check the chest/guard addresses and see if anything
4067 lines up
4068
4069 """
4070
4071 for bordering_room in Neighbors(destination_room, Room_List):
4072
4073 if Chest_In_Room(bordering_room) == True or Deku_Guard_In_Room(bordering_room) == True:
4074
4075 for loading_plane in Shared_Transitions(destination_room, bordering_room):
4076
4077 # COPY STATE
4078 #######################################################
4079 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy_SS)
4080 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy_SS)
4081
4082 room_copy_dict_2 = {}
4083 for room in Room_List_Copy_2:
4084 room_copy_dict_2[room.number] = room
4085
4086 Heap_Copy_2 = Copy_Heap(Heap_Copy_SS, Room_List_Copy_2, Overlay_Dict_Copy_2)
4087
4088 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy_SS, Room_List_Copy_2)
4089 #######################################################
4090
4091 action_list_2 = []
4092
4093 loading_plane_copy = Find_Actor_Copy(loading_plane, Room_List_Copy_2)
4094
4095 bordering_room_copy = room_copy_dict_2[bordering_room.number]
4096
4097 Load_Room(Heap_Copy_2, bordering_room_copy, loading_plane_copy, Overlay_Dict_Copy_2)
4098 action_list_2.append("Load Room: Room %d" %(bordering_room_copy.number) + " with " + loading_plane_copy.name + " %d" %(loading_plane_copy.priority))
4099
4100
4101 ##### Now check for chests/deku guards
4102
4103 chest_guard_list = []
4104
4105 for entry in Heap_Copy_2:
4106
4107 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
4108 chest_guard_list.append(entry)
4109
4110 soln_found = False
4111 for entry in chest_guard_list:
4112 if (pot.address - entry.address) in Offset_List:
4113
4114 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
4115
4116 if (pot.address - entry.address) == 0x160:
4117 angle_solution_count += 1
4118 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4119 elif (pot.address - entry.address) == 0x1F0:
4120 position_solution_count += 1
4121 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4122
4123 soln_found = True
4124
4125 if soln_found is True:
4126 total_action_list = action_list + action_list_transition + action_list100 + action_list_2
4127
4128 # the "a" argument is important so we don't overwrite previous solutions
4129 with open(filename, "a") as file:
4130
4131 for action in total_action_list:
4132
4133 file.write(action + "\n")
4134 file.write("-----\n")
4135
4136
4137
4138 ##### Only smoke is loaded from superslide
4139 elif Grabbable_Dict[pot][0][1] == '1':
4140
4141 action_list010 = []
4142
4143 # COPY STATE
4144 #######################################################
4145 Room_List_Copy_SS = Copy_Room_List(Room_List_Copy)
4146 Overlay_Dict_Copy_SS = Copy_Overlay_Dict(Overlay_Dict_Copy)
4147
4148 room_copy_dict_SS = {}
4149 for room in Room_List_Copy_SS:
4150 room_copy_dict_SS[room.number] = room
4151
4152 Heap_Copy_SS = Copy_Heap(Heap_Copy, Room_List_Copy_SS, Overlay_Dict_Copy_SS)
4153
4154 Grabbable_Dict_Copy_SS = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_SS)
4155 #######################################################
4156
4157 Allocate_Smoke(Heap_Copy_SS, new_neighbor.number, Overlay_Dict_Copy_SS)
4158 action_list010.append("Superslide with Smoke still allocated")
4159
4160 # The room we superslide into through the plane corresponding to the given pot
4161 destination_room = Current_Room([new_neighbor, Grabbable_Dict[pot][1]], Room_List)
4162
4163 destination_room_copy = room_copy_dict_SS[destination_room.number]
4164
4165 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_SS)
4166 superslide_transition_copy = Grabbable_Dict_Copy_SS[pot_copy][1]
4167
4168 Load_Room(Heap_Copy_SS, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_SS)
4169 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4170
4171 """
4172
4173 Now we check all neighbors of our current room (destination_room) and for
4174 each neighbor that has a chest or deku guard in it, we will create a copy
4175 of our copy of the state, then enter each of them through each possible
4176 loading plane and then check the chest/guard addresses and see if anything
4177 lines up
4178
4179 """
4180
4181 for bordering_room in Neighbors(destination_room, Room_List):
4182
4183 if Chest_In_Room(bordering_room) == True or Deku_Guard_In_Room(bordering_room) == True:
4184
4185 for loading_plane in Shared_Transitions(destination_room, bordering_room):
4186
4187 # COPY STATE
4188 #######################################################
4189 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy_SS)
4190 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy_SS)
4191
4192 room_copy_dict_2 = {}
4193 for room in Room_List_Copy_2:
4194 room_copy_dict_2[room.number] = room
4195
4196 Heap_Copy_2 = Copy_Heap(Heap_Copy_SS, Room_List_Copy_2, Overlay_Dict_Copy_2)
4197
4198 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy_SS, Room_List_Copy_2)
4199 #######################################################
4200
4201 action_list_2 = []
4202
4203 loading_plane_copy = Find_Actor_Copy(loading_plane, Room_List_Copy_2)
4204
4205 bordering_room_copy = room_copy_dict_2[bordering_room.number]
4206
4207 Load_Room(Heap_Copy_2, bordering_room_copy, loading_plane_copy, Overlay_Dict_Copy_2)
4208 action_list_2.append("Load Room: Room %d" %(bordering_room_copy.number) + " with " + loading_plane_copy.name + " %d" %(loading_plane_copy.priority))
4209
4210
4211 ##### Now check for chests/deku guards
4212
4213 chest_guard_list = []
4214
4215 for entry in Heap_Copy_2:
4216
4217 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
4218 chest_guard_list.append(entry)
4219
4220 soln_found = False
4221 for entry in chest_guard_list:
4222 if (pot.address - entry.address) in Offset_List:
4223
4224 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
4225
4226 if (pot.address - entry.address) == 0x160:
4227 angle_solution_count += 1
4228 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4229 elif (pot.address - entry.address) == 0x1F0:
4230 position_solution_count += 1
4231 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4232
4233 soln_found = True
4234
4235 if soln_found is True:
4236 total_action_list = action_list + action_list_transition + action_list010 + action_list_2
4237
4238 # the "a" argument is important so we don't overwrite previous solutions
4239 with open(filename, "a") as file:
4240
4241 for action in total_action_list:
4242
4243 file.write(action + "\n")
4244 file.write("-----\n")
4245
4246
4247 #### Bomb and Smoke are both unloaded
4248 elif Grabbable_Dict[pot][0][2] == '1':
4249
4250 action_list001 = []
4251
4252 # COPY STATE
4253 #######################################################
4254 Room_List_Copy_SS = Copy_Room_List(Room_List_Copy)
4255 Overlay_Dict_Copy_SS = Copy_Overlay_Dict(Overlay_Dict_Copy)
4256
4257 room_copy_dict_SS = {}
4258 for room in Room_List_Copy_SS:
4259 room_copy_dict_SS[room.number] = room
4260
4261 Heap_Copy_SS = Copy_Heap(Heap_Copy, Room_List_Copy_SS, Overlay_Dict_Copy_SS)
4262
4263 Grabbable_Dict_Copy_SS = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_SS)
4264 #######################################################
4265
4266 # Do not allocate anything
4267 action_list001.append("Superslide with Bomb and Smoke unloaded when passing plane")
4268
4269 # The room we superslide into through the plane corresponding to the given pot
4270 destination_room = Current_Room([new_neighbor, Grabbable_Dict[pot][1]], Room_List)
4271
4272 destination_room_copy = room_copy_dict_SS[destination_room.number]
4273
4274 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_SS)
4275 superslide_transition_copy = Grabbable_Dict_Copy_SS[pot_copy][1]
4276
4277 Load_Room(Heap_Copy_SS, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_SS)
4278 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4279
4280 """
4281
4282 Now we check all neighbors of our current room (destination_room) and for
4283 each neighbor that has a chest or deku guard in it, we will create a copy
4284 of our copy of the state, then enter each of them through each possible
4285 loading plane and then check the chest/guard addresses and see if anything
4286 lines up
4287
4288 """
4289
4290 for bordering_room in Neighbors(destination_room, Room_List):
4291
4292 if Chest_In_Room(bordering_room) == True or Deku_Guard_In_Room(bordering_room) == True:
4293
4294 for loading_plane in Shared_Transitions(destination_room, bordering_room):
4295
4296 # COPY STATE
4297 #######################################################
4298 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy_SS)
4299 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy_SS)
4300
4301 room_copy_dict_2 = {}
4302 for room in Room_List_Copy_2:
4303 room_copy_dict_2[room.number] = room
4304
4305 Heap_Copy_2 = Copy_Heap(Heap_Copy_SS, Room_List_Copy_2, Overlay_Dict_Copy_2)
4306
4307 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy_SS, Room_List_Copy_2)
4308 #######################################################
4309
4310 action_list_2 = []
4311
4312 loading_plane_copy = Find_Actor_Copy(loading_plane, Room_List_Copy_2)
4313
4314 bordering_room_copy = room_copy_dict_2[bordering_room.number]
4315
4316 Load_Room(Heap_Copy_2, bordering_room_copy, loading_plane_copy, Overlay_Dict_Copy_2)
4317 action_list_2.append("Load Room: Room %d" %(bordering_room_copy.number) + " with " + loading_plane_copy.name + " %d" %(loading_plane_copy.priority))
4318
4319
4320 ##### Now check for chests/deku guards
4321
4322 chest_guard_list = []
4323
4324 for entry in Heap_Copy_2:
4325
4326 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
4327 chest_guard_list.append(entry)
4328
4329 soln_found = False
4330 for entry in chest_guard_list:
4331 if (pot.address - entry.address) in Offset_List:
4332
4333 action_list_2.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
4334
4335 if (pot.address - entry.address) == 0x160:
4336 angle_solution_count += 1
4337 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4338 elif (pot.address - entry.address) == 0x1F0:
4339 position_solution_count += 1
4340 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4341
4342 soln_found = True
4343
4344 if soln_found is True:
4345 total_action_list = action_list + action_list_transition + action_list001 + action_list_2
4346
4347 # the "a" argument is important so we don't overwrite previous solutions
4348 with open(filename, "a") as file:
4349
4350 for action in total_action_list:
4351
4352 file.write(action + "\n")
4353 file.write("-----\n")
4354
4355
4356
4357 # If there isn't a chest/guard, superslide (into chest/guard room by assumption), then exit then reenter it (this case never happens in palace, so this is an okay assumption)
4358 elif Chest_In_Room(new_neighbor) == False and Deku_Guard_In_Room(new_neighbor) == False:
4359
4360 for pot in valid_pot_list:
4361
4362 # both bomb and smoke loaded on superslide
4363 if Grabbable_Dict[pot][0][0] == '1':
4364
4365 action_list100 = []
4366
4367 # COPY STATE
4368 #######################################################
4369 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
4370 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
4371
4372 room_copy_dict_2 = {}
4373 for room in Room_List_Copy_2:
4374 room_copy_dict_2[room.number] = room
4375
4376 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
4377
4378 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
4379 #######################################################
4380
4381 Bomb_And_Smoke_Superslide(Heap_Copy_2, new_neighbor_copy.number, Overlay_Dict_Copy_2)
4382 action_list100.append("Superslide with Bomb and Smoke still allocated")
4383
4384 # The room we superslide into through the plane corresponding to the given pot
4385 destination_room = Current_Room([new_neighbor, Grabbable_Dict[pot][1]], Room_List)
4386
4387 destination_room_copy = room_copy_dict_2[destination_room.number]
4388 new_neighbor_copy_2 = room_copy_dict_2[new_neighbor_copy.number]
4389
4390 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_2)
4391 superslide_transition_copy = Grabbable_Dict_Copy_2[pot_copy][1]
4392
4393 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
4394 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4395
4396 # Now exit the chest room
4397 Load_Room(Heap_Copy_2, new_neighbor_copy_2, superslide_transition_copy, Overlay_Dict_Copy_2)
4398 action_list100.append("Load Room: Room %d" %(new_neighbor_copy_2.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4399
4400 # Now reenter the chest room
4401 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
4402 action_list100.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4403
4404 ##### Now check for chests/deku guards
4405
4406 chest_guard_list = []
4407
4408 for entry in Heap_Copy_2:
4409
4410 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
4411 chest_guard_list.append(entry)
4412
4413 soln_found = False
4414 for entry in chest_guard_list:
4415 if (pot.address - entry.address) in Offset_List:
4416
4417 action_list100.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
4418
4419 if (pot.address - entry.address) == 0x160:
4420 angle_solution_count += 1
4421 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4422 elif (pot.address - entry.address) == 0x1F0:
4423 position_solution_count += 1
4424 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4425
4426 soln_found = True
4427
4428 if soln_found is True:
4429 total_action_list = action_list + action_list_transition + action_list100
4430
4431 # the "a" argument is important so we don't overwrite previous solutions
4432 with open(filename, "a") as file:
4433
4434 for action in total_action_list:
4435
4436 file.write(action + "\n")
4437 file.write("-----\n")
4438
4439
4440
4441 ##### Only smoke is loaded from superslide
4442 elif Grabbable_Dict[pot][0][1] == '1':
4443
4444 action_list010 = []
4445
4446 # COPY STATE
4447 #######################################################
4448 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
4449 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
4450
4451 room_copy_dict_2 = {}
4452 for room in Room_List_Copy_2:
4453 room_copy_dict_2[room.number] = room
4454
4455 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
4456
4457 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
4458 #######################################################
4459
4460 Allocate_Smoke(Heap_Copy_2, new_neighbor_copy.number, Overlay_Dict_Copy_2)
4461 action_list010.append("Superslide with Smoke still allocated")
4462
4463 # The room we superslide into through the plane corresponding to the given pot
4464 destination_room = Current_Room([new_neighbor, Grabbable_Dict[pot][1]], Room_List)
4465
4466 destination_room_copy = room_copy_dict_2[destination_room.number]
4467 new_neighbor_copy_2 = room_copy_dict_2[new_neighbor_copy.number]
4468
4469 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_2)
4470 superslide_transition_copy = Grabbable_Dict_Copy_2[pot_copy][1]
4471
4472 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
4473 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4474
4475 # Now exit the chest room
4476 Load_Room(Heap_Copy_2, new_neighbor_copy_2, superslide_transition_copy, Overlay_Dict_Copy_2)
4477 action_list010.append("Load Room: Room %d" %(new_neighbor_copy_2.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4478
4479 # Now reenter the chest room
4480 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
4481 action_list010.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4482
4483 ##### Now check for chests/deku guards
4484
4485 chest_guard_list = []
4486
4487 for entry in Heap_Copy_2:
4488
4489 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
4490 chest_guard_list.append(entry)
4491
4492 soln_found = False
4493 for entry in chest_guard_list:
4494 if (pot.address - entry.address) in Offset_List:
4495
4496 action_list010.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
4497
4498 if (pot.address - entry.address) == 0x160:
4499 angle_solution_count += 1
4500 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4501 elif (pot.address - entry.address) == 0x1F0:
4502 position_solution_count += 1
4503 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4504
4505 soln_found = True
4506
4507 if soln_found is True:
4508 total_action_list = action_list + action_list_transition + action_list010
4509
4510 # the "a" argument is important so we don't overwrite previous solutions
4511 with open(filename, "a") as file:
4512
4513 for action in total_action_list:
4514
4515 file.write(action + "\n")
4516 file.write("-----\n")
4517
4518
4519
4520 #### Bomb and Smoke are both unloaded
4521 elif Grabbable_Dict[pot][0][2] == '1':
4522
4523 action_list001 = []
4524
4525 # COPY STATE
4526 #######################################################
4527 Room_List_Copy_2 = Copy_Room_List(Room_List_Copy)
4528 Overlay_Dict_Copy_2 = Copy_Overlay_Dict(Overlay_Dict_Copy)
4529
4530 room_copy_dict_2 = {}
4531 for room in Room_List_Copy_2:
4532 room_copy_dict_2[room.number] = room
4533
4534 Heap_Copy_2 = Copy_Heap(Heap_Copy, Room_List_Copy_2, Overlay_Dict_Copy_2)
4535
4536 Grabbable_Dict_Copy_2 = Copy_Grabbable_Dict(Grabbable_Dict_Copy, Room_List_Copy_2)
4537 #######################################################
4538
4539 # Do not allocate anything
4540 action_list001.append("Superslide with Bomb and Smoke unloaded when passing plane")
4541
4542 # The room we superslide into through the plane corresponding to the given pot
4543 destination_room = Current_Room([new_neighbor, Grabbable_Dict[pot][1]], Room_List)
4544
4545 destination_room_copy = room_copy_dict_2[destination_room.number]
4546 new_neighbor_copy_2 = room_copy_dict_2[new_neighbor_copy.number]
4547
4548 pot_copy = Find_Actor_Copy(pot, Room_List_Copy_2)
4549 superslide_transition_copy = Grabbable_Dict_Copy_2[pot_copy][1]
4550
4551 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
4552 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4553
4554 # Now exit the chest room
4555 Load_Room(Heap_Copy_2, new_neighbor_copy_2, superslide_transition_copy, Overlay_Dict_Copy_2)
4556 action_list001.append("Load Room: Room %d" %(new_neighbor_copy_2.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4557
4558 # Now reenter the chest room
4559 Load_Room(Heap_Copy_2, destination_room_copy, superslide_transition_copy, Overlay_Dict_Copy_2)
4560 action_list001.append("Load Room: Room %d" %(destination_room_copy.number) + " with " + superslide_transition_copy.name + " %d" %(superslide_transition_copy.priority))
4561
4562 ##### Now check for chests/deku guards
4563
4564 chest_guard_list = []
4565
4566 for entry in Heap_Copy_2:
4567
4568 if type(entry) == Actor and (entry.Id == '0006' or entry.Id == '017A'):
4569 chest_guard_list.append(entry)
4570
4571 soln_found = False
4572 for entry in chest_guard_list:
4573 if (pot.address - entry.address) in Offset_List:
4574
4575 action_list001.append("SOLUTION: " + pot.name + " (Priority %d)" %(pot.priority) + " from Room %d" %(pot.room_number) + " lines up with " + entry.name + " (Priority %d)" %(entry.priority) + " from Room %d" %(entry.room_number) + " with offset: " + hex(pot.address - entry.address))
4576
4577 if (pot.address - entry.address) == 0x160:
4578 angle_solution_count += 1
4579 print("ANGLE SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4580 elif (pot.address - entry.address) == 0x1F0:
4581 position_solution_count += 1
4582 print("Z POSITION SOLUTION FOUND (CHEST)!!!!!!!!!!!")
4583
4584 soln_found = True
4585
4586 if soln_found is True:
4587 total_action_list = action_list + action_list_transition + action_list001
4588
4589 # the "a" argument is important so we don't overwrite previous solutions
4590 with open(filename, "a") as file:
4591
4592 for action in total_action_list:
4593
4594 file.write(action + "\n")
4595 file.write("-----\n")
4596
4597
4598
4599
4600###############################################################################
4601###############################################################################
4602###############################################################################
4603###############################################################################
4604###############################################################################
4605###############################################################################
4606###############################################################################
4607###############################################################################
4608###############################################################################
4609###############################################################################
4610###############################################################################
4611###############################################################################
4612###############################################################################
4613###############################################################################
4614###############################################################################
4615###############################################################################
4616###############################################################################
4617###############################################################################
4618###############################################################################
4619###############################################################################
4620###############################################################################
4621###############################################################################
4622###############################################################################
4623###############################################################################
4624###############################################################################
4625###############################################################################
4626###############################################################################
4627###############################################################################
4628###############################################################################
4629###############################################################################
4630###############################################################################
4631###############################################################################
4632###############################################################################
4633###############################################################################
4634###############################################################################
4635###############################################################################
4636###############################################################################
4637###############################################################################
4638###############################################################################
4639###############################################################################
4640###############################################################################
4641###############################################################################
4642###############################################################################
4643###############################################################################
4644###############################################################################
4645###############################################################################
4646###############################################################################
4647###############################################################################
4648
4649
4650
4651
4652
4653
4654
4655"""
4656
4657 Before proceeding, we should define all of the transitions we plan on passing through
4658
4659 Since "Beneath the Graveyard" is relatively simple and I currently only want to consider
4660 passing through a single plane, I will just define Plane_1 to be the plane shared between
4661 Room0 and Room1
4662
4663 This loading plane happens the be the second element in Room0_queue, so I will define it based on that
4664
4665"""
4666
4667Oceanside_Plane_0 = Oceanside_Room3_queue[0]
4668
4669
4670
4671
4672
4673"""
4674
4675 Grabbable_dict is a dictionary of the grabbable actors (such as pots) that
4676 we want to attempt to use for superslide SRM where the keys are the grabbable
4677 actors and the values are lists with 3-bit strings where each bit means:
4678
4679 100 : Possible to enter Plane with both Bomb and Smoke loaded
4680 010 : Possible to enter Plane with Smoke loaded, but no Bomb loaded
4681 001 : Possible to enter Plane with no Smoke loaded
4682
4683 and Transitions, where the transitions are the ones you can superslide through
4684
4685
4686"""
4687
4688Oceanside_Grabbable_dict = {
4689 Oceanside_Room3_queue[6] : ['010', Oceanside_Plane_0],
4690 Oceanside_Room3_queue[7] : ['010', Oceanside_Plane_0]
4691 }
4692
4693
4694Hardcoded_Allocation_List0 = [
4695 'Smoke',
4696 'Chu',
4697 'Chu',
4698 'Chu',
4699 'Arrow',
4700 'Arrow',
4701 'Arrow',
4702 'Arrow',
4703 'Arrow',
4704 'Bomb',
4705 'Bomb',
4706 'Bomb',
4707 'Zora Fins',
4708 'Fish',
4709 'Fish',
4710 'Bugs',
4711 'Bugs',
4712 'Hookshot',
4713 'Charged Spin Attack'
4714 ]
4715
4716Hardcoded_Allocation_List_2 = [
4717 'Smoke',
4718 'Arrow',
4719 'Arrow',
4720 'Arrow',
4721 'Arrow',
4722 'Arrow',
4723 'Bomb',
4724 'Bomb',
4725 'Bomb',
4726 'Hookshot',
4727 'Charged Spin Attack'
4728 ]
4729
4730
4731
4732save_path = "C:\\Users\\doldop\\Documents\\Bizhawk RAM Watch\\scripts\\"
4733name_of_file = "solver oceainside0"
4734complete_name = save_path + name_of_file + ".txt"
4735
4736Heap = [Node(0x40B140, node_size), Node(0x5FFFFF, node_size)]
4737
4738Randomized_Solver(Oceanside_Room3, Oceanside_Room_List, 5, Hardcoded_Allocation_List_2, Oceanside_Grabbable_dict, Overlay_dict, complete_name, [0x160, 0x1F0], Heap)