diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2023-11-10 14:07:56 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-10 13:07:56 -0600 |
commit | a43fb727a292bd9476dc8de5685c5b6c38a6a919 (patch) | |
tree | 9e702125b47c95fcaf2accf548aba241a9d50282 /player_logic.py | |
parent | bbbbc71bee25cfd22c5304f98f5a7881383585a3 (diff) | |
download | lingo-apworld-a43fb727a292bd9476dc8de5685c5b6c38a6a919.tar.gz lingo-apworld-a43fb727a292bd9476dc8de5685c5b6c38a6a919.tar.bz2 lingo-apworld-a43fb727a292bd9476dc8de5685c5b6c38a6a919.zip |
Lingo: Fix edge case painting shuffle accessibility issues (#2441)
* Lingo: Fix painting shuffle logic issue in The Wise * Lingo: More generic painting cycle prevention * Lingo: okay how about now * Lingo: Consider Owl Hallway blocked painting areas in vanilla doors * Lingo: so honestly I should've seen this one coming * Lingo: Refined req_blocked for vanilla doors * Lingo: Orange Tower Basement is also owl-blocked * Lingo: Rewrite randomize_paintings to eliminate rerolls Now, mapping is done in two phases, rather than assigning everything at once and then rerolling if the mapping is non-viable.
Diffstat (limited to 'player_logic.py')
-rw-r--r-- | player_logic.py | 62 |
1 files changed, 33 insertions, 29 deletions
diff --git a/player_logic.py b/player_logic.py index 217ad91..66fe317 100644 --- a/player_logic.py +++ b/player_logic.py | |||
@@ -241,43 +241,46 @@ class LingoPlayerLogic: | |||
241 | 241 | ||
242 | door_shuffle = world.options.shuffle_doors | 242 | door_shuffle = world.options.shuffle_doors |
243 | 243 | ||
244 | # Determine the set of exit paintings. All required-exit paintings are included, as are all | 244 | # First, assign mappings to the required-exit paintings. We ensure that req-blocked paintings do not lead to |
245 | # required-when-no-doors paintings if door shuffle is off. We then fill the set with random other paintings. | 245 | # required paintings. |
246 | chosen_exits = [] | 246 | req_exits = [] |
247 | required_painting_rooms = REQUIRED_PAINTING_ROOMS | ||
247 | if door_shuffle == ShuffleDoors.option_none: | 248 | if door_shuffle == ShuffleDoors.option_none: |
248 | chosen_exits = [painting_id for painting_id, painting in PAINTINGS.items() | 249 | required_painting_rooms += REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS |
249 | if painting.required_when_no_doors] | 250 | req_exits = [painting_id for painting_id, painting in PAINTINGS.items() if painting.required_when_no_doors] |
250 | chosen_exits += [painting_id for painting_id, painting in PAINTINGS.items() | 251 | req_enterable = [painting_id for painting_id, painting in PAINTINGS.items() |
251 | if painting.exit_only and painting.required] | 252 | if not painting.exit_only and not painting.disable and not painting.req_blocked and |
253 | not painting.req_blocked_when_no_doors and painting.room not in required_painting_rooms] | ||
254 | else: | ||
255 | req_enterable = [painting_id for painting_id, painting in PAINTINGS.items() | ||
256 | if not painting.exit_only and not painting.disable and not painting.req_blocked and | ||
257 | painting.room not in required_painting_rooms] | ||
258 | req_exits += [painting_id for painting_id, painting in PAINTINGS.items() | ||
259 | if painting.exit_only and painting.required] | ||
260 | req_entrances = world.random.sample(req_enterable, len(req_exits)) | ||
261 | |||
262 | self.PAINTING_MAPPING = dict(zip(req_entrances, req_exits)) | ||
263 | |||
264 | # Next, determine the rest of the exit paintings. | ||
252 | exitable = [painting_id for painting_id, painting in PAINTINGS.items() | 265 | exitable = [painting_id for painting_id, painting in PAINTINGS.items() |
253 | if not painting.enter_only and not painting.disable and not painting.required] | 266 | if not painting.enter_only and not painting.disable and painting_id not in req_exits and |
254 | chosen_exits += world.random.sample(exitable, PAINTING_EXITS - len(chosen_exits)) | 267 | painting_id not in req_entrances] |
268 | nonreq_exits = world.random.sample(exitable, PAINTING_EXITS - len(req_exits)) | ||
269 | chosen_exits = req_exits + nonreq_exits | ||
255 | 270 | ||
256 | # Determine the set of entrance paintings. | 271 | # Determine the rest of the entrance paintings. |
257 | enterable = [painting_id for painting_id, painting in PAINTINGS.items() | 272 | enterable = [painting_id for painting_id, painting in PAINTINGS.items() |
258 | if not painting.exit_only and not painting.disable and painting_id not in chosen_exits] | 273 | if not painting.exit_only and not painting.disable and painting_id not in chosen_exits and |
259 | chosen_entrances = world.random.sample(enterable, PAINTING_ENTRANCES) | 274 | painting_id not in req_entrances] |
275 | chosen_entrances = world.random.sample(enterable, PAINTING_ENTRANCES - len(req_entrances)) | ||
260 | 276 | ||
261 | # Create a mapping from entrances to exits. | 277 | # Assign one entrance to each non-required exit, to ensure that the total number of exits is achieved. |
262 | for warp_exit in chosen_exits: | 278 | for warp_exit in nonreq_exits: |
263 | warp_enter = world.random.choice(chosen_entrances) | 279 | warp_enter = world.random.choice(chosen_entrances) |
264 | |||
265 | # Check whether this is a warp from a required painting room to another (or the same) required painting | ||
266 | # room. This could cause a cycle that would make certain regions inaccessible. | ||
267 | warp_exit_room = PAINTINGS[warp_exit].room | ||
268 | warp_enter_room = PAINTINGS[warp_enter].room | ||
269 | |||
270 | required_painting_rooms = REQUIRED_PAINTING_ROOMS | ||
271 | if door_shuffle == ShuffleDoors.option_none: | ||
272 | required_painting_rooms += REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS | ||
273 | |||
274 | if warp_exit_room in required_painting_rooms and warp_enter_room in required_painting_rooms: | ||
275 | # This shuffling is non-workable. Start over. | ||
276 | return False | ||
277 | |||
278 | chosen_entrances.remove(warp_enter) | 280 | chosen_entrances.remove(warp_enter) |
279 | self.PAINTING_MAPPING[warp_enter] = warp_exit | 281 | self.PAINTING_MAPPING[warp_enter] = warp_exit |
280 | 282 | ||
283 | # Assign each of the remaining entrances to any required or non-required exit. | ||
281 | for warp_enter in chosen_entrances: | 284 | for warp_enter in chosen_entrances: |
282 | warp_exit = world.random.choice(chosen_exits) | 285 | warp_exit = world.random.choice(chosen_exits) |
283 | self.PAINTING_MAPPING[warp_enter] = warp_exit | 286 | self.PAINTING_MAPPING[warp_enter] = warp_exit |
@@ -292,7 +295,8 @@ class LingoPlayerLogic: | |||
292 | # Just for sanity's sake, ensure that all required painting rooms are accessed. | 295 | # Just for sanity's sake, ensure that all required painting rooms are accessed. |
293 | for painting_id, painting in PAINTINGS.items(): | 296 | for painting_id, painting in PAINTINGS.items(): |
294 | if painting_id not in self.PAINTING_MAPPING.values() \ | 297 | if painting_id not in self.PAINTING_MAPPING.values() \ |
295 | and (painting.required or (painting.required_when_no_doors and door_shuffle == 0)): | 298 | and (painting.required or (painting.required_when_no_doors and |
299 | door_shuffle == ShuffleDoors.option_none)): | ||
296 | return False | 300 | return False |
297 | 301 | ||
298 | return True | 302 | return True |