From fc2855ca6d0e63467b2237dcce44c237c7dfef76 Mon Sep 17 00:00:00 2001 From: black-sliver <59490463+black-sliver@users.noreply.github.com> Date: Fri, 27 Oct 2023 18:09:12 +0200 Subject: [PATCH] Stardew Valley: speed up rules creation by 4% (#2371) * Stardew Valley: speed up rules creation by 4% No class should ever inherit from And, Or, False_ or True_ and isinstance is not free. Sadly there is no cheap way to forbid inheritance, but it was tested using metaclass. * Stardew Valley: save calls to type() Local variable is a bit faster than fetching type again * Stardew Valley: save calls to True_() and False_(), also use 'in' operator * Stardew Valley: optimize And and Or simplification * Stardew Valley: optimize logic constructors --- worlds/stardew_valley/stardew_rule.py | 111 ++++++++++++++------------ 1 file changed, 61 insertions(+), 50 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index d0fa9858..5455a40e 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Iterable, Dict, List, Union, FrozenSet +from typing import Iterable, Dict, List, Union, FrozenSet, Set from BaseClasses import CollectionState, ItemClassification from .items import item_table @@ -14,13 +14,13 @@ class StardewRule: raise NotImplementedError def __or__(self, other) -> StardewRule: - if isinstance(other, Or): + if type(other) is Or: return Or(self, *other.rules) return Or(self, other) def __and__(self, other) -> StardewRule: - if isinstance(other, And): + if type(other) is And: return And(other.rules.union({self})) return And(self, other) @@ -80,28 +80,36 @@ class False_(StardewRule): # noqa return 999999999 +false_ = False_() +true_ = True_() +assert false_ is False_() +assert true_ is True_() + + class Or(StardewRule): rules: FrozenSet[StardewRule] def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): - rules_list = set() + rules_list: Set[StardewRule] + if isinstance(rule, Iterable): - rules_list.update(rule) + rules_list = {*rule} else: - rules_list.add(rule) + rules_list = {rule} if rules is not None: rules_list.update(rules) assert rules_list, "Can't create a Or conditions without rules" - new_rules = set() - for rule in rules_list: - if isinstance(rule, Or): - new_rules.update(rule.rules) - else: - new_rules.add(rule) - rules_list = new_rules + if any(type(rule) is Or for rule in rules_list): + new_rules: Set[StardewRule] = set() + for rule in rules_list: + if type(rule) is Or: + new_rules.update(rule.rules) + else: + new_rules.add(rule) + rules_list = new_rules self.rules = frozenset(rules_list) @@ -112,11 +120,11 @@ class Or(StardewRule): return f"({' | '.join(repr(rule) for rule in self.rules)})" def __or__(self, other): - if isinstance(other, True_): + if other is true_: return other - if isinstance(other, False_): + if other is false_: return self - if isinstance(other, Or): + if type(other) is Or: return Or(self.rules.union(other.rules)) return Or(self.rules.union({other})) @@ -131,17 +139,17 @@ class Or(StardewRule): return min(rule.get_difficulty() for rule in self.rules) def simplify(self) -> StardewRule: - if any(isinstance(rule, True_) for rule in self.rules): - return True_() + if true_ in self.rules: + return true_ - simplified_rules = {rule.simplify() for rule in self.rules} - simplified_rules = {rule for rule in simplified_rules if rule is not False_()} + simplified_rules = [simplified for simplified in {rule.simplify() for rule in self.rules} + if simplified is not false_] if not simplified_rules: - return False_() + return false_ if len(simplified_rules) == 1: - return next(iter(simplified_rules)) + return simplified_rules[0] return Or(simplified_rules) @@ -150,25 +158,26 @@ class And(StardewRule): rules: FrozenSet[StardewRule] def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): - rules_list = set() + rules_list: Set[StardewRule] + if isinstance(rule, Iterable): - rules_list.update(rule) + rules_list = {*rule} else: - rules_list.add(rule) + rules_list = {rule} if rules is not None: rules_list.update(rules) - if len(rules_list) < 1: - rules_list.add(True_()) - - new_rules = set() - for rule in rules_list: - if isinstance(rule, And): - new_rules.update(rule.rules) - else: - new_rules.add(rule) - rules_list = new_rules + if not rules_list: + rules_list.add(true_) + elif any(type(rule) is And for rule in rules_list): + new_rules: Set[StardewRule] = set() + for rule in rules_list: + if type(rule) is And: + new_rules.update(rule.rules) + else: + new_rules.add(rule) + rules_list = new_rules self.rules = frozenset(rules_list) @@ -179,11 +188,11 @@ class And(StardewRule): return f"({' & '.join(repr(rule) for rule in self.rules)})" def __and__(self, other): - if isinstance(other, True_): + if other is true_: return self - if isinstance(other, False_): + if other is false_: return other - if isinstance(other, And): + if type(other) is And: return And(self.rules.union(other.rules)) return And(self.rules.union({other})) @@ -198,17 +207,17 @@ class And(StardewRule): return max(rule.get_difficulty() for rule in self.rules) def simplify(self) -> StardewRule: - if any(isinstance(rule, False_) for rule in self.rules): - return False_() + if false_ in self.rules: + return false_ - simplified_rules = {rule.simplify() for rule in self.rules} - simplified_rules = {rule for rule in simplified_rules if rule is not True_()} + simplified_rules = [simplified for simplified in {rule.simplify() for rule in self.rules} + if simplified is not true_] if not simplified_rules: - return True_() + return true_ if len(simplified_rules) == 1: - return next(iter(simplified_rules)) + return simplified_rules[0] return And(simplified_rules) @@ -218,11 +227,12 @@ class Count(StardewRule): rules: List[StardewRule] def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): - rules_list = [] + rules_list: List[StardewRule] + if isinstance(rule, Iterable): - rules_list.extend(rule) + rules_list = [*rule] else: - rules_list.append(rule) + rules_list = [rule] if rules is not None: rules_list.extend(rules) @@ -260,11 +270,12 @@ class TotalReceived(StardewRule): player: int def __init__(self, count: int, items: Union[str, Iterable[str]], player: int): - items_list = [] + items_list: List[str] + if isinstance(items, Iterable): - items_list.extend(items) + items_list = [*items] else: - items_list.append(items) + items_list = [items] assert items_list, "Can't create a Total Received conditions without items" for item in items_list: