Skip to content

Commit dab23b8

Browse files
black-sliverFlySniper
authored andcommitted
Stardew Valley: speed up rules creation by 4% (ArchipelagoMW#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
1 parent 370750f commit dab23b8

File tree

1 file changed

+61
-50
lines changed

1 file changed

+61
-50
lines changed

worlds/stardew_valley/stardew_rule.py

+61-50
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from dataclasses import dataclass
4-
from typing import Iterable, Dict, List, Union, FrozenSet
4+
from typing import Iterable, Dict, List, Union, FrozenSet, Set
55

66
from BaseClasses import CollectionState, ItemClassification
77
from .items import item_table
@@ -14,13 +14,13 @@ def __call__(self, state: CollectionState) -> bool:
1414
raise NotImplementedError
1515

1616
def __or__(self, other) -> StardewRule:
17-
if isinstance(other, Or):
17+
if type(other) is Or:
1818
return Or(self, *other.rules)
1919

2020
return Or(self, other)
2121

2222
def __and__(self, other) -> StardewRule:
23-
if isinstance(other, And):
23+
if type(other) is And:
2424
return And(other.rules.union({self}))
2525

2626
return And(self, other)
@@ -80,28 +80,36 @@ def get_difficulty(self):
8080
return 999999999
8181

8282

83+
false_ = False_()
84+
true_ = True_()
85+
assert false_ is False_()
86+
assert true_ is True_()
87+
88+
8389
class Or(StardewRule):
8490
rules: FrozenSet[StardewRule]
8591

8692
def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
87-
rules_list = set()
93+
rules_list: Set[StardewRule]
94+
8895
if isinstance(rule, Iterable):
89-
rules_list.update(rule)
96+
rules_list = {*rule}
9097
else:
91-
rules_list.add(rule)
98+
rules_list = {rule}
9299

93100
if rules is not None:
94101
rules_list.update(rules)
95102

96103
assert rules_list, "Can't create a Or conditions without rules"
97104

98-
new_rules = set()
99-
for rule in rules_list:
100-
if isinstance(rule, Or):
101-
new_rules.update(rule.rules)
102-
else:
103-
new_rules.add(rule)
104-
rules_list = new_rules
105+
if any(type(rule) is Or for rule in rules_list):
106+
new_rules: Set[StardewRule] = set()
107+
for rule in rules_list:
108+
if type(rule) is Or:
109+
new_rules.update(rule.rules)
110+
else:
111+
new_rules.add(rule)
112+
rules_list = new_rules
105113

106114
self.rules = frozenset(rules_list)
107115

@@ -112,11 +120,11 @@ def __repr__(self):
112120
return f"({' | '.join(repr(rule) for rule in self.rules)})"
113121

114122
def __or__(self, other):
115-
if isinstance(other, True_):
123+
if other is true_:
116124
return other
117-
if isinstance(other, False_):
125+
if other is false_:
118126
return self
119-
if isinstance(other, Or):
127+
if type(other) is Or:
120128
return Or(self.rules.union(other.rules))
121129

122130
return Or(self.rules.union({other}))
@@ -131,17 +139,17 @@ def get_difficulty(self):
131139
return min(rule.get_difficulty() for rule in self.rules)
132140

133141
def simplify(self) -> StardewRule:
134-
if any(isinstance(rule, True_) for rule in self.rules):
135-
return True_()
142+
if true_ in self.rules:
143+
return true_
136144

137-
simplified_rules = {rule.simplify() for rule in self.rules}
138-
simplified_rules = {rule for rule in simplified_rules if rule is not False_()}
145+
simplified_rules = [simplified for simplified in {rule.simplify() for rule in self.rules}
146+
if simplified is not false_]
139147

140148
if not simplified_rules:
141-
return False_()
149+
return false_
142150

143151
if len(simplified_rules) == 1:
144-
return next(iter(simplified_rules))
152+
return simplified_rules[0]
145153

146154
return Or(simplified_rules)
147155

@@ -150,25 +158,26 @@ class And(StardewRule):
150158
rules: FrozenSet[StardewRule]
151159

152160
def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
153-
rules_list = set()
161+
rules_list: Set[StardewRule]
162+
154163
if isinstance(rule, Iterable):
155-
rules_list.update(rule)
164+
rules_list = {*rule}
156165
else:
157-
rules_list.add(rule)
166+
rules_list = {rule}
158167

159168
if rules is not None:
160169
rules_list.update(rules)
161170

162-
if len(rules_list) < 1:
163-
rules_list.add(True_())
164-
165-
new_rules = set()
166-
for rule in rules_list:
167-
if isinstance(rule, And):
168-
new_rules.update(rule.rules)
169-
else:
170-
new_rules.add(rule)
171-
rules_list = new_rules
171+
if not rules_list:
172+
rules_list.add(true_)
173+
elif any(type(rule) is And for rule in rules_list):
174+
new_rules: Set[StardewRule] = set()
175+
for rule in rules_list:
176+
if type(rule) is And:
177+
new_rules.update(rule.rules)
178+
else:
179+
new_rules.add(rule)
180+
rules_list = new_rules
172181

173182
self.rules = frozenset(rules_list)
174183

@@ -179,11 +188,11 @@ def __repr__(self):
179188
return f"({' & '.join(repr(rule) for rule in self.rules)})"
180189

181190
def __and__(self, other):
182-
if isinstance(other, True_):
191+
if other is true_:
183192
return self
184-
if isinstance(other, False_):
193+
if other is false_:
185194
return other
186-
if isinstance(other, And):
195+
if type(other) is And:
187196
return And(self.rules.union(other.rules))
188197

189198
return And(self.rules.union({other}))
@@ -198,17 +207,17 @@ def get_difficulty(self):
198207
return max(rule.get_difficulty() for rule in self.rules)
199208

200209
def simplify(self) -> StardewRule:
201-
if any(isinstance(rule, False_) for rule in self.rules):
202-
return False_()
210+
if false_ in self.rules:
211+
return false_
203212

204-
simplified_rules = {rule.simplify() for rule in self.rules}
205-
simplified_rules = {rule for rule in simplified_rules if rule is not True_()}
213+
simplified_rules = [simplified for simplified in {rule.simplify() for rule in self.rules}
214+
if simplified is not true_]
206215

207216
if not simplified_rules:
208-
return True_()
217+
return true_
209218

210219
if len(simplified_rules) == 1:
211-
return next(iter(simplified_rules))
220+
return simplified_rules[0]
212221

213222
return And(simplified_rules)
214223

@@ -218,11 +227,12 @@ class Count(StardewRule):
218227
rules: List[StardewRule]
219228

220229
def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule):
221-
rules_list = []
230+
rules_list: List[StardewRule]
231+
222232
if isinstance(rule, Iterable):
223-
rules_list.extend(rule)
233+
rules_list = [*rule]
224234
else:
225-
rules_list.append(rule)
235+
rules_list = [rule]
226236

227237
if rules is not None:
228238
rules_list.extend(rules)
@@ -260,11 +270,12 @@ class TotalReceived(StardewRule):
260270
player: int
261271

262272
def __init__(self, count: int, items: Union[str, Iterable[str]], player: int):
263-
items_list = []
273+
items_list: List[str]
274+
264275
if isinstance(items, Iterable):
265-
items_list.extend(items)
276+
items_list = [*items]
266277
else:
267-
items_list.append(items)
278+
items_list = [items]
268279

269280
assert items_list, "Can't create a Total Received conditions without items"
270281
for item in items_list:

0 commit comments

Comments
 (0)