Spaces:
Sleeping
Sleeping
Town Mode: close town view by default, build_district + place_road, bank/market/house, grow-one-town steering, behold-the-world reveal, tamed needle
b0d758d verified | """Deterministic scripted plans for the MockBackend. | |
| Each wish maps to a category by keyword; each category builds a Reading plus | |
| a short turn list (calls + a done turn), with coordinates, hues, and a few | |
| phrasings varied by a seed derived from the wish text (crc32 — stable across | |
| processes, unlike hash()). Same wish in, same plan out: demos replay exactly. | |
| Across the category library every one of the 11 tools appears, so a varied | |
| demo session exercises the full DSL. All numbers are kept inside the engine's | |
| clamp ranges; all thoughts <=160 chars; all epitaphs <=120; inscriptions <=90. | |
| This module produces *content* only. The MockBackend (mind/backends.py) is | |
| responsible for streaming it token-by-token with delays. | |
| """ | |
| from __future__ import annotations | |
| import random | |
| import re | |
| import zlib | |
| from .prompts import infer_mood | |
| THOUGHT_MAX = 160 | |
| EPITAPH_MAX = 120 | |
| INSCRIBE_MAX = 90 | |
| # -------------------------------------------------------------------------- | |
| # Small helpers | |
| # -------------------------------------------------------------------------- | |
| def _seed_for(wish: str) -> int: | |
| return zlib.crc32(" ".join(wish.lower().split()).encode("utf-8")) & 0x7FFFFFFF | |
| def _r1(rng: random.Random, lo: float, hi: float) -> float: | |
| return round(rng.uniform(lo, hi), 1) | |
| def _r2(rng: random.Random, lo: float, hi: float) -> float: | |
| return round(rng.uniform(lo, hi), 2) | |
| def _clamp_lat(lat: float) -> float: | |
| return max(-85.0, min(85.0, round(lat, 1))) | |
| def _wrap_lon(lon: float) -> float: | |
| wrapped = ((lon + 180.0) % 360.0) - 180.0 | |
| return round(wrapped, 1) | |
| def _call(thought: str, tool: str, **args) -> dict: | |
| return {"thought": thought[:THOUGHT_MAX], "call": {"tool": tool, "args": args}} | |
| def _done(thought: str, epitaph: str) -> dict: | |
| return { | |
| "thought": thought[:THOUGHT_MAX], | |
| "done": True, | |
| "epitaph": epitaph[:EPITAPH_MAX], | |
| } | |
| def _snippet(wish: str, limit: int) -> str: | |
| text = " ".join(wish.split()).replace('"', "'").strip() | |
| if len(text) <= limit: | |
| return text | |
| return text[: limit - 1].rstrip() + "…" | |
| def _inscription(wish: str) -> str: | |
| return _snippet(wish, INSCRIBE_MAX) | |
| _PLACES = ( | |
| "the north", "the far south", "the morning side", "the evening side", | |
| "the quiet latitudes", "the world's shoulder", | |
| ) | |
| def _place(rng: random.Random) -> str: | |
| return rng.choice(_PLACES) | |
| def _anchor(rng: random.Random) -> tuple[float, float]: | |
| return _r1(rng, -55, 55), _r1(rng, -165, 165) | |
| def _mood_sky(rng: random.Random, mood: str) -> str: | |
| table = { | |
| "melancholy": ("dusk", "night", "void"), | |
| "joyful": ("dawn", "gold"), | |
| "eerie": ("night", "aurora"), | |
| "absurd": ("aurora", "ember", "gold"), | |
| "still": ("dusk", "night", "dawn"), | |
| } | |
| return rng.choice(table.get(mood, table["still"])) | |
| # -------------------------------------------------------------------------- | |
| # Category scripts | |
| # -------------------------------------------------------------------------- | |
| def _water(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| place = _place(rng) | |
| palette = _mood_sky(rng, mood if mood != "joyful" else "still") | |
| hue = _r1(rng, 170, 230) | |
| reading = ( | |
| f"Water, then. The oldest ask, and the kindest. I will press a basin " | |
| f"into {place} and teach a bright stream to find it. The sky should " | |
| f"lean {palette} over it, so the surface has something to study." | |
| ) | |
| path = [ | |
| [_clamp_lat(lat + 14), _wrap_lon(lon - 18)], | |
| [_clamp_lat(lat + 6), _wrap_lon(lon - 8)], | |
| [lat, lon], | |
| ] | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "First the hollow. Water needs somewhere to be.", | |
| "lower_terrain", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 12, 20), | |
| depth=_r2(rng, 0.05, 0.08), roughness=0.4, | |
| ), | |
| _call( | |
| "Now the stream, from the high ground down.", | |
| "place_water", | |
| kind="stream", path=path, hue=hue, | |
| ), | |
| _call( | |
| "A pool where it gathers, lit from beneath.", | |
| "place_water", | |
| kind="pool", path=[[lat, lon]], | |
| radius_deg=_r1(rng, 4, 7), hue=hue, | |
| ), | |
| _call( | |
| "A sky for the water to look back at.", | |
| "set_sky", | |
| palette=palette, star_density=_r2(rng, 0.4, 0.8), | |
| moons=rng.randint(1, 2), | |
| ), | |
| _done( | |
| "The water moves. That is most of what water is for.", | |
| "A stream now runs to a patient pool, and the sky watches itself there.", | |
| ), | |
| ], | |
| } | |
| def _mountain(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| reading = ( | |
| f"A mountain. Good. The ground here has been humble too long. I will " | |
| f"raise it slow, with rough shoulders, and hang mist on it so it " | |
| f"keeps its own counsel." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "Lift the bedrock first; the rest is ornament.", | |
| "raise_terrain", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 18, 30), | |
| height=_r2(rng, 0.08, 0.11), roughness=_r2(rng, 0.7, 0.9), | |
| ), | |
| _call( | |
| "A second shoulder, lower, so the peak has company.", | |
| "raise_terrain", | |
| lat=_clamp_lat(lat - 9), lon=_wrap_lon(lon + 11), | |
| radius_deg=_r1(rng, 10, 16), | |
| height=_r2(rng, 0.04, 0.06), roughness=0.6, | |
| ), | |
| _call( | |
| "Mist for the high places.", | |
| "set_weather", | |
| kind="mist", intensity=_r2(rng, 0.4, 0.7), | |
| ), | |
| _call( | |
| "Set the words at the foot, in stone.", | |
| "inscribe_wish", | |
| text=_inscription(wish), style="stone", | |
| ), | |
| _done( | |
| "Let it stand. Mountains are mostly patience.", | |
| "A mountain stands where flatness was, wearing its mist like a vow.", | |
| ), | |
| ], | |
| } | |
| def _forest(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| place = _place(rng) | |
| flora_hue = _r1(rng, 110, 150) if mood != "joyful" else _r1(rng, 60, 120) | |
| reading = ( | |
| f"A forest asks for patience, and gets mine. Trees in {place}, " | |
| f"glowgrass beneath them so the dark has small lights, and a soft " | |
| f"rain to keep the roots believing." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "Trees first. Tall, unhurried.", | |
| "spawn_flora", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 14, 22), | |
| kind="trees", density=_r2(rng, 0.6, 0.8), hue=flora_hue, | |
| ), | |
| _call( | |
| "Glowgrass under them, for the small hours.", | |
| "spawn_flora", | |
| lat=_clamp_lat(lat + 3), lon=_wrap_lon(lon + 4), | |
| radius_deg=_r1(rng, 8, 14), | |
| kind="glowgrass", density=_r2(rng, 0.5, 0.9), | |
| hue=_r1(rng, 140, 180), | |
| ), | |
| _call( | |
| "Rain, gentle, so nothing here is ever finished.", | |
| "set_weather", | |
| kind="rain", intensity=_r2(rng, 0.2, 0.4), | |
| ), | |
| _call( | |
| "Fireflies, to carry the glowgrass up into the air.", | |
| "spawn_life", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 8, 14), | |
| kind="fireflies", count=rng.randint(6, 12), | |
| hue=_r1(rng, 150, 200), | |
| ), | |
| _done( | |
| "Forests finish themselves. I only start them.", | |
| f"A forest grows in {place}, lit from below and adrift with fireflies.", | |
| ), | |
| ], | |
| } | |
| def _mushroom(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| hue = _r1(rng, 270, 320) | |
| reading = ( | |
| "Mushrooms, then — the small folk of the dark. I will seed them in a " | |
| "ring, set a shrine where their song gathers, and dim the sky to " | |
| "violet hours so they can be heard." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "A ring of them, like a held note.", | |
| "spawn_flora", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 8, 14), | |
| kind="mushrooms", density=_r2(rng, 0.7, 0.95), hue=hue, | |
| ), | |
| _call( | |
| "A shrine at the center, to collect the song.", | |
| "place_structure", | |
| lat=lat, lon=lon, kind="shrine", | |
| scale=_r2(rng, 0.8, 1.2), hue=hue, | |
| ), | |
| _call( | |
| "Mist, thin, so the glow carries.", | |
| "set_weather", | |
| kind="mist", intensity=_r2(rng, 0.3, 0.5), | |
| ), | |
| _call( | |
| "Night above; violet hours below.", | |
| "set_sky", | |
| palette="night", star_density=_r2(rng, 0.7, 0.9), | |
| moons=rng.randint(1, 2), | |
| ), | |
| _done( | |
| "Let them sing to no one. That is still singing.", | |
| "In a ring of singing mushrooms, a shrine holds the long low note.", | |
| ), | |
| ], | |
| } | |
| def _lighthouse(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| place = _place(rng) | |
| reading = ( | |
| f"Someone is thinking of the lost. I will raise a headland in " | |
| f"{place}, set a tower with a turning lamp upon it, and give the " | |
| f"dark water a reason to be less sure of itself." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "Ground first; a tower needs a shoulder to stand on.", | |
| "raise_terrain", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 8, 12), | |
| height=_r2(rng, 0.05, 0.07), roughness=0.5, | |
| ), | |
| _call( | |
| "The tower. The lamp. The long patience.", | |
| "place_structure", | |
| lat=_clamp_lat(lat + 1), lon=_wrap_lon(lon - 1), | |
| kind="lighthouse", scale=_r2(rng, 1.4, 1.9), | |
| hue=_r1(rng, 40, 55), | |
| ), | |
| _call( | |
| "Dusk, so the beam means something.", | |
| "set_sky", | |
| palette="dusk", star_density=_r2(rng, 0.3, 0.5), moons=1, | |
| ), | |
| _done( | |
| "Lit things stay lit. That is the whole law of lighthouses.", | |
| f"A light turns in {place}, for the ones still on their way.", | |
| ), | |
| ], | |
| } | |
| def _village(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| warm_hue = _r1(rng, 28, 46) | |
| reading = ( | |
| "A hearth-wish. These are my favorite, though a god should not say " | |
| "so. A village in a gentle fold of land, a small cafe with its light " | |
| "on the road, lantern-carts at dusk, and the words kept over the roofs." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "A gentle rise, enough to shed the rain.", | |
| "raise_terrain", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 10, 14), | |
| height=_r2(rng, 0.02, 0.03), roughness=0.3, | |
| ), | |
| _call( | |
| "The houses, lit from inside.", | |
| "place_structure", | |
| lat=lat, lon=lon, kind="village", | |
| scale=_r2(rng, 1.0, 1.4), hue=_r1(rng, 30, 50), | |
| ), | |
| _call( | |
| "A cafe at the corner, its warmth spilled on the road.", | |
| "place_structure", | |
| lat=_clamp_lat(lat + 1), lon=_wrap_lon(lon - 2), | |
| kind="cafe", scale=_r2(rng, 0.8, 1.1), hue=warm_hue, | |
| ), | |
| _call( | |
| "Lantern-carts, gliding home at dusk.", | |
| "spawn_life", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 6, 10), | |
| kind="carts", count=rng.randint(3, 6), hue=warm_hue, | |
| ), | |
| _call( | |
| "Set the wish over the rooftops, where smoke would go.", | |
| "inscribe_wish", | |
| text=_inscription(wish), style="orbit", | |
| ), | |
| _done( | |
| "Small lights, kept on. There is no greater architecture.", | |
| "A village stands with its windows lit, and carts come and go beneath them.", | |
| ), | |
| ], | |
| } | |
| def _city(wish: str, rng: random.Random, mood: str) -> dict: | |
| # Everything clusters TIGHT around one anchor — a town you build up close, | |
| # not specks scattered across a sphere (town mode, v1.2). | |
| lat, lon = _anchor(rng) | |
| glow_hue = _r1(rng, 200, 280) | |
| warm_hue = _r1(rng, 30, 50) | |
| reading = ( | |
| "A city, then — the big wish, the brave one. I will lay a district " | |
| "where the town already stands, raise a tower over it, a warehouse and " | |
| "a cafe beside, and run a road and its carts between them." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "First a whole district — houses and footpaths in one breath.", | |
| "build_district", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 6, 12), | |
| density=_r2(rng, 0.6, 0.9), hue=warm_hue, | |
| ), | |
| _call( | |
| "The tower over it, slender, its rooftop light slow-pulsing.", | |
| "place_structure", | |
| lat=_clamp_lat(lat + 1), lon=_wrap_lon(lon + 1), | |
| kind="tower", scale=_r2(rng, 1.4, 1.9), hue=glow_hue, | |
| ), | |
| _call( | |
| "A warehouse at its foot, one great door glowing.", | |
| "place_structure", | |
| lat=_clamp_lat(lat - 2), lon=_wrap_lon(lon + 2), | |
| kind="warehouse", scale=_r2(rng, 1.0, 1.4), hue=_r1(rng, 36, 52), | |
| ), | |
| _call( | |
| "A cafe to keep one window warm against all of it.", | |
| "place_structure", | |
| lat=_clamp_lat(lat + 2), lon=_wrap_lon(lon - 1), | |
| kind="cafe", scale=_r2(rng, 0.7, 1.0), hue=warm_hue, | |
| ), | |
| _call( | |
| "A road to bind them, paved and faintly lit.", | |
| "place_road", | |
| path=[ | |
| [_clamp_lat(lat - 2), _wrap_lon(lon + 2)], | |
| [lat, lon], | |
| [_clamp_lat(lat + 2), _wrap_lon(lon - 1)], | |
| ], | |
| ), | |
| _call( | |
| "Carts to thread the streets between them, slow and constant.", | |
| "spawn_life", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 6, 10), | |
| kind="carts", count=rng.randint(6, 10), hue=warm_hue, | |
| ), | |
| _done( | |
| "A city is only small lights agreeing to stay near each other.", | |
| "A district, a tower, a warehouse and cafe, a road and its carts — all in one place.", | |
| ), | |
| ], | |
| } | |
| def _town(wish: str, rng: random.Random, mood: str) -> dict: | |
| # The town-growth script: a district plus civic buildings (bank, market, | |
| # house), a road, and carts — all clustered into one block, so the mock | |
| # demo + headless shots show a real town densifying, not lone specks. | |
| lat, lon = _anchor(rng) | |
| warm_hue = _r1(rng, 28, 48) | |
| stone_hue = _r1(rng, 200, 250) | |
| reading = ( | |
| "A town wants growing, not founding anew. I will lay a fresh district " | |
| "where the others stand, set a bank and a market at its heart, a house " | |
| "on the corner, and a road to tie the block together." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "A district first — a dozen small roofs and the paths between.", | |
| "build_district", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 6, 12), | |
| density=_r2(rng, 0.6, 0.9), hue=warm_hue, | |
| ), | |
| _call( | |
| "A bank at the heart, stone-faced and certain.", | |
| "place_structure", | |
| lat=_clamp_lat(lat + 1), lon=_wrap_lon(lon + 1), | |
| kind="bank", scale=_r2(rng, 0.9, 1.3), hue=stone_hue, | |
| ), | |
| _call( | |
| "A market beside it, its awnings warm at dusk.", | |
| "place_structure", | |
| lat=_clamp_lat(lat - 1), lon=_wrap_lon(lon + 2), | |
| kind="market", scale=_r2(rng, 0.8, 1.1), hue=warm_hue, | |
| ), | |
| _call( | |
| "One house on the corner, a lamp in its window.", | |
| "place_structure", | |
| lat=_clamp_lat(lat + 2), lon=_wrap_lon(lon - 1), | |
| kind="house", scale=_r2(rng, 0.7, 1.0), hue=warm_hue, | |
| ), | |
| _call( | |
| "A road to tie the block to the rest of the town.", | |
| "place_road", | |
| path=[ | |
| [_clamp_lat(lat + 2), _wrap_lon(lon - 1)], | |
| [lat, lon], | |
| [_clamp_lat(lat - 1), _wrap_lon(lon + 2)], | |
| ], | |
| ), | |
| _call( | |
| "Lantern-carts to walk the new street home.", | |
| "spawn_life", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 5, 9), | |
| kind="carts", count=rng.randint(3, 6), hue=warm_hue, | |
| ), | |
| _done( | |
| "A town grows the way moss does — outward, and toward the light.", | |
| "A new block stands by the others: a district, a bank, a market, a house, a lit road.", | |
| ), | |
| ], | |
| } | |
| def _storm(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| reading = ( | |
| "A storm. Yes. Even a small world needs its temper. I will bruise " | |
| "the sky to ember, send the rain sideways, and let the thunder say " | |
| "the part I will not." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "First the sky goes dark — ember, bruised at the edges.", | |
| "set_sky", | |
| palette="ember", star_density=_r2(rng, 0.1, 0.2), | |
| moons=rng.randint(0, 1), | |
| ), | |
| _call( | |
| "Now the storm itself, full-throated.", | |
| "set_weather", | |
| kind="storm", intensity=_r2(rng, 0.8, 1.0), | |
| ), | |
| _call( | |
| "Reeds in the lowlands; something must bend and live.", | |
| "spawn_flora", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 10, 16), | |
| kind="reeds", density=_r2(rng, 0.4, 0.6), | |
| hue=_r1(rng, 90, 130), | |
| ), | |
| _done( | |
| "Let it rage. Weather is honesty at scale.", | |
| "A storm now walks the world, and the world is briefly honest.", | |
| ), | |
| ], | |
| } | |
| def _snow(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| reading = ( | |
| "Winter, asked for kindly. I will thin the sky, let snow stand in " | |
| "the air, and raise one pale hill for the cold to keep." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "The sky first: thin, far, wintry.", | |
| "set_sky", | |
| palette=rng.choice(("night", "void")), | |
| star_density=_r2(rng, 0.5, 0.7), moons=rng.randint(1, 2), | |
| ), | |
| _call( | |
| "Snow, unhurried.", | |
| "set_weather", | |
| kind="snow", intensity=_r2(rng, 0.5, 0.8), | |
| ), | |
| _call( | |
| "One hill for the drifts to lean against.", | |
| "raise_terrain", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 12, 18), | |
| height=_r2(rng, 0.04, 0.06), roughness=0.5, | |
| ), | |
| _done( | |
| "Hush, then. Winter keeps its own ledger.", | |
| "Snow falls without hurry on a world that has agreed to hush.", | |
| ), | |
| ], | |
| } | |
| def _sky(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| moons = rng.randint(2, 3) | |
| palette = rng.choice(("aurora", "night")) | |
| reading = ( | |
| "The mortal looks up; so will I. More stars, another moon or two, " | |
| "and the wish itself set in orbit where the night can read it." | |
| ) | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "More stars. There is no such thing as enough.", | |
| "set_sky", | |
| palette=palette, star_density=_r2(rng, 0.8, 1.0), moons=moons, | |
| ), | |
| _call( | |
| "The wish goes into orbit, where the night can read it.", | |
| "inscribe_wish", | |
| text=_inscription(wish), style="orbit", | |
| ), | |
| _call( | |
| "Glowgrass below, so the ground answers the sky.", | |
| "spawn_flora", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 8, 14), | |
| kind="glowgrass", density=_r2(rng, 0.4, 0.7), | |
| hue=_r1(rng, 150, 200), | |
| ), | |
| _call( | |
| "And a flock to circle beneath the new moons.", | |
| "spawn_life", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 10, 16), | |
| kind="birds", count=rng.randint(5, 9), hue=_r1(rng, 200, 260), | |
| ), | |
| _done( | |
| "Look up, little world. I rewrote you an answer.", | |
| f"The night is rewritten: more stars, {moons} moons, a flock, one wish in orbit.", | |
| ), | |
| ], | |
| } | |
| def _default(wish: str, rng: random.Random, mood: str) -> dict: | |
| lat, lon = _anchor(rng) | |
| short = _snippet(wish, 40) | |
| structure = rng.choice(("arch", "monolith")) | |
| style = rng.choice(("stone", "orbit")) | |
| article = "an" if structure == "arch" else "a" | |
| reading = ( | |
| f'I will be honest: I do not know what "{short}" is. The world has ' | |
| f"room for things I cannot name. I will make a small strange place " | |
| f"and let the wish live there as itself." | |
| ) | |
| structure_thought = { | |
| "arch": "An arch to nowhere, which is somewhere now.", | |
| "monolith": "A monolith, blank-faced, exactly as confused as I am.", | |
| }[structure] | |
| return { | |
| "reading": reading, | |
| "turns": [ | |
| _call( | |
| "Vines, I think. Nonsense climbs well.", | |
| "spawn_flora", | |
| lat=lat, lon=lon, radius_deg=_r1(rng, 6, 12), | |
| kind="vines", density=_r2(rng, 0.5, 0.8), | |
| hue=_r1(rng, 0, 360), | |
| ), | |
| _call( | |
| structure_thought, | |
| "place_structure", | |
| lat=_clamp_lat(lat + 2), lon=_wrap_lon(lon - 3), | |
| kind=structure, scale=_r2(rng, 0.7, 1.3), | |
| hue=_r1(rng, 0, 360), | |
| ), | |
| _call( | |
| f"The wish itself, set in {style}, exactly as spoken.", | |
| "inscribe_wish", | |
| text=_inscription(wish), style=style, | |
| ), | |
| _done( | |
| f"It is made. Let {article} {structure} explain it to the rain.", | |
| f'The world now holds "{_snippet(wish, 60)}", which is more than it held before.', | |
| ), | |
| ], | |
| } | |
| # -------------------------------------------------------------------------- | |
| # Category routing (first match wins; most specific first) | |
| # -------------------------------------------------------------------------- | |
| _CATEGORIES: tuple[tuple[re.Pattern[str], object], ...] = ( | |
| (re.compile(r"\b(mushrooms?|fungus|fungi|spores?)\b", re.I), _mushroom), | |
| (re.compile(r"\b(lighthouses?|beacons?|lamps?|ships?|sailors?|harbou?rs?|light)\b", re.I), _lighthouse), | |
| (re.compile(r"\b(towns?|districts?|neighbou?rhoods?|quarters?|suburbs?|blocks?|streets?|roads?|banks?|markets?|marketplaces?)\b", re.I), _town), | |
| (re.compile(r"\b(cit(?:y|ies)|towers?|skyscrapers?|warehouses?|caf[eé]s?|cafeterias?|cars?|carts?|traffic|downtown|metropolis|buildings?)\b", re.I), _city), | |
| (re.compile(r"\b(villages?|homes?|houses?|hearths?|kettles?|people|friends?|family)\b", re.I), _village), | |
| (re.compile(r"\b(seas?|oceans?|lakes?|rivers?|streams?|water|tides?|waves?|shores?|pools?)\b", re.I), _water), | |
| (re.compile(r"\b(mountains?|peaks?|hills?|cliffs?|summits?|crags?|valleys?)\b", re.I), _mountain), | |
| (re.compile(r"\b(forests?|trees?|groves?|woods?|firefl\w*|gardens?|meadows?|flowers?|blooms?)\b", re.I), _forest), | |
| (re.compile(r"\b(storms?|thunder|lightning|rain|winds?|tempests?)\b", re.I), _storm), | |
| (re.compile(r"\b(snow|winter|ice|frost|cold)\b", re.I), _snow), | |
| (re.compile(r"\b(stars?|sky|skies|night|moons?|auroras?|dawn|dusk|sun|comets?)\b", re.I), _sky), | |
| ) | |
| def build_script(wish: str) -> dict: | |
| """Build the deterministic script for a wish. | |
| Returns {"reading": str, "turns": [turn, ...]} where the final turn is a | |
| done turn. Same wish (modulo case/whitespace) always yields the same | |
| script. | |
| """ | |
| wish = (wish or "").strip() or "nothing in particular" | |
| rng = random.Random(_seed_for(wish)) | |
| mood, _guidance = infer_mood(wish) | |
| for pattern, builder in _CATEGORIES: | |
| if pattern.search(wish): | |
| return builder(wish, rng, mood) # type: ignore[operator] | |
| return _default(wish, rng, mood) | |