mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
The Witness: Automatic Postgame & Disabled Panels Calculation (#2698)
* Refactor postgame code to be more readable * Change all references to options to strings * oops * Fix some outdated code related to yaml-disabled EPs * Small fixes to short/longbox stuff (thanks Medic) * comment * fix duplicate * Removed triplicate lmfao * Better comment * added another 'unfun' postgame consideration * comment * more option strings * oops * Remove an unnecessary comparison * another string missed * New classification changes (Credit: Exempt-Medic) * Don't need to pass world * Comments * Replace it with another magic system because why not at this point :DDDDDD * oops * Oops * Another was missed * Make events conditions. Disable_Non_Randomized will no longer just 'have all events' * What the fuck? Has this just always been broken? * Don't have boolean function with 'not' in the name * Another useful classification * slight code refactor * Funny haha booleans * This would create a really bad merge error * I can't believe this actually kind of works * And here's the punchline. + some bugfixes * Comment dat code * Comments galore * LMAO OOPS * so nice I did it twice * debug x2 * Careful * Add more comments * That comment is a bit unnecessary now * Fix overriding region connections * Correct a comment * Correct again * Rename variable * Idk I guess this is in this branch now * More tweaking of postgame & comments * This is commit just exists to fix that grammar error * I think I can just fucking delete this now??? * Forgot to reset something here * Delete dead codepath * Obelisk Keys were getting yote erroneously * More comments * Fix duplicate connections * Oopsington III * performance improvements & cleanup * More rules cleanup and performance improvements * Oh cool I can do this huh * Okay but this is even more swag tho * Lazy eval * remove some implicit checks * Is this too magical yet * more guard magic * Maaaaaaaagiccccccccc * Laaaaaaaaaaaaaaaazzzzzzyyyyyyyyyyy * Make it docstring * Newline bc I like that better * this is a little spooky lol * lol * Wait * spoO * Better variable name and comment * Improved comment again * better API * oops I deleted a deepcopy * lol help * Help??? * player_regionsns lmao * Add some comments * Make doors disabled properly again. I hope this works * Don't disable lasers * Omega oops * Make Floor 2 Exit not exist * Make a fix that's warps compatible * I think this was an oversight, I tested a seed and it seems to have the same result * This is definitely less Violet than before * Does this feel more violet lol * Exception if a laser gets disabled, cleanup * Ruff * >:( * consistent utils import * Make autopostgame more reviewable (hopefully) * more reviewability * WitnessRule * replace another instance of it * lint * style * comment * found the bug * Move comment * Get rid of cache and ugly allow_victory * comments and lint
This commit is contained in:
@@ -2,7 +2,14 @@ from functools import lru_cache
|
||||
from math import floor
|
||||
from pkgutil import get_data
|
||||
from random import random
|
||||
from typing import Any, Collection, Dict, FrozenSet, List, Set, Tuple
|
||||
from typing import Any, Collection, Dict, FrozenSet, Iterable, List, Set, Tuple
|
||||
|
||||
# A WitnessRule is just an or-chain of and-conditions.
|
||||
# It represents the set of all options that could fulfill this requirement.
|
||||
# E.g. if something requires "Dots or (Shapers and Stars)", it'd be represented as: {{"Dots"}, {"Shapers, "Stars"}}
|
||||
# {} is an unusable requirement.
|
||||
# {{}} is an always usable requirement.
|
||||
WitnessRule = FrozenSet[FrozenSet[str]]
|
||||
|
||||
|
||||
def weighted_sample(world_random: random, population: List, weights: List[float], k: int) -> List:
|
||||
@@ -48,7 +55,7 @@ def build_weighted_int_list(inputs: Collection[float], total: int) -> List[int]:
|
||||
return rounded_output
|
||||
|
||||
|
||||
def define_new_region(region_string: str) -> Tuple[Dict[str, Any], Set[Tuple[str, FrozenSet[FrozenSet[str]]]]]:
|
||||
def define_new_region(region_string: str) -> Tuple[Dict[str, Any], Set[Tuple[str, WitnessRule]]]:
|
||||
"""
|
||||
Returns a region object by parsing a line in the logic file
|
||||
"""
|
||||
@@ -76,12 +83,13 @@ def define_new_region(region_string: str) -> Tuple[Dict[str, Any], Set[Tuple[str
|
||||
region_obj = {
|
||||
"name": region_name,
|
||||
"shortName": region_name_simple,
|
||||
"panels": list()
|
||||
"entities": list(),
|
||||
"physical_entities": list(),
|
||||
}
|
||||
return region_obj, options
|
||||
|
||||
|
||||
def parse_lambda(lambda_string) -> FrozenSet[FrozenSet[str]]:
|
||||
def parse_lambda(lambda_string) -> WitnessRule:
|
||||
"""
|
||||
Turns a lambda String literal like this: a | b & c
|
||||
into a set of sets like this: {{a}, {b, c}}
|
||||
@@ -181,36 +189,8 @@ def get_discard_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Exclusions/Discards.txt")
|
||||
|
||||
|
||||
def get_caves_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Postgame/Caves.txt")
|
||||
|
||||
|
||||
def get_beyond_challenge_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Postgame/Beyond_Challenge.txt")
|
||||
|
||||
|
||||
def get_bottom_floor_discard_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Postgame/Bottom_Floor_Discard.txt")
|
||||
|
||||
|
||||
def get_bottom_floor_discard_nondoors_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Postgame/Bottom_Floor_Discard_NonDoors.txt")
|
||||
|
||||
|
||||
def get_mountain_upper_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Postgame/Mountain_Upper.txt")
|
||||
|
||||
|
||||
def get_challenge_vault_box_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Postgame/Challenge_Vault_Box.txt")
|
||||
|
||||
|
||||
def get_path_to_challenge_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Postgame/Path_To_Challenge.txt")
|
||||
|
||||
|
||||
def get_mountain_lower_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Postgame/Mountain_Lower.txt")
|
||||
def get_caves_except_path_to_challenge_exclusion_list() -> List[str]:
|
||||
return get_adjustment_file("settings/Exclusions/Caves_Except_Path_To_Challenge.txt")
|
||||
|
||||
|
||||
def get_elevators_come_to_you() -> List[str]:
|
||||
@@ -233,21 +213,21 @@ def get_items() -> List[str]:
|
||||
return get_adjustment_file("WitnessItems.txt")
|
||||
|
||||
|
||||
def dnf_remove_redundancies(dnf_requirement: FrozenSet[FrozenSet[str]]) -> FrozenSet[FrozenSet[str]]:
|
||||
def optimize_witness_rule(witness_rule: WitnessRule) -> WitnessRule:
|
||||
"""Removes any redundant terms from a logical formula in disjunctive normal form.
|
||||
This means removing any terms that are a superset of any other term get removed.
|
||||
This is possible because of the boolean absorption law: a | (a & b) = a"""
|
||||
to_remove = set()
|
||||
|
||||
for option1 in dnf_requirement:
|
||||
for option2 in dnf_requirement:
|
||||
for option1 in witness_rule:
|
||||
for option2 in witness_rule:
|
||||
if option2 < option1:
|
||||
to_remove.add(option1)
|
||||
|
||||
return dnf_requirement - to_remove
|
||||
return witness_rule - to_remove
|
||||
|
||||
|
||||
def dnf_and(dnf_requirements: List[FrozenSet[FrozenSet[str]]]) -> FrozenSet[FrozenSet[str]]:
|
||||
def logical_and_witness_rules(witness_rules: Iterable[WitnessRule]) -> WitnessRule:
|
||||
"""
|
||||
performs the "and" operator on a list of logical formula in disjunctive normal form, represented as a set of sets.
|
||||
A logical formula might look like this: {{a, b}, {c, d}}, which would mean "a & b | c & d".
|
||||
@@ -255,7 +235,7 @@ def dnf_and(dnf_requirements: List[FrozenSet[FrozenSet[str]]]) -> FrozenSet[Froz
|
||||
"""
|
||||
current_overall_requirement = frozenset({frozenset()})
|
||||
|
||||
for next_dnf_requirement in dnf_requirements:
|
||||
for next_dnf_requirement in witness_rules:
|
||||
new_requirement: Set[FrozenSet[str]] = set()
|
||||
|
||||
for option1 in current_overall_requirement:
|
||||
@@ -264,4 +244,8 @@ def dnf_and(dnf_requirements: List[FrozenSet[FrozenSet[str]]]) -> FrozenSet[Froz
|
||||
|
||||
current_overall_requirement = frozenset(new_requirement)
|
||||
|
||||
return dnf_remove_redundancies(current_overall_requirement)
|
||||
return optimize_witness_rule(current_overall_requirement)
|
||||
|
||||
|
||||
def logical_or_witness_rules(witness_rules: Iterable[WitnessRule]) -> WitnessRule:
|
||||
return optimize_witness_rule(frozenset.union(*witness_rules))
|
||||
|
||||
Reference in New Issue
Block a user