"""Panel-Primitive (creator2-Lektionen 15-24): 2 = Konsens-Minimum, Merge nur einstimmig, Ausfall = keine Stimme = kein Entscheid, Ersatz-Richter bei genau einem Ausfall.""" from typing import Awaitable, Callable def einstimmig(stimmen: list, n: int, urteil: Callable) -> bool: """True nur bei vollzähligem Panel UND allen Stimmen True. urteil(s) → True/False/None; None (Ausfall/Parse) = keine Stimme.""" urteile = [urteil(s) for s in stimmen if s is not None] urteile = [u for u in urteile if u is not None] return len(urteile) >= n and all(urteile) async def panel(ruf: Callable[[int], Awaitable], groesse: int) -> list: """groesse unabhängige Calls; fällt GENAU eine Stimme aus, läuft ein Ersatz-Richter (Index -1). None-Stimmen bleiben in der Liste.""" import asyncio stimmen = list(await asyncio.gather(*(ruf(i) for i in range(groesse)))) gueltig = [s for s in stimmen if s is not None] if groesse >= 2 and len(gueltig) == groesse - 1: stimmen.append(await ruf(-1)) return stimmen def mehrheit(stimmen: list, urteil: Callable) -> bool | None: """Mehrheitsentscheid (Klärung, 3er): None wenn keine Mehrheit möglich.""" urteile = [urteil(s) for s in stimmen if s is not None] urteile = [u for u in urteile if u is not None] if not urteile: return None ja = sum(1 for u in urteile if u) return ja * 2 > len(urteile)