Stardew Valley: simplify in-place (#2393)

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
This commit is contained in:
black-sliver 2023-10-29 13:20:28 +01:00 committed by GitHub
parent ff65de1464
commit d9b076a687
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 47 deletions

View File

@ -88,6 +88,7 @@ assert true_ is True_()
class Or(StardewRule): class Or(StardewRule):
rules: FrozenSet[StardewRule] rules: FrozenSet[StardewRule]
_simplified: bool
def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
rules_list: Set[StardewRule] rules_list: Set[StardewRule]
@ -112,6 +113,7 @@ class Or(StardewRule):
rules_list = new_rules rules_list = new_rules
self.rules = frozenset(rules_list) self.rules = frozenset(rules_list)
self._simplified = False
def __call__(self, state: CollectionState) -> bool: def __call__(self, state: CollectionState) -> bool:
return any(rule(state) for rule in self.rules) return any(rule(state) for rule in self.rules)
@ -139,6 +141,8 @@ class Or(StardewRule):
return min(rule.get_difficulty() for rule in self.rules) return min(rule.get_difficulty() for rule in self.rules)
def simplify(self) -> StardewRule: def simplify(self) -> StardewRule:
if self._simplified:
return self
if true_ in self.rules: if true_ in self.rules:
return true_ return true_
@ -151,11 +155,14 @@ class Or(StardewRule):
if len(simplified_rules) == 1: if len(simplified_rules) == 1:
return simplified_rules[0] return simplified_rules[0]
return Or(simplified_rules) self.rules = frozenset(simplified_rules)
self._simplified = True
return self
class And(StardewRule): class And(StardewRule):
rules: FrozenSet[StardewRule] rules: FrozenSet[StardewRule]
_simplified: bool
def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
rules_list: Set[StardewRule] rules_list: Set[StardewRule]
@ -180,6 +187,7 @@ class And(StardewRule):
rules_list = new_rules rules_list = new_rules
self.rules = frozenset(rules_list) self.rules = frozenset(rules_list)
self._simplified = False
def __call__(self, state: CollectionState) -> bool: def __call__(self, state: CollectionState) -> bool:
return all(rule(state) for rule in self.rules) return all(rule(state) for rule in self.rules)
@ -207,6 +215,8 @@ class And(StardewRule):
return max(rule.get_difficulty() for rule in self.rules) return max(rule.get_difficulty() for rule in self.rules)
def simplify(self) -> StardewRule: def simplify(self) -> StardewRule:
if self._simplified:
return self
if false_ in self.rules: if false_ in self.rules:
return false_ return false_
@ -219,7 +229,9 @@ class And(StardewRule):
if len(simplified_rules) == 1: if len(simplified_rules) == 1:
return simplified_rules[0] return simplified_rules[0]
return And(simplified_rules) self.rules = frozenset(simplified_rules)
self._simplified = True
return self
class Count(StardewRule): class Count(StardewRule):

View File

@ -1,56 +1,57 @@
import unittest
from .. import True_ from .. import True_
from ..logic import Received, Has, False_, And, Or from ..logic import Received, Has, False_, And, Or
def test_simplify_true_in_and(): class TestSimplification(unittest.TestCase):
rules = { def test_simplify_true_in_and(self):
"Wood": True_(), rules = {
"Rock": True_(), "Wood": True_(),
} "Rock": True_(),
summer = Received("Summer", 0, 1) }
assert (Has("Wood", rules) & summer & Has("Rock", rules)).simplify() == summer 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_false_in_or(): def test_simplify_and_in_and(self):
rules = { rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)),
"Wood": False_(), And(Received('Winter', 0, 1), Received('Spring', 0, 1)))
"Rock": False_(), self.assertEqual(rule.simplify(),
} And(Received('Summer', 0, 1), Received('Fall', 0, 1),
summer = Received("Summer", 0, 1) Received('Winter', 0, 1), Received('Spring', 0, 1)))
assert (Has("Wood", rules) | summer | Has("Rock", rules)).simplify() == summer
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_and_in_and(): def test_simplify_or_in_or(self):
rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule = Or(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)),
And(Received('Winter', 0, 1), Received('Spring', 0, 1))) Or(Received('Winter', 0, 1), Received('Spring', 0, 1)))
assert rule.simplify() == And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), self.assertEqual(rule.simplify(),
Received('Spring', 0, 1)) 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_duplicated_and(): def test_simplify_true_in_or(self):
rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule = Or(True_(), Received('Summer', 0, 1))
And(Received('Summer', 0, 1), Received('Fall', 0, 1))) self.assertEqual(rule.simplify(), True_())
assert rule.simplify() == And(Received('Summer', 0, 1), Received('Fall', 0, 1))
def test_simplify_false_in_and(self):
def test_simplify_or_in_or(): rule = And(False_(), Received('Summer', 0, 1))
rule = Or(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)), self.assertEqual(rule.simplify(), False_())
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_()