File size: 1,584 Bytes
3831e97 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | """Placement rule helpers used by ShopSpace and PREP-only edits."""
from __future__ import annotations
from typing import Iterable, Sequence, Tuple
GridPos = Tuple[int, int]
def entrance_blocked(tags) -> bool:
return "is_entrance" in set(tags or [])
def can_rotate(footprint) -> bool:
"""All furniture may rotate; non-square footprints swap axes on rotate."""
try:
w, h = int(footprint[0]), int(footprint[1])
except (TypeError, IndexError, ValueError):
return False
return w > 0 and h > 0
def rotate_footprint_xy(footprint, rot90: bool = False) -> Tuple[int, int]:
"""Return (w,h) after optional 90° rotate (shared with furniture_shop)."""
w, h = int(footprint[0]), int(footprint[1])
return (h, w) if rot90 else (w, h)
def prep_only_edit(phase: str) -> bool:
"""Layout edits allowed only in PREP."""
return str(phase).upper() == "PREP"
def overlap(a_origin: GridPos, a_fp: Sequence[int], b_origin: GridPos, b_fp: Sequence[int]) -> bool:
ax, ay = a_origin
aw, ah = int(a_fp[0]), int(a_fp[1])
bx, by = b_origin
bw, bh = int(b_fp[0]), int(b_fp[1])
return not (ax + aw <= bx or bx + bw <= ax or ay + ah <= by or by + bh <= ay)
def layout_comfort(free_cells: int, total_cells: int) -> bool:
"""True when enough free walking room remains."""
if total_cells <= 0:
return False
return (free_cells / total_cells) >= 0.25
def validate_display_slots(slot_ids: Iterable[str], required: int = 5) -> bool:
ids = list(slot_ids)
return len(ids) >= required and len(set(ids)) == len(ids)
|