Files
pony/demo.py

453 lines
17 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
MLP: Tails of Equestria — Demo & Test
En narrativ demohistorie med test af spilmotoren.
Hver ponytype i Equestria er repræsenteret. Alle egenskaber,
sværhedsgrader, talenter og edge cases testes i en sammenhængende historie.
"""
import random
import sys
from dataclasses import dataclass, field
from typing import List
# ── Data ──────────────────────────────────────────────
EGENSKABER = ["krop", "sind", "charme"]
EGENSKAB_NAVNE = {"krop": "Krop", "sind": "Sind", "charme": "Charme"}
SVÆRHED = {"Let": 1, "Normal": 2, "Svært": 3, "Meget svær": 4}
TALENTER = [
"Atlete", "Ekspert", "Kamp", "Kreativ", "Dyreven", "Magi",
"Listig", "Lider", "Sæljer", "Overlever",
]
SAERHEDER = [
"Modig", "Ridderlig", "Ambitiøs", "Trofast", "Eventyrlysten",
"Gavmild", "Fornuftig", "Glat", "Intuitiv", "Makaber",
"Opfindsom", "Praktisk", "Stolt", "Underlig",
]
# ── Pony ──────────────────────────────────────────────
@dataclass
class Pony:
navn: str
type: str
krop: int
sind: int
charme: int
talenter: List[str] = field(default_factory=list)
særheder: List[str] = field(default_factory=list)
udholdenhed: int = 0
venskabstegn: str = ""
# ── Terninger ─────────────────────────────────────────
def kast_terninger(antal: int) -> list[int]:
if antal < 1:
return []
return [random.randint(1, 6) for _ in range(antal)]
def tæl_succeser(terninger: list[int]) -> int:
succeser = 0
for t in terninger:
if t == 6:
succeser += 2
elif t >= 4:
succeser += 1
return succeser
# ── Test ──────────────────────────────────────────────
def test(pony: Pony, egenskab: str, sværhedsgrad: str, talent: str | None = None) -> str:
terninger = 0
if egenskab not in EGENSKABER:
return f"Ukendt egenskab: {egenskab}"
terninger += getattr(pony, egenskab)
if talent and talent in pony.talenter:
terninger += 1
if sværhedsgrad not in SVÆRHED:
return f"Ukendt sværhedsgrad: {sværhedsgrad}"
kræver = SVÆRHED[sværhedsgrad]
resultat = kast_terninger(terninger)
succeser = tæl_succeser(resultat)
ulykker = resultat.count(1)
fantastiske = resultat.count(6)
navne = EGENSKAB_NAVNE.get(egenskab, egenskab)
terning_del = f"{navne} ({terninger}d6)"
if talent:
terning_del += f" + {talent}"
linjer = [
f"\n🎲 {pony.navn} tester: {terning_del} mod {sværhedsgrad}",
f" Resultat: {resultat}",
]
if succeser >= kræver:
overskud = succeser - kræver
linjer.append(f" ✅ SUCCES! ({succeser} succeser, behøvede {kræver})")
if overskud >= 3:
linjer.append(" 🌟 En fantastisk bedrift — alle er imponerede!")
elif overskud >= 1:
linjer.append(" ✨ Det lykkedes flot — du får bonus til næste gang!")
else:
linjer.append(f" ❌ MISLYKKES ({succeser} succeser, behøvede {kræver})")
if ulykker > 0:
linjer.append(f" ⚠️ Der var {ulykker} ulykke(r) — noget gik helt galt!")
if fantastiske > 0:
linjer.append(f" Men {fantastiske} fantastisk(e) terning(r) reddede lidt af situationen.")
if fantastiske > 0:
linjer.append(f" ({fantastiske} fantastisk(e) succes(er) ✦)")
return "\n".join(linjer)
def print_pony(pony: Pony) -> None:
print(f"\n{'='*44}")
print(f" 🦄 {pony.navn}")
print(f" Type: {pony.type} | Venskabstegn: {pony.venskabstegn or '(—)'}")
print(f"{''*44}")
for attr, navn in [("krop", "Krop"), ("sind", "Sind"), ("charme", "Charme")]:
v = getattr(pony, attr)
print(f" {navn}: {''*v}{''*(4-v)}")
print(f" Udholdenhed: {pony.udholdenhed}")
print(f" Talenter: {', '.join(pony.talenter)}")
print(f" Særheder: {', '.join(pony.særheder)}")
print(f"{'='*44}\n")
# ── Test tracking ─────────────────────────────────────
tests_kørt = 0
tests_succes = 0
tests_fejlet = 0
def tæl_test(output: str) -> None:
global tests_kørt, tests_succes, tests_fejlet
tests_kørt += 1
if "✅ SUCCES" in output:
tests_succes += 1
else:
tests_fejlet += 1
def print_header(titel: str) -> None:
print(f"\n{'' * 58}")
print(f" {titel}")
print(f"{'' * 58}\n")
def print_sprog(titel: str) -> None:
print(f"{titel}\n")
# ── Demo ──────────────────────────────────────────────
def main() -> None:
global tests_kørt, tests_succes, tests_fejlet
# ═══════════════════════════════════════════════════
# Opret én pony af HVER type
# ═══════════════════════════════════════════════════
ponies: List[Pony] = []
ponies.append(Pony(
navn="Apple Bloom",
type="Earth Pony",
krop=4, sind=2, charme=2,
talenter=["Overlever", "Sæljer"],
særheder=["Trofast", "Praktisk"],
udholdenhed=5, venskabstegn="æble med blad",
))
ponies.append(Pony(
navn="Rainbow Dash",
type="Pegasus",
krop=4, sind=1, charme=2,
talenter=["Atlete", "Kamp"],
særheder=["Modig", "Stolt"],
udholdenhed=5, venskabstegn="regnbue-lyn",
))
ponies.append(Pony(
navn="Twilight Sparkle",
type="Alicorn",
krop=2, sind=3, charme=2,
talenter=["Magi", "Ekspert"],
særheder=["Intuitiv", "Ambitiøs"],
udholdenhed=3, venskabstegn="sekskantstjerne",
))
ponies.append(Pony(
navn="Trixie Lulamoon",
type="Unicorn",
krop=2, sind=2, charme=3,
talenter=["Magi", "Kreativ"],
særheder=["Stolt", "Glat"],
udholdenhed=3, venskabstegn="måne med hat",
))
ponies.append(Pony(
navn="Chrysalis (omvendt)",
type="Changeling",
krop=2, sind=2, charme=3,
talenter=["Listig", "Lider"],
særheder=["Glat", "Makaber"],
udholdenhed=3, venskabstegn="broget sommerfugl",
))
ponies.append(Pony(
navn="Styggi",
type="Otherkin",
krop=3, sind=2, charme=1,
talenter=["Kamp", "Overlever"],
særheder=["Ridderlig", "Eventyrlysten"],
udholdenhed=4, venskabstegn="kløe med hjerte",
))
# Minion (krop=0 for edge case!)
ponies.append(Pony(
navn="Snivvyl",
type="Minion",
krop=0, sind=1, charme=1,
talenter=["Listig", "Sæljer"],
særheder=["Underlig", "Opfindsom"],
udholdenhed=1, venskabstegn="krum nøgle",
))
earth = ponies[0]
pegasus = ponies[1]
alicorn = ponies[2]
unicorn = ponies[3]
changeling = ponies[4]
otherkin = ponies[5]
minion = ponies[6]
# ═══════════════════════════════════════════════════
# HISTORIEN starter
# ═══════════════════════════════════════════════════
print_header("MY LITTLE PONY: TAILS OF EQUESTRIA — DEMO & TEST")
print_sprog("En narrativ test med alle ponytyper, egenskaber, sværhedsgrader og talenter")
# ───────────────────────────────────────────────────
print_header("AKT 1 — PONYSERNE MØDES I PONYVILLE")
print_sprog("En solrig morgen. En hær af ponyer samles foran Carrot Top's cafe.")
print("Syv ponyer af syv forskellige typer mødes for første gang.")
print("Der er spænding i luften — og kaffe i koppen.\n")
for p in ponies:
print_pony(p)
print_sprog("Test 1: Rainbow Dash viser frem — Charme, Let")
output = test(pegasus, "charme", "Let")
print(output); tæl_test(output)
print_sprog("Test 2: Twilight forstår situationen — Sind, Normal (med Ekspert)")
output = test(alicorn, "sind", "Normal", "Ekspert")
print(output); tæl_test(output)
print_sprog("Test 3: Snivvyl prøver at være usynlig — Listig, Normal")
output = test(minion, "sind", "Normal", "Listig")
print(output); tæl_test(output)
# ───────────────────────────────────────────────────
print_header("AKT 2 — APPLES TINGEN ER I FÆRDE MED AT VISNE")
print_sprog("Apple Bloom opdagrer, at hele æblehaven lider. Hun kalder på hjælp.")
print_sprog("Test 4: Apple Bloom undersøger rødderne — Krop, Svært (med Overlever)")
output = test(earth, "krop", "Svært", "Overlever")
print(output); tæl_test(output)
print_sprog("Test 5: Twilight laver en heks for vækst — Sind, Svært (med Magi)")
output = test(alicorn, "sind", "Svært", "Magi")
print(output); tæl_test(output)
print_sprog("Test 6: Trixie forsøger sin egen 'magi' — Sind, Let (med Magi)")
output = test(unicorn, "sind", "Let", "Magi")
print(output); tæl_test(output)
print_sprog("Test 7: Chrysalis tilbyder 'kærlighed' til træerne — Charme, Normal (med Listig)")
output = test(changeling, "charme", "Normal", "Listig")
print(output); tæl_test(output)
# ───────────────────────────────────────────────────
print_header("AKT 3 — DET MØRKET UNDER MYSTERY KNOLL")
print_sprog("Lydene fra Myrmyren Knold gør alle nervøse. En ekspedition dannes.")
print_sprog("Test 8: Styggys kampinstinkt — Krop, Svært (med Kamp)")
output = test(otherkin, "krop", "Svært", "Kamp")
print(output); tæl_test(output)
print_sprog("Test 9: Rainbow Dash's flyveevne i mørket — Krop, Meget svær (med Atlete)")
output = test(pegasus, "krop", "Meget svær", "Atlete")
print(output); tæl_test(output)
print_sprog("Test 10: Trixies kreativ løsning — Sind, Svært (med Kreativ)")
output = test(unicorn, "sind", "Svært", "Kreativ")
print(output); tæl_test(output)
print_sprog("Test 11: Chrysalis leder gruppen — Charme, Normal (med Lider)")
output = test(changeling, "charme", "Normal", "Lider")
print(output); tæl_test(output)
print_sprog("Test 12: Snivvyl sælger 'hjælpemidler' — Charme, Let (med Sæljer)")
output = test(minion, "charme", "Let", "Sæljer")
print(output); tæl_test(output)
print_sprog("Test 13: Apple Bloom forhandler med markedsfolk — Charme, Normal (med Sæljer)")
output = test(earth, "charme", "Normal", "Sæljer")
print(output); tæl_test(output)
# ───────────────────────────────────────────────────
print_header("AKT 4 — DET STORE SAMARBEJDE")
print_sprog("Alle egenskaber, alle sværhedsgrader — den ultimative test.")
print("Hver pony tester alle tre egenskaber mod fire sværhedsgrader.")
print("Dette er den store udfordring.\n")
for p in ponies:
print_header(f"🦄 {p.navn} ({p.type}) — fuld testmatrix")
for attr in EGENSKABER:
for sg in SVÆRHED:
output = test(p, attr, sg)
print(output); tæl_test(output)
print()
# ───────────────────────────────────────────────────
print_header("AKT 5 — GRÆNSERNES UDFORDRING")
print_sprog("Edge cases — terningegrænser, 0 terninger, og ekstreme scenarioer.")
print_sprog("Test: Snivvyls Krop=0 mod Let (0d6 — umuligt at slå noget)")
output = test(minion, "krop", "Let")
print(output); tæl_test(output)
print_sprog("Test: Ugyldig egenskab — fejlhåndtering")
output = test(alicorn, "flyvehastighed", "Let")
print(f"\n🎲 Fejltest: {output}")
tæl_test(output)
print_sprog("Test: Ugyldig sværhedsgrad — fejlhåndtering")
output = test(alicorn, "krop", "Umuleg")
print(f"\n🎲 Fejltest: {output}")
tæl_test(output)
# ───────────────────────────────────────────────────
print_header("AKT 6 — SIMULERT TERNINGEKONTROL")
print_sprog("Verifikation af terningelogik med kendte input.")
sim_ok = 0
sim_total = 0
# Scenario A: alle 6-tal
sim_total += 1
alle_six = [6] * 5
s_a = tæl_succeser(alle_six)
ok_a = s_a == 10
if ok_a: sim_ok += 1
print(f" A) 5×6 = {s_a} succeser (forventet: 10) {'' if ok_a else ''}")
# Scenario B: alle 1-tal
sim_total += 1
alle_ene = [1] * 5
s_b = tæl_succeser(alle_ene)
ok_b = s_b == 0
if ok_b: sim_ok += 1
print(f" B) 5×1 = {s_b} succeser (forventet: 0) {'' if ok_b else ''}")
# Scenario C: alle 4-tal
sim_total += 1
alle_fire = [4] * 5
s_c = tæl_succeser(alle_fire)
ok_c = s_c == 5
if ok_c: sim_ok += 1
print(f" C) 5×4 = {s_c} succeser (forventet: 5) {'' if ok_c else ''}")
# Scenario D: blandet [1,3,4,5,6] → 1+1+2=4
sim_total += 1
blandet = [1, 3, 4, 5, 6]
s_d = tæl_succeser(blandet)
ok_d = s_d == 4
if ok_d: sim_ok += 1
print(f" D) [1,3,4,5,6] = {s_d} succeser (forventet: 4) {'' if ok_d else ''}")
# Scenario E: tom liste
sim_total += 1
s_0 = tæl_succeser([])
ok_0 = s_0 == 0
if ok_0: sim_ok += 1
print(f" E) [] = {s_0} succeser (forventet: 0) {'' if ok_0 else ''}")
# Scenario F: kast_terninger(0)
sim_total += 1
kast_0 = kast_terninger(0)
ok_k0 = kast_0 == []
if ok_k0: sim_ok += 1
print(f" F) kast_terninger(0) = {kast_0} (forventet: []) {'' if ok_k0 else ''}")
# Scenario G: stor simulation
sim_total += 1
sim_values = []
for _ in range(1000):
r = kast_terninger(3)
sim_values.append(tæl_succeser(r))
g = sum(sim_values) / len(sim_values)
ok_g = 0.5 < g < 3.0
if ok_g: sim_ok += 1
print(f" G) 1000×3d6 → gennemsnit {g:.2f} (interval: {min(sim_values)}-{max(sim_values)}) {'' if ok_g else ''}")
print(f"\n {''*30}")
print(f" Simuleringer: {sim_ok}/{sim_total} bestået\n")
# ───────────────────────────────────────────────────
print_header("SAMMENFATNING")
print_sprog("Hvad lykkedes, hvad fejlede, og hvor mange tests er kørt?")
print(f" {''*44}")
print(f" 📊 TESTRESULTATER:")
print(f" {''*44}")
print(f" Total tests kørte: {tests_kørt}")
print(f" ✅ Succes: {tests_succes}")
print(f" ❌ Mislykkedes: {tests_fejlet}")
if tests_kørt > 0:
pct = (tests_succes / tests_kørt) * 100
print(f" Succesrate: {pct:.0f}%")
print(f" {''*44}")
print(f" 🎲 SIMULERINGER: {sim_ok}/{sim_total} bestået")
print(f" {''*44}")
# Test matrix dækning
print(f"\n {''*44}")
print(f" 🦄 PONYSER TESTET:")
for p in ponies:
print(f" {p.type:12s}{p.navn}")
print(f" {''*44}")
print(f"\n {''*44}")
print(f" 📋 EGENSKABER TESTET: {', '.join(EGENSKAB_NAVNE.values())}")
print(f" 📋 SVÆRHEDSGRADER: {', '.join(SVÆRHED.keys())}")
print(f" {''*44}")
print(f"\n {''*44}")
print(f" 🎯 TALENTER TESTET:")
tested_talenter = set()
for p in ponies:
for t in p.talenter:
tested_talenter.add(t)
for t in sorted(tested_talenter):
print(f"{t}")
print(f" {''*44}")
print(f"\n {''*44}")
print(f" 🧪 EDGE CASES TESTET:")
print(f" ✅ Krop=0 (0 terninger)")
print(f" ✅ Ugyldig egenskab")
print(f" ✅ Ugyldig sværhedsgrad")
print(f" ✅ Simuleret alle 6-tal")
print(f" ✅ Simuleret alle 1-tal")
print(f" ✅ kast_terninger(0)")
print(f" ✅ 1000× storsimulation")
print(f" {''*44}")
print_header("DEMO FULDFØRT 🌈")
print_sprog("Tak for nu! Venskab er den stærkeste magi i Equestria.")
sys.exit(0 if sim_ok == sim_total else 1)
if __name__ == "__main__":
main()