Files
majiang-rl/majiang_rl/tiles.py
2026-01-14 10:49:00 +08:00

66 lines
1.5 KiB
Python

from __future__ import annotations
from typing import Iterable, List, Tuple
SUITS = ("wan", "tong", "suo")
WINDS = ("east", "south", "west", "north")
DRAGONS = ("red", "green", "white")
FLOWERS = (
"plum",
"orchid",
"chrysanthemum",
"bamboo",
"spring",
"summer",
"autumn",
"winter",
)
# 34 suited + honors, plus 8 flowers = 42
TILE_TYPES: List[str] = []
for suit in SUITS:
for rank in range(1, 10):
TILE_TYPES.append(f"{suit}_{rank}")
for wind in WINDS:
TILE_TYPES.append(f"wind_{wind}")
for dragon in DRAGONS:
TILE_TYPES.append(f"dragon_{dragon}")
for flower in FLOWERS:
TILE_TYPES.append(f"flower_{flower}")
SUITED_RANGE = range(0, 27)
HONOR_RANGE = range(27, 34)
FLOWER_RANGE = range(34, 42)
def build_wall(rng) -> List[int]:
wall: List[int] = []
for tile_id in range(34):
wall.extend([tile_id] * 4)
for tile_id in FLOWER_RANGE:
wall.append(tile_id)
rng.shuffle(wall)
return wall
def is_flower(tile_id: int) -> bool:
return tile_id in FLOWER_RANGE
def tile_name(tile_id: int) -> str:
return TILE_TYPES[tile_id]
def counts_from_tiles(tiles: Iterable[int], size: int = 42) -> List[int]:
counts = [0] * size
for tile_id in tiles:
counts[tile_id] += 1
return counts
def split_suit_index(tile_id: int) -> Tuple[int, int] | None:
if tile_id not in SUITED_RANGE:
return None
suit = tile_id // 9
rank = tile_id % 9
return suit, rank