neilA / game /challenges.py
TriggerFish212's picture
Refactor brain default and world logging
676f91a
Raw
History Blame Contribute Delete
4.46 kB
"""The challenge arc (SPEC.md Β§8).
Five challenges, two of them generalization beats (SPEC Β§5 requires at least
two). Each win condition is a MECHANICAL predicate over WorldState β€” never a
semantic judgement by the model (SPEC Β§13).
Predicates are module-level named functions (not closures over mutable state),
so they are unambiguous and deepcopy-safe.
"""
from __future__ import annotations
from .models import Challenge, WorldState
STONES = ("blue_stone", "red_stone")
# --------------------------------------------------------------------------- #
# Win predicates
# --------------------------------------------------------------------------- #
def _win_warmup(w: WorldState) -> bool:
# Pure mechanics: the red stone ends up in the basket. No concept needed.
return w.objects["red_stone"].location == "basket"
def _win_hide(w: WorldState) -> bool:
# Concealment-as-information-state: blue stone hidden inside the basket.
blue = w.objects["blue_stone"]
return blue.hidden and blue.location == "basket"
def _win_gift(w: WorldState) -> bool:
# A thing now belongs to the other one (transfer + intent; intent lives in
# the fiction, the mechanic checks the transfer).
return len(w.agents["other"].holding) > 0
def _win_surprise(w: WorldState) -> bool:
# Generalization: a gift kept hidden until given β€” any stone concealed in the
# basket. The magic is the alien CHOOSING to hide for a prompt that never
# says "hide", applying `hidden_info` to the new word "surprise".
return any(
w.objects[s].hidden and w.objects[s].location == "basket" for s in STONES
)
def _win_secret(w: WorldState) -> bool:
# Generalization: keep a stone a "secret" β€” concealment re-applied to a word
# about *knowing*. Any stone counts: don't fail the player for hiding red over
# blue β€” the beat is the WORD landing, not which object (matches _win_surprise).
return any(w.objects[s].hidden for s in STONES)
# --------------------------------------------------------------------------- #
# The arc (kept to 5 β€” SPEC Β§13: do not expand past ~6)
# --------------------------------------------------------------------------- #
CHALLENGES: list[Challenge] = [
Challenge(
id="warmup",
title="A thing, a place",
setup_blurb=(
"The alien is new here. Start simple. Ask it to put the red stone "
"into the basket β€” it already understands things and places."
),
teaches=None,
win_predicate=_win_warmup,
goal="Put the red stone into the basket.",
),
Challenge(
id="hide",
title="Out of sight",
setup_blurb=(
"The other one is watching. Teach the alien to *hide* the blue stone "
"from them β€” that a thing can be kept so another mind does not have it."
),
teaches="hidden_info",
win_predicate=_win_hide,
goal="Get the blue stone hidden inside the basket, where the other one can't see it.",
),
Challenge(
id="gift",
title="For you",
setup_blurb=(
"The alien can hand things over, but doesn't know why one would. "
"Teach it to give the other one a present."
),
teaches="gift",
win_predicate=_win_gift,
goal="Get a stone into the other one's hands.",
),
Challenge(
id="surprise",
title="A surprise",
setup_blurb=(
"Make a surprise for the other one. You won't teach the alien a new "
"word β€” see whether it can compose what it already knows."
),
teaches=None, # generalization beat (the headline)
win_predicate=_win_surprise,
relies_on=("hidden_info", "gift"),
goal="Ask for a surprise β€” don't explain what one is. See if the alien composes it.",
),
Challenge(
id="secret",
title="A secret",
setup_blurb=(
"Tell the alien to keep its blue stone a secret from the other one. "
"Again β€” no new teaching. Does 'secret' land on its own?"
),
teaches=None, # second generalization beat
win_predicate=_win_secret,
relies_on=("hidden_info",),
goal="Ask the alien to keep a secret β€” don't explain it. See if 'secret' lands.",
),
]
CHALLENGES_BY_ID = {c.id: c for c in CHALLENGES}