LovecaSim / engine /game /state_utils.py
trioskosmos's picture
Upload folder using huggingface_hub
bb3fbf9 verified
import logging
from typing import Any, Dict, Iterator
try:
pass
except:
pass
logger = logging.getLogger(__name__)
class StateMixin:
"""Base class for checking equality of state objects."""
def __eq__(self, other):
return isinstance(self, type(other)) and self.__dict__ == other.__dict__
def copy_slots_to(self, target: "StateMixin") -> None:
"""Copy all fields defined in __slots__ to the target object."""
if not hasattr(self, "__slots__"):
return
for name in self.__slots__:
if hasattr(self, name):
val = getattr(self, name)
# Handle mutable types that need explicit copying
if isinstance(val, list):
setattr(target, name, val[:])
elif isinstance(val, set):
setattr(target, name, set(val))
elif isinstance(val, dict):
setattr(target, name, dict(val))
elif hasattr(val, "copy"):
setattr(target, name, val.copy())
else:
setattr(target, name, val)
# ----------------------------------------------------------------------------
# Unique ID (UID) System
# ----------------------------------------------------------------------------
# Masks: 20 bits for Base ID, 12 bits for Instance
BASE_ID_MASK = 0xFFFFF
INSTANCE_SHIFT = 20
def get_base_id(uid: int) -> int:
"""Extract the base card definition ID from a potentially combined UID."""
return uid & BASE_ID_MASK
def get_instance_index(uid: int) -> int:
"""Extract the instance index from a UID."""
return uid >> INSTANCE_SHIFT
def create_uid(base_id: int, instance_index: int) -> int:
"""Create a unique instance ID from a base ID and an index."""
# Safety check: base_id must fit in 20 bits
if base_id > BASE_ID_MASK:
logger.warning(f"Base ID {base_id} exceeds mask {BASE_ID_MASK}!")
return (base_id & BASE_ID_MASK) | (instance_index << INSTANCE_SHIFT)
class MaskedDB(dict):
"""
A dictionary wrapper that automatically masks unique instance IDs (UIDs)
to retrieve data associated with the base ID.
This allows the game state to essentially 'ignore' the instance part of an ID
when looking up static card data.
"""
def __init__(self, data: Dict[int, Any]):
super().__init__(data)
self._data = data
def __getitem__(self, key: int) -> Any:
# Resolve UID to base ID
try:
base_id = int(key) & BASE_ID_MASK
if base_id in self._data:
return self._data[base_id]
# Fallback to string key for JSON-loaded data
return self._data[str(base_id)]
except (ValueError, TypeError):
raise KeyError(key)
def __contains__(self, key: object) -> bool:
try:
base_id = int(key) & BASE_ID_MASK
return base_id in self._data or str(base_id) in self._data
except (ValueError, TypeError):
return False
def get(self, key: int, default: Any = None) -> Any:
try:
if key is None:
return default
base_id = int(key) & BASE_ID_MASK
if base_id in self._data:
return self._data[base_id]
# Fallback to string key
return self._data.get(str(base_id), default)
except (ValueError, TypeError):
return default
def __len__(self) -> int:
return len(self._data)
def __iter__(self) -> Iterator[int]:
# Iterate over ORIGINAL base IDs (keys of _data)
return iter(self._data)
def keys(self):
return self._data.keys()
def values(self):
return self._data.values()
def items(self):
return self._data.items()