Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Witness: Fix Tunnels Theater Flower EP Access Logic + Add Unit Test for it (and Expert PP2) #3807

Merged
merged 6 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 18 additions & 32 deletions worlds/witness/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ def _can_do_expert_pp2(state: CollectionState, world: "WitnessWorld") -> bool:
"""

player = world.player
player_regions = world.player_regions
two_way_entrance_register = world.player_regions.two_way_entrance_register

front_access = (
any(e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 2nd Pressure Plate", "Keep"])
any(e.can_reach(state) for e in two_way_entrance_register["Keep 2nd Pressure Plate", "Keep"])
and state.can_reach_region("Keep", player)
)

Expand All @@ -88,7 +88,7 @@ def _can_do_expert_pp2(state: CollectionState, world: "WitnessWorld") -> bool:
# Front access works. Now, we need to check for the many ways to access PP2 from the back.
# All of those ways lead through the PP3 exit door from PP4. So we check this first.

fourth_to_third = any(e.can_reach(state) for e in player_regions.two_way_entrance_register[
fourth_to_third = any(e.can_reach(state) for e in two_way_entrance_register[
"Keep 3rd Pressure Plate", "Keep 4th Pressure Plate"
])

Expand All @@ -100,17 +100,15 @@ def _can_do_expert_pp2(state: CollectionState, world: "WitnessWorld") -> bool:
# The shadows shortcut is the simplest way.

shadows_shortcut = (
any(e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 4th Pressure Plate", "Shadows"])
any(e.can_reach(state) for e in two_way_entrance_register["Keep 4th Pressure Plate", "Shadows"])
)

if shadows_shortcut:
return True

# We don't have the Shadows shortcut. This means we need to come in through the PP4 exit door instead.

tower_to_pp4 = any(
e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 4th Pressure Plate", "Keep Tower"]
)
tower_to_pp4 = any(e.can_reach(state) for e in two_way_entrance_register["Keep 4th Pressure Plate", "Keep Tower"])

# If we don't have the PP4 exit door, we've run out of options.
if not tower_to_pp4:
Expand All @@ -119,7 +117,7 @@ def _can_do_expert_pp2(state: CollectionState, world: "WitnessWorld") -> bool:
# We have the PP4 exit door. If we can get to Keep Tower from behind, we can do PP2.
# The simplest way would be the Tower Shortcut.

tower_shortcut = any(e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep", "Keep Tower"])
tower_shortcut = any(e.can_reach(state) for e in two_way_entrance_register["Keep", "Keep Tower"])

if tower_shortcut:
return True
Expand All @@ -128,56 +126,44 @@ def _can_do_expert_pp2(state: CollectionState, world: "WitnessWorld") -> bool:
# Getting to Keep Tower through the hedge mazes. This can be done in a multitude of ways.
# No matter what, though, we would need Hedge Maze 4 Exit to Keep Tower.

tower_access_from_hedges = any(
e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 4th Maze", "Keep Tower"]
)
tower_access_from_hedges = any(e.can_reach(state) for e in two_way_entrance_register["Keep 4th Maze", "Keep Tower"])

if not tower_access_from_hedges:
return False

# We can reach Keep Tower from Hedge Maze 4. If we now have the Hedge 4 Shortcut, we are immediately good.

hedge_4_shortcut = any(
e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 4th Maze", "Keep"]
)
hedge_4_shortcut = any(e.can_reach(state) for e in two_way_entrance_register["Keep 4th Maze", "Keep"])

# If we have the hedge 4 shortcut, that works.
if hedge_4_shortcut:
return True

# We don't have the hedge 4 shortcut. This means we would now need to come through Hedge Maze 3.

hedge_3_to_4 = any(
e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 4th Maze", "Keep 3rd Maze"]
)
hedge_3_to_4 = any(e.can_reach(state) for e in two_way_entrance_register["Keep 4th Maze", "Keep 3rd Maze"])

if not hedge_3_to_4:
return False

# We can get to Hedge 4 from Hedge 3. If we have the Hedge 3 Shortcut, we're good.

hedge_3_shortcut = any(
e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 3rd Maze", "Keep"]
)
hedge_3_shortcut = any(e.can_reach(state) for e in two_way_entrance_register["Keep 3rd Maze", "Keep"])

if hedge_3_shortcut:
return True

# We don't have Hedge 3 Shortcut. This means we would now need to come through Hedge Maze 2.

hedge_2_to_3 = any(
e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 3rd Maze", "Keep 2nd Maze"]
)
hedge_2_to_3 = any(e.can_reach(state) for e in two_way_entrance_register["Keep 3rd Maze", "Keep 2nd Maze"])

if not hedge_2_to_3:
return False

# We can get to Hedge 3 from Hedge 2. If we can get from Keep to Hedge 2, we're good.
# This covers both Hedge 1 Exit and Hedge 2 Shortcut, because Hedge 1 is just part of the Keep region.

return any(
e.can_reach(state) for e in player_regions.two_way_entrance_register["Keep 2nd Maze", "Keep"]
)
return any(e.can_reach(state) for e in two_way_entrance_register["Keep 2nd Maze", "Keep"])


def _can_do_theater_to_tunnels(state: CollectionState, world: "WitnessWorld") -> bool:
Expand All @@ -189,11 +175,11 @@ def _can_do_theater_to_tunnels(state: CollectionState, world: "WitnessWorld") ->
# Checking for access to Theater is not necessary, as solvability of Tutorial Video is checked in the other half
# of the Theater Flowers EP condition.

player_regions = world.player_regions
two_way_entrance_register = world.player_regions.two_way_entrance_register

direct_access = (
any(e.can_reach(state) for e in player_regions.two_way_entrance_register["Tunnels", "Windmill Interior"])
and any(e.can_reach(state) for e in player_regions.two_way_entrance_register["Theater", "Windmill Interior"])
any(e.can_reach(state) for e in two_way_entrance_register["Tunnels", "Windmill Interior"])
and any(e.can_reach(state) for e in two_way_entrance_register["Theater", "Windmill Interior"])
)

if direct_access:
Expand All @@ -210,9 +196,9 @@ def _can_do_theater_to_tunnels(state: CollectionState, world: "WitnessWorld") ->
# We also need a way from Town to Tunnels.

return (
any(e.can_reach(state) for e in player_regions.two_way_entrance_register["Tunnels", "Windmill Interior"])
and any(e.can_reach(state) for e in player_regions.two_way_entrance_register["Town", "Windmill Interior"])
or any(e.can_reach(state) for e in player_regions.two_way_entrance_register["Tunnels", "Town"])
any(e.can_reach(state) for e in two_way_entrance_register["Tunnels", "Windmill Interior"])
and any(e.can_reach(state) for e in two_way_entrance_register["Outside Windmill", "Windmill Interior"])
or any(e.can_reach(state) for e in two_way_entrance_register["Tunnels", "Town"])
)


Expand Down
66 changes: 66 additions & 0 deletions worlds/witness/test/test_weird_traversals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from ..test import WitnessTestBase


class TestWeirdTraversalRequirements(WitnessTestBase):
options = {
"shuffle_vault_boxes": True,
"shuffle_symbols": False,
"shuffle_EPs": "individual",
"EP_difficulty": "tedious",
"shuffle_doors": "doors",
"door_groupings": "off",
"puzzle_randomization": "sigma_expert",
}

def test_weird_traversal_requirements(self) -> None:
"""
Test that Tunnels Theater Flowers EP and Expert PP2 consider all valid paths logically.
"""

with self.subTest("Tunnels Theater Flowers EP"):
self.assertAccessDependency(
["Tunnels Theater Flowers EP"],
[
["Theater Exit Left (Door)", "Windmill Entry (Door)", "Tunnels Theater Shortcut (Door)"],
["Theater Exit Right (Door)", "Windmill Entry (Door)", "Tunnels Theater Shortcut (Door)"],
["Theater Exit Left (Door)", "Tunnels Town Shortcut (Door)"],
["Theater Exit Right (Door)", "Tunnels Town Shortcut (Door)"],
["Theater Entry (Door)", "Tunnels Theater Shortcut (Door)"],
["Theater Entry (Door)", "Windmill Entry (Door)", "Tunnels Town Shortcut (Door)"],
],
only_check_listed=True,
)

with self.subTest("Expert Keep Pressure Plates 2"):
# Always necessary
self.assertAccessDependency(
["Keep Pressure Plates 2"],
[["Keep Pressure Plates 1 Exit (Door)"]],
only_check_listed=True,
)

# Always necessary
self.assertAccessDependency(
["Keep Pressure Plates 2"],
[["Keep Pressure Plates 3 Exit (Door)"]],
only_check_listed=True,
)

# All the possible "Exit methods" from PP3
self.assertAccessDependency(
["Keep Pressure Plates 2"],
[
["Keep Shadows Shortcut (Door)"],
["Keep Pressure Plates 4 Exit (Door)", "Keep Tower Shortcut (Door)"],
["Keep Pressure Plates 4 Exit (Door)", "Keep Hedge Maze 4 Exit (Door)",
"Keep Hedge Maze 4 Shortcut (Door)"],
["Keep Pressure Plates 4 Exit (Door)", "Keep Hedge Maze 4 Exit (Door)",
"Keep Hedge Maze 3 Exit (Door)", "Keep Hedge Maze 3 Shortcut (Door)"],
["Keep Pressure Plates 4 Exit (Door)", "Keep Hedge Maze 4 Exit (Door)",
"Keep Hedge Maze 3 Exit (Door)", "Keep Hedge Maze 2 Exit (Door)",
"Keep Hedge Maze 2 Shortcut (Door)"],
["Keep Pressure Plates 4 Exit (Door)", "Keep Hedge Maze 4 Exit (Door)",
"Keep Hedge Maze 3 Exit (Door)", "Keep Hedge Maze 2 Exit (Door)", "Keep Hedge Maze 1 Exit (Door)"],
],
only_check_listed=True,
)
Loading