Skip to content

Commit

Permalink
Stardew Valley: simplify in-place (ArchipelagoMW#2393)
Browse files Browse the repository at this point in the history
this allows skipping multiple simplifications of the same object, e.g. item_rules
also update the logic simplification tests to be a proper unittest.TestCase
  • Loading branch information
black-sliver authored and Jouramie committed Feb 28, 2024
1 parent 9e140f6 commit a64dd4f
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 54 deletions.
16 changes: 14 additions & 2 deletions worlds/stardew_valley/stardew_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def get_difficulty(self):

class Or(StardewRule):
rules: FrozenSet[StardewRule]
_simplified: bool

def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
rules_list: Set[StardewRule]
Expand All @@ -112,6 +113,7 @@ def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: Star
rules_list = new_rules

self.rules = frozenset(rules_list)
self._simplified = False

def __call__(self, state: CollectionState) -> bool:
return any(rule(state) for rule in self.rules)
Expand Down Expand Up @@ -139,6 +141,8 @@ def get_difficulty(self):
return min(rule.get_difficulty() for rule in self.rules)

def simplify(self) -> StardewRule:
if self._simplified:
return self
if true_ in self.rules:
return true_

Expand All @@ -151,11 +155,14 @@ def simplify(self) -> StardewRule:
if len(simplified_rules) == 1:
return simplified_rules[0]

return Or(simplified_rules)
self.rules = frozenset(simplified_rules)
self._simplified = True
return self


class And(StardewRule):
rules: FrozenSet[StardewRule]
_simplified: bool

def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
rules_list: Set[StardewRule]
Expand All @@ -180,6 +187,7 @@ def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: Star
rules_list = new_rules

self.rules = frozenset(rules_list)
self._simplified = False

def __call__(self, state: CollectionState) -> bool:
return all(rule(state) for rule in self.rules)
Expand Down Expand Up @@ -207,6 +215,8 @@ def get_difficulty(self):
return max(rule.get_difficulty() for rule in self.rules)

def simplify(self) -> StardewRule:
if self._simplified:
return self
if false_ in self.rules:
return false_

Expand All @@ -219,7 +229,9 @@ def simplify(self) -> StardewRule:
if len(simplified_rules) == 1:
return simplified_rules[0]

return And(simplified_rules)
self.rules = frozenset(simplified_rules)
self._simplified = True
return self


class Count(StardewRule):
Expand Down
105 changes: 53 additions & 52 deletions worlds/stardew_valley/test/TestLogicSimplification.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,57 @@
import unittest
from .. import True_
from ..logic import Received, Has, False_, And, Or


def test_simplify_true_in_and():
rules = {
"Wood": True_(),
"Rock": True_(),
}
summer = Received("Summer", 0, 1)
assert (Has("Wood", rules) & summer & Has("Rock", rules)).simplify() == summer


def test_simplify_false_in_or():
rules = {
"Wood": False_(),
"Rock": False_(),
}
summer = Received("Summer", 0, 1)
assert (Has("Wood", rules) | summer | Has("Rock", rules)).simplify() == summer


def test_simplify_and_in_and():
rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)),
And(Received('Winter', 0, 1), Received('Spring', 0, 1)))
assert rule.simplify() == And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1),
Received('Spring', 0, 1))


def test_simplify_duplicated_and():
rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)),
And(Received('Summer', 0, 1), Received('Fall', 0, 1)))
assert rule.simplify() == And(Received('Summer', 0, 1), Received('Fall', 0, 1))


def test_simplify_or_in_or():
rule = Or(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)),
Or(Received('Winter', 0, 1), Received('Spring', 0, 1)))
assert rule.simplify() == Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1),
Received('Spring', 0, 1))


def test_simplify_duplicated_or():
rule = And(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)),
Or(Received('Summer', 0, 1), Received('Fall', 0, 1)))
assert rule.simplify() == Or(Received('Summer', 0, 1), Received('Fall', 0, 1))


def test_simplify_true_in_or():
rule = Or(True_(), Received('Summer', 0, 1))
assert rule.simplify() == True_()


def test_simplify_false_in_and():
rule = And(False_(), Received('Summer', 0, 1))
assert rule.simplify() == False_()
class TestSimplification(unittest.TestCase):
def test_simplify_true_in_and(self):
rules = {
"Wood": True_(),
"Rock": True_(),
}
summer = Received("Summer", 0, 1)
self.assertEqual((Has("Wood", rules) & summer & Has("Rock", rules)).simplify(),
summer)

def test_simplify_false_in_or(self):
rules = {
"Wood": False_(),
"Rock": False_(),
}
summer = Received("Summer", 0, 1)
self.assertEqual((Has("Wood", rules) | summer | Has("Rock", rules)).simplify(),
summer)

def test_simplify_and_in_and(self):
rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)),
And(Received('Winter', 0, 1), Received('Spring', 0, 1)))
self.assertEqual(rule.simplify(),
And(Received('Summer', 0, 1), Received('Fall', 0, 1),
Received('Winter', 0, 1), Received('Spring', 0, 1)))

def test_simplify_duplicated_and(self):
rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)),
And(Received('Summer', 0, 1), Received('Fall', 0, 1)))
self.assertEqual(rule.simplify(),
And(Received('Summer', 0, 1), Received('Fall', 0, 1)))

def test_simplify_or_in_or(self):
rule = Or(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)),
Or(Received('Winter', 0, 1), Received('Spring', 0, 1)))
self.assertEqual(rule.simplify(),
Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1),
Received('Spring', 0, 1)))

def test_simplify_duplicated_or(self):
rule = And(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)),
Or(Received('Summer', 0, 1), Received('Fall', 0, 1)))
self.assertEqual(rule.simplify(),
Or(Received('Summer', 0, 1), Received('Fall', 0, 1)))

def test_simplify_true_in_or(self):
rule = Or(True_(), Received('Summer', 0, 1))
self.assertEqual(rule.simplify(), True_())

def test_simplify_false_in_and(self):
rule = And(False_(), Received('Summer', 0, 1))
self.assertEqual(rule.simplify(), False_())

0 comments on commit a64dd4f

Please sign in to comment.