453 lines
17 KiB
Python
453 lines
17 KiB
Python
#!/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() |