Stardew Valley: Make sure number of month in time logic is a int to improve performance by ~20% (#3665)

* make sure number of month is actually a int

* improve rule explain like in pr

* remove redundant if in can_complete_bundle

* assert number is int so cache is not bloated
This commit is contained in:
Jérémie Bolduc 2024-07-20 15:24:24 -04:00 committed by GitHub
parent e33a9991ef
commit 34e7748f23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 38 additions and 9 deletions

View File

@ -27,8 +27,8 @@ class BundleLogicMixin(BaseLogicMixin):
self.bundle = BundleLogic(*args, **kwargs)
class BundleLogic(BaseLogic[Union[ReceivedLogicMixin, HasLogicMixin, TimeLogicMixin, RegionLogicMixin, MoneyLogicMixin, QualityLogicMixin, FishingLogicMixin, SkillLogicMixin,
QuestLogicMixin]]):
class BundleLogic(BaseLogic[Union[ReceivedLogicMixin, HasLogicMixin, TimeLogicMixin, RegionLogicMixin, MoneyLogicMixin, QualityLogicMixin, FishingLogicMixin,
SkillLogicMixin, QuestLogicMixin]]):
# Should be cached
def can_complete_bundle(self, bundle: Bundle) -> StardewRule:
item_rules = []
@ -45,7 +45,7 @@ QuestLogicMixin]]):
qualities.append(bundle_item.quality)
quality_rules = self.get_quality_rules(qualities)
item_rules = self.logic.has_n(*item_rules, count=bundle.number_required)
time_rule = True_() if time_to_grind <= 0 else self.logic.time.has_lived_months(time_to_grind)
time_rule = self.logic.time.has_lived_months(time_to_grind)
return can_speak_junimo & item_rules & quality_rules & time_rule
def get_quality_rules(self, qualities: List[str]) -> StardewRule:

View File

@ -41,7 +41,7 @@ class MuseumLogic(BaseLogic[Union[ReceivedLogicMixin, HasLogicMixin, TimeLogicMi
else:
geodes_rule = False_()
# monster_rule = self.can_farm_monster(item.monsters)
time_needed_to_grind = (20 - item.difficulty) / 2
time_needed_to_grind = int((20 - item.difficulty) // 2)
time_rule = self.logic.time.has_lived_months(time_needed_to_grind)
pan_rule = False_()
if item.item_name == Mineral.earth_crystal or item.item_name == Mineral.fire_quartz or item.item_name == Mineral.frozen_tear:

View File

@ -26,8 +26,10 @@ class TimeLogic(BaseLogic[Union[TimeLogicMixin, HasLogicMixin]]):
@cache_self1
def has_lived_months(self, number: int) -> StardewRule:
assert isinstance(number, int), "Can't have lived a fraction of a month. Use // instead of / when dividing."
if number <= 0:
return self.logic.true_
number = min(number, MAX_MONTHS)
return HasProgressionPercent(self.player, number * MONTH_COEFFICIENT)

View File

@ -431,7 +431,7 @@ class Count(BaseStardewRule):
return len(self.rules)
def __repr__(self):
return f"Received {self.count} {repr(self.rules)}"
return f"Received {self.count} [{', '.join(f'{value}x {repr(rule)}' for rule, value in self.counter.items())}]"
@dataclass(frozen=True)

View File

@ -34,7 +34,7 @@ class RuleExplanation:
if not self.sub_rules:
return self.summary(depth)
return self.summary(depth) + "\n" + "\n".join(RuleExplanation.__str__(i, depth + 1)
return self.summary(depth) + "\n" + "\n".join(i.__str__(depth + 1)
if i.result is not self.expected else i.summary(depth + 1)
for i in sorted(self.explained_sub_rules, key=lambda x: x.result))
@ -42,7 +42,7 @@ class RuleExplanation:
if not self.sub_rules:
return self.summary(depth)
return self.summary(depth) + "\n" + "\n".join(RuleExplanation.__repr__(i, depth + 1)
return self.summary(depth) + "\n" + "\n".join(i.__repr__(depth + 1)
for i in sorted(self.explained_sub_rules, key=lambda x: x.result))
@cached_property
@ -61,6 +61,33 @@ class RuleExplanation:
return [_explain(i, self.state, self.expected, self.explored_rules_key) for i in self.sub_rules]
@dataclass
class CountSubRuleExplanation(RuleExplanation):
count: int = 1
@staticmethod
def from_explanation(expl: RuleExplanation, count: int) -> CountSubRuleExplanation:
return CountSubRuleExplanation(expl.rule, expl.state, expl.expected, expl.sub_rules, expl.explored_rules_key, expl.current_rule_explored, count)
def summary(self, depth=0) -> str:
summary = " " * depth + f"{self.count}x {str(self.rule)} -> {self.result}"
if self.current_rule_explored:
summary += " [Already explained]"
return summary
@dataclass
class CountExplanation(RuleExplanation):
rule: Count
@cached_property
def explained_sub_rules(self) -> List[RuleExplanation]:
return [
CountSubRuleExplanation.from_explanation(_explain(rule, self.state, self.expected, self.explored_rules_key), count)
for rule, count in self.rule.counter.items()
]
def explain(rule: CollectionRule, state: CollectionState, expected: bool = True) -> RuleExplanation:
if isinstance(rule, StardewRule):
return _explain(rule, state, expected, explored_spots=set())
@ -80,7 +107,7 @@ def _(rule: AggregatingStardewRule, state: CollectionState, expected: bool, expl
@_explain.register
def _(rule: Count, state: CollectionState, expected: bool, explored_spots: Set[Tuple[str, str]]) -> RuleExplanation:
return RuleExplanation(rule, state, expected, rule.rules, explored_rules_key=explored_spots)
return CountExplanation(rule, state, expected, rule.rules, explored_rules_key=explored_spots)
@_explain.register

View File

@ -122,4 +122,4 @@ class HasProgressionPercent(CombinableStardewRule):
return self, self(state)
def __repr__(self):
return f"Received {self.percent}% progression items."
return f"Received {self.percent}% progression items"