Archipelago/worlds/sm/variaRandomizer/logic/smbool.py

123 lines
3.4 KiB
Python

def flatten(l):
if type(l) is list:
return [ y for x in l for y in flatten(x) ]
else:
return [ l ]
# super metroid boolean
class SMBool:
__slots__ = ('bool', 'difficulty', '_knows', '_items')
def __init__(self, boolean, difficulty=0, knows=[], items=[]):
self.bool = boolean
self.difficulty = difficulty
self._knows = knows
self._items = items
@property
def knows(self):
self._knows = list(set(flatten(self._knows)))
return self._knows
@knows.setter
def knows(self, knows):
self._knows = knows
@property
def items(self):
self._items = list(set(flatten(self._items)))
return self._items
@items.setter
def items(self, items):
self._items = items
def __repr__(self):
# to display the smbool as a string
return 'SMBool({}, {}, {}, {})'.format(self.bool, self.difficulty, sorted(self.knows), sorted(self.items))
def __getitem__(self, index):
# to acces the smbool as [0] for the bool and [1] for the difficulty.
# required when we load a json preset where the smbool is stored as a list,
# and we add missing smbools to it, so we have a mix of lists and smbools.
if index == 0:
return self.bool
elif index == 1:
return self.difficulty
def __bool__(self):
# when used in boolean expressions (with and/or/not) (python3)
return self.bool
def __eq__(self, other):
# for ==
return self.bool == other
def __ne__(self, other):
# for !=
return self.bool != other
def __lt__(self, other):
# for <
if self.bool and other.bool:
return self.difficulty < other.difficulty
else:
return self.bool
def __copy__(self):
return SMBool(self.bool, self.difficulty, self._knows, self._items)
def json(self):
# as we have slots instead of dict
return {'bool': self.bool, 'difficulty': self.difficulty, 'knows': self.knows, 'items': self.items}
def wand(*args):
# looping here is faster than using "if ... in" construct
for smb in args:
if not smb.bool:
return smboolFalse
difficulty = 0
for smb in args:
difficulty += smb.difficulty
return SMBool(True,
difficulty,
[ smb._knows for smb in args ],
[ smb._items for smb in args ])
def wandmax(*args):
# looping here is faster than using "if ... in" construct
for smb in args:
if not smb.bool:
return smboolFalse
difficulty = 0
for smb in args:
if smb.difficulty > difficulty:
difficulty = smb.difficulty
return SMBool(True,
difficulty,
[ smb._knows for smb in args ],
[ smb._items for smb in args ])
def wor(*args):
# looping here is faster than using "if ... in" construct
for smb in args:
if smb.bool:
return min(args)
return smboolFalse
# negates boolean part of the SMBool
def wnot(a):
return smboolFalse if a.bool else SMBool(True, a.difficulty)
__and__ = wand
__or__ = wor
__not__ = wnot
smboolFalse = SMBool(False)