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
This commit is contained in:
parent
6a2407468a
commit
fc2855ca6d
|
@ -1,7 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
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 BaseClasses import CollectionState, ItemClassification
|
||||||
from .items import item_table
|
from .items import item_table
|
||||||
|
@ -14,13 +14,13 @@ class StardewRule:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def __or__(self, other) -> StardewRule:
|
def __or__(self, other) -> StardewRule:
|
||||||
if isinstance(other, Or):
|
if type(other) is Or:
|
||||||
return Or(self, *other.rules)
|
return Or(self, *other.rules)
|
||||||
|
|
||||||
return Or(self, other)
|
return Or(self, other)
|
||||||
|
|
||||||
def __and__(self, other) -> StardewRule:
|
def __and__(self, other) -> StardewRule:
|
||||||
if isinstance(other, And):
|
if type(other) is And:
|
||||||
return And(other.rules.union({self}))
|
return And(other.rules.union({self}))
|
||||||
|
|
||||||
return And(self, other)
|
return And(self, other)
|
||||||
|
@ -80,28 +80,36 @@ class False_(StardewRule): # noqa
|
||||||
return 999999999
|
return 999999999
|
||||||
|
|
||||||
|
|
||||||
|
false_ = False_()
|
||||||
|
true_ = True_()
|
||||||
|
assert false_ is False_()
|
||||||
|
assert true_ is True_()
|
||||||
|
|
||||||
|
|
||||||
class Or(StardewRule):
|
class Or(StardewRule):
|
||||||
rules: FrozenSet[StardewRule]
|
rules: FrozenSet[StardewRule]
|
||||||
|
|
||||||
def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
|
def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
|
||||||
rules_list = set()
|
rules_list: Set[StardewRule]
|
||||||
|
|
||||||
if isinstance(rule, Iterable):
|
if isinstance(rule, Iterable):
|
||||||
rules_list.update(rule)
|
rules_list = {*rule}
|
||||||
else:
|
else:
|
||||||
rules_list.add(rule)
|
rules_list = {rule}
|
||||||
|
|
||||||
if rules is not None:
|
if rules is not None:
|
||||||
rules_list.update(rules)
|
rules_list.update(rules)
|
||||||
|
|
||||||
assert rules_list, "Can't create a Or conditions without rules"
|
assert rules_list, "Can't create a Or conditions without rules"
|
||||||
|
|
||||||
new_rules = set()
|
if any(type(rule) is Or for rule in rules_list):
|
||||||
for rule in rules_list:
|
new_rules: Set[StardewRule] = set()
|
||||||
if isinstance(rule, Or):
|
for rule in rules_list:
|
||||||
new_rules.update(rule.rules)
|
if type(rule) is Or:
|
||||||
else:
|
new_rules.update(rule.rules)
|
||||||
new_rules.add(rule)
|
else:
|
||||||
rules_list = new_rules
|
new_rules.add(rule)
|
||||||
|
rules_list = new_rules
|
||||||
|
|
||||||
self.rules = frozenset(rules_list)
|
self.rules = frozenset(rules_list)
|
||||||
|
|
||||||
|
@ -112,11 +120,11 @@ class Or(StardewRule):
|
||||||
return f"({' | '.join(repr(rule) for rule in self.rules)})"
|
return f"({' | '.join(repr(rule) for rule in self.rules)})"
|
||||||
|
|
||||||
def __or__(self, other):
|
def __or__(self, other):
|
||||||
if isinstance(other, True_):
|
if other is true_:
|
||||||
return other
|
return other
|
||||||
if isinstance(other, False_):
|
if other is false_:
|
||||||
return self
|
return self
|
||||||
if isinstance(other, Or):
|
if type(other) is Or:
|
||||||
return Or(self.rules.union(other.rules))
|
return Or(self.rules.union(other.rules))
|
||||||
|
|
||||||
return Or(self.rules.union({other}))
|
return Or(self.rules.union({other}))
|
||||||
|
@ -131,17 +139,17 @@ 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 any(isinstance(rule, True_) for rule in self.rules):
|
if true_ in self.rules:
|
||||||
return True_()
|
return true_
|
||||||
|
|
||||||
simplified_rules = {rule.simplify() for rule in self.rules}
|
simplified_rules = [simplified for simplified in {rule.simplify() for rule in self.rules}
|
||||||
simplified_rules = {rule for rule in simplified_rules if rule is not False_()}
|
if simplified is not false_]
|
||||||
|
|
||||||
if not simplified_rules:
|
if not simplified_rules:
|
||||||
return False_()
|
return false_
|
||||||
|
|
||||||
if len(simplified_rules) == 1:
|
if len(simplified_rules) == 1:
|
||||||
return next(iter(simplified_rules))
|
return simplified_rules[0]
|
||||||
|
|
||||||
return Or(simplified_rules)
|
return Or(simplified_rules)
|
||||||
|
|
||||||
|
@ -150,25 +158,26 @@ class And(StardewRule):
|
||||||
rules: FrozenSet[StardewRule]
|
rules: FrozenSet[StardewRule]
|
||||||
|
|
||||||
def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
|
def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
|
||||||
rules_list = set()
|
rules_list: Set[StardewRule]
|
||||||
|
|
||||||
if isinstance(rule, Iterable):
|
if isinstance(rule, Iterable):
|
||||||
rules_list.update(rule)
|
rules_list = {*rule}
|
||||||
else:
|
else:
|
||||||
rules_list.add(rule)
|
rules_list = {rule}
|
||||||
|
|
||||||
if rules is not None:
|
if rules is not None:
|
||||||
rules_list.update(rules)
|
rules_list.update(rules)
|
||||||
|
|
||||||
if len(rules_list) < 1:
|
if not rules_list:
|
||||||
rules_list.add(True_())
|
rules_list.add(true_)
|
||||||
|
elif any(type(rule) is And for rule in rules_list):
|
||||||
new_rules = set()
|
new_rules: Set[StardewRule] = set()
|
||||||
for rule in rules_list:
|
for rule in rules_list:
|
||||||
if isinstance(rule, And):
|
if type(rule) is And:
|
||||||
new_rules.update(rule.rules)
|
new_rules.update(rule.rules)
|
||||||
else:
|
else:
|
||||||
new_rules.add(rule)
|
new_rules.add(rule)
|
||||||
rules_list = new_rules
|
rules_list = new_rules
|
||||||
|
|
||||||
self.rules = frozenset(rules_list)
|
self.rules = frozenset(rules_list)
|
||||||
|
|
||||||
|
@ -179,11 +188,11 @@ class And(StardewRule):
|
||||||
return f"({' & '.join(repr(rule) for rule in self.rules)})"
|
return f"({' & '.join(repr(rule) for rule in self.rules)})"
|
||||||
|
|
||||||
def __and__(self, other):
|
def __and__(self, other):
|
||||||
if isinstance(other, True_):
|
if other is true_:
|
||||||
return self
|
return self
|
||||||
if isinstance(other, False_):
|
if other is false_:
|
||||||
return other
|
return other
|
||||||
if isinstance(other, And):
|
if type(other) is And:
|
||||||
return And(self.rules.union(other.rules))
|
return And(self.rules.union(other.rules))
|
||||||
|
|
||||||
return And(self.rules.union({other}))
|
return And(self.rules.union({other}))
|
||||||
|
@ -198,17 +207,17 @@ 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 any(isinstance(rule, False_) for rule in self.rules):
|
if false_ in self.rules:
|
||||||
return False_()
|
return false_
|
||||||
|
|
||||||
simplified_rules = {rule.simplify() for rule in self.rules}
|
simplified_rules = [simplified for simplified in {rule.simplify() for rule in self.rules}
|
||||||
simplified_rules = {rule for rule in simplified_rules if rule is not True_()}
|
if simplified is not true_]
|
||||||
|
|
||||||
if not simplified_rules:
|
if not simplified_rules:
|
||||||
return True_()
|
return true_
|
||||||
|
|
||||||
if len(simplified_rules) == 1:
|
if len(simplified_rules) == 1:
|
||||||
return next(iter(simplified_rules))
|
return simplified_rules[0]
|
||||||
|
|
||||||
return And(simplified_rules)
|
return And(simplified_rules)
|
||||||
|
|
||||||
|
@ -218,11 +227,12 @@ class Count(StardewRule):
|
||||||
rules: List[StardewRule]
|
rules: List[StardewRule]
|
||||||
|
|
||||||
def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
|
def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
|
||||||
rules_list = []
|
rules_list: List[StardewRule]
|
||||||
|
|
||||||
if isinstance(rule, Iterable):
|
if isinstance(rule, Iterable):
|
||||||
rules_list.extend(rule)
|
rules_list = [*rule]
|
||||||
else:
|
else:
|
||||||
rules_list.append(rule)
|
rules_list = [rule]
|
||||||
|
|
||||||
if rules is not None:
|
if rules is not None:
|
||||||
rules_list.extend(rules)
|
rules_list.extend(rules)
|
||||||
|
@ -260,11 +270,12 @@ class TotalReceived(StardewRule):
|
||||||
player: int
|
player: int
|
||||||
|
|
||||||
def __init__(self, count: int, items: Union[str, Iterable[str]], player: int):
|
def __init__(self, count: int, items: Union[str, Iterable[str]], player: int):
|
||||||
items_list = []
|
items_list: List[str]
|
||||||
|
|
||||||
if isinstance(items, Iterable):
|
if isinstance(items, Iterable):
|
||||||
items_list.extend(items)
|
items_list = [*items]
|
||||||
else:
|
else:
|
||||||
items_list.append(items)
|
items_list = [items]
|
||||||
|
|
||||||
assert items_list, "Can't create a Total Received conditions without items"
|
assert items_list, "Can't create a Total Received conditions without items"
|
||||||
for item in items_list:
|
for item in items_list:
|
||||||
|
|
Loading…
Reference in New Issue