Temaer: fælles temabank i party/data/themes.json
Tegn og Gæts temaer flyttes til ét sted (party/data/themes.json med
loaderen party/themes.py), så Spionen kan bruge de samme i stedet for en
kopi. Navne og ord er uændrede, så Tegn og Gæt og dets forvarmede
{tema}-replikker opfører sig som før.
Spionen skal bruge ord, det er nemt at give stikord til: spy_themes() giver
de temaer, der har mindst 15 konkrete navneord i ét ord. "spion": false
udelader et tema (film og serier: titler), og "spion_skip" enkelte ord (si,
and, frikvarter, lektier, hygge). Det giver 13 temaer med 15 til 18 ord.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ Serveren er autoritativ. Hver skærm har én WebSocket, sender handlinger og få
|
||||
| Mappe | Indhold |
|
||||
| --- | --- |
|
||||
| `fupogfakta/` | Spilmotor, modeller for kategorier og spørgsmål, spørgsmålsbank i `data/*.json` |
|
||||
| `tegnoggaet/` | Spilmotor for Tegn og Gæt, temaer i `data/themes.json`, speakerens replikker |
|
||||
| `tegnoggaet/` | Spilmotor for Tegn og Gæt og speakerens replikker (temaerne er fælles: `party/data/themes.json`) |
|
||||
| `party/` | Rum, WebSocket-consumers, sider, Authentik-header-login, templates og JS/CSS; spilregistret i `games.py` |
|
||||
| `partyhub/` | Django-projekt (settings, ASGI) |
|
||||
| `deploy/` | systemd-unit, miljøfil-skabelon og `deploy.sh` |
|
||||
|
||||
+1
-1
@@ -312,5 +312,5 @@ styrer selv tempoet ud fra `started_at` og `plan[].ms`.
|
||||
|
||||
Point: +100 pr. hjerte til den, der lavede bidraget, og +500 til ejeren af en kæde, der overlevede. Priser:
|
||||
"Bedste tegning" og "Bedste gæt" (flest hjerter, ved lighed det første i afsløringen), "Kæden der overlevede" og
|
||||
"Største forvandling" (mindst lighed mellem første ord og sidste gæt). Temaerne står i `tegnoggaet/data/themes.json`
|
||||
"Største forvandling" (mindst lighed mellem første ord og sidste gæt). Temaerne står i `party/data/themes.json`
|
||||
og speakerens replikker i `tegnoggaet/narrator/lines.json`.
|
||||
|
||||
@@ -0,0 +1,355 @@
|
||||
[
|
||||
{
|
||||
"id": "dyr",
|
||||
"name": "Dyr",
|
||||
"icon": "🐘",
|
||||
"words": [
|
||||
"kat",
|
||||
"hund",
|
||||
"elefant",
|
||||
"giraf",
|
||||
"pingvin",
|
||||
"krokodille",
|
||||
"blæksprutte",
|
||||
"flodhest",
|
||||
"pindsvin",
|
||||
"edderkop",
|
||||
"sommerfugl",
|
||||
"kænguru",
|
||||
"hval",
|
||||
"ugle",
|
||||
"snegl",
|
||||
"zebra",
|
||||
"papegøje",
|
||||
"isbjørn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "film",
|
||||
"name": "Film og serier",
|
||||
"icon": "🎬",
|
||||
"words": [
|
||||
"løvernes konge",
|
||||
"frost",
|
||||
"star wars",
|
||||
"harry potter",
|
||||
"titanic",
|
||||
"jurassic park",
|
||||
"find nemo",
|
||||
"shrek",
|
||||
"toy story",
|
||||
"ringenes herre",
|
||||
"olsen banden",
|
||||
"spiderman",
|
||||
"batman",
|
||||
"pippi langstrømpe",
|
||||
"minions",
|
||||
"mary poppins",
|
||||
"ghostbusters"
|
||||
],
|
||||
"spion": false
|
||||
},
|
||||
{
|
||||
"id": "koekken",
|
||||
"name": "Ting i køkkenet",
|
||||
"icon": "🍳",
|
||||
"words": [
|
||||
"gaffel",
|
||||
"pande",
|
||||
"køleskab",
|
||||
"brødrister",
|
||||
"piskeris",
|
||||
"kaffemaskine",
|
||||
"grydeske",
|
||||
"ovn",
|
||||
"mikroovn",
|
||||
"kagerulle",
|
||||
"si",
|
||||
"osteskærer",
|
||||
"opvaskemaskine",
|
||||
"tekande",
|
||||
"skærebræt",
|
||||
"kasserolle",
|
||||
"køkkenrulle"
|
||||
],
|
||||
"spion_skip": [
|
||||
"si"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "jul",
|
||||
"name": "Jul",
|
||||
"icon": "🎄",
|
||||
"words": [
|
||||
"juletræ",
|
||||
"julemand",
|
||||
"nisse",
|
||||
"rensdyr",
|
||||
"snemand",
|
||||
"gave",
|
||||
"risalamande",
|
||||
"pebernødder",
|
||||
"stjerne",
|
||||
"kravlenisse",
|
||||
"slæde",
|
||||
"julehjerte",
|
||||
"lys",
|
||||
"and",
|
||||
"juletræsfod",
|
||||
"mandelgave",
|
||||
"kalenderlys",
|
||||
"sne"
|
||||
],
|
||||
"spion_skip": [
|
||||
"and"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "sport",
|
||||
"name": "Sport",
|
||||
"icon": "⚽",
|
||||
"words": [
|
||||
"fodbold",
|
||||
"håndbold",
|
||||
"cykelløb",
|
||||
"svømning",
|
||||
"tennis",
|
||||
"golf",
|
||||
"skihop",
|
||||
"boksning",
|
||||
"badminton",
|
||||
"basketball",
|
||||
"bueskydning",
|
||||
"surfing",
|
||||
"ishockey",
|
||||
"kunstskøjteløb",
|
||||
"maraton",
|
||||
"vægtløftning",
|
||||
"ridning"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "mad",
|
||||
"name": "Mad",
|
||||
"icon": "🍕",
|
||||
"words": [
|
||||
"pizza",
|
||||
"pandekager",
|
||||
"spaghetti",
|
||||
"hotdog",
|
||||
"frikadeller",
|
||||
"sushi",
|
||||
"burger",
|
||||
"is",
|
||||
"banan",
|
||||
"vandmelon",
|
||||
"æbleskiver",
|
||||
"smørrebrød",
|
||||
"popcorn",
|
||||
"rugbrød",
|
||||
"flæskesteg",
|
||||
"kanelsnegl",
|
||||
"tacos",
|
||||
"lagkage"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "strand",
|
||||
"name": "På stranden",
|
||||
"icon": "🏖️",
|
||||
"words": [
|
||||
"sandslot",
|
||||
"parasol",
|
||||
"badebold",
|
||||
"krabbe",
|
||||
"solcreme",
|
||||
"fyrtårn",
|
||||
"bølge",
|
||||
"måge",
|
||||
"badehåndklæde",
|
||||
"vandmand",
|
||||
"luftmadras",
|
||||
"solbriller",
|
||||
"spand og skovl",
|
||||
"muslingeskal",
|
||||
"isbod",
|
||||
"badebukser",
|
||||
"redningsvest"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "job",
|
||||
"name": "Job",
|
||||
"icon": "👩🚒",
|
||||
"words": [
|
||||
"brandmand",
|
||||
"læge",
|
||||
"politibetjent",
|
||||
"kok",
|
||||
"pilot",
|
||||
"frisør",
|
||||
"tandlæge",
|
||||
"landmand",
|
||||
"maler",
|
||||
"astronaut",
|
||||
"postbud",
|
||||
"skuespiller",
|
||||
"lærer",
|
||||
"dyrlæge",
|
||||
"tømrer",
|
||||
"dommer",
|
||||
"klovn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "skole",
|
||||
"name": "I skolen",
|
||||
"icon": "🏫",
|
||||
"words": [
|
||||
"tavle",
|
||||
"lommeregner",
|
||||
"skoletaske",
|
||||
"lineal",
|
||||
"blyant",
|
||||
"frikvarter",
|
||||
"madpakke",
|
||||
"globus",
|
||||
"lektier",
|
||||
"viskelæder",
|
||||
"gymnastiksal",
|
||||
"skolebus",
|
||||
"mikroskop",
|
||||
"saks",
|
||||
"atlas",
|
||||
"klokke",
|
||||
"penalhus"
|
||||
],
|
||||
"spion_skip": [
|
||||
"frikvarter",
|
||||
"lektier"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "eventyr",
|
||||
"name": "Eventyr",
|
||||
"icon": "🏰",
|
||||
"words": [
|
||||
"drage",
|
||||
"prinsesse",
|
||||
"slot",
|
||||
"trold",
|
||||
"heks",
|
||||
"enhjørning",
|
||||
"havfrue",
|
||||
"trylledrik",
|
||||
"ridder",
|
||||
"frø",
|
||||
"glasko",
|
||||
"den grimme ælling",
|
||||
"tinsoldat",
|
||||
"kejserens nye klæder",
|
||||
"fe",
|
||||
"skattekiste",
|
||||
"tryllestav",
|
||||
"ulv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "transport",
|
||||
"name": "Transport",
|
||||
"icon": "🚂",
|
||||
"words": [
|
||||
"tog",
|
||||
"cykel",
|
||||
"helikopter",
|
||||
"ubåd",
|
||||
"traktor",
|
||||
"rumraket",
|
||||
"sejlbåd",
|
||||
"brandbil",
|
||||
"løbehjul",
|
||||
"luftballon",
|
||||
"skraldebil",
|
||||
"færge",
|
||||
"motorcykel",
|
||||
"flyvemaskine",
|
||||
"rulleskøjter",
|
||||
"taxa",
|
||||
"kran"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "musik",
|
||||
"name": "Musik",
|
||||
"icon": "🎸",
|
||||
"words": [
|
||||
"guitar",
|
||||
"trommer",
|
||||
"klaver",
|
||||
"trompet",
|
||||
"violin",
|
||||
"mikrofon",
|
||||
"harmonika",
|
||||
"dirigent",
|
||||
"kor",
|
||||
"koncert",
|
||||
"høretelefoner",
|
||||
"saxofon",
|
||||
"blokfløjte",
|
||||
"rockstjerne",
|
||||
"luftguitar",
|
||||
"kontrabas",
|
||||
"tamburin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "danmark",
|
||||
"name": "Danmark",
|
||||
"icon": "🇩🇰",
|
||||
"words": [
|
||||
"den lille havfrue",
|
||||
"dannebrog",
|
||||
"vikingeskib",
|
||||
"lego",
|
||||
"rundetårn",
|
||||
"tivoli",
|
||||
"cykelsti",
|
||||
"pølsevogn",
|
||||
"kronborg",
|
||||
"dronning",
|
||||
"hygge",
|
||||
"klitter",
|
||||
"vindmølle",
|
||||
"kongekrone",
|
||||
"fastelavn",
|
||||
"sankthans",
|
||||
"kolonihave"
|
||||
],
|
||||
"spion_skip": [
|
||||
"hygge"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rummet",
|
||||
"name": "Rummet",
|
||||
"icon": "🚀",
|
||||
"words": [
|
||||
"astronaut",
|
||||
"planet",
|
||||
"måne",
|
||||
"rumvæsen",
|
||||
"stjerneskud",
|
||||
"satellit",
|
||||
"sort hul",
|
||||
"saturn",
|
||||
"teleskop",
|
||||
"rumstation",
|
||||
"ufo",
|
||||
"komet",
|
||||
"månelanding",
|
||||
"solsystem",
|
||||
"mars",
|
||||
"rumdragt"
|
||||
]
|
||||
}
|
||||
]
|
||||
+1
-1
@@ -16,7 +16,7 @@ from pathlib import Path
|
||||
|
||||
from fupogfakta.engine import GameError
|
||||
from tegnoggaet.engine import EMPTY_GUESS, MAX_PLAYERS, MIN_PLAYERS, RULES, RULES_STEP_MS, Game
|
||||
from tegnoggaet.themes import load_themes
|
||||
from party.themes import load_themes
|
||||
|
||||
from . import rooms, tts
|
||||
from .narrator import Narrator, generic_texts, one_of, untag
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
"""Den fælles temabank (party/data/themes.json): Tegn og Gæt som før, og nok gode ord til Spionen."""
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
from party.themes import SPY_MIN_WORDS, load_themes, spy_themes, spy_words
|
||||
|
||||
|
||||
class ThemeBankTests(SimpleTestCase):
|
||||
def test_tegn_og_gaet_gets_the_same_themes(self):
|
||||
themes = load_themes()
|
||||
self.assertEqual(len(themes), 14)
|
||||
self.assertEqual(len({t["id"] for t in themes}), 14)
|
||||
for t in themes:
|
||||
self.assertTrue(t["name"] and t["icon"] and len(t["words"]) >= 16, t["id"])
|
||||
|
||||
def test_spionen_has_enough_concrete_words(self):
|
||||
themes = spy_themes()
|
||||
self.assertGreaterEqual(len(themes), 10)
|
||||
for t in themes:
|
||||
self.assertGreaterEqual(len(t["words"]), SPY_MIN_WORDS, t["id"])
|
||||
self.assertTrue(all(" " not in w for w in t["words"]), t["id"])
|
||||
self.assertNotIn("film", {t["id"] for t in themes}) # titler er dårlige at give stikord til
|
||||
|
||||
def test_skip_list(self):
|
||||
self.assertNotIn("si", spy_words({"words": ["si", "ovn"], "spion_skip": ["si"]}))
|
||||
self.assertEqual(spy_words({"words": ["sort hul", "måne"]}), ["måne"])
|
||||
self.assertEqual(spy_words({"words": ["x"], "spion": False}), [])
|
||||
@@ -17,7 +17,7 @@ from party.narrator import Narrator, instead_of, one_of
|
||||
from party.rooms import Room
|
||||
from party.tegn import TegnRoom
|
||||
from tegnoggaet.engine import Game as TegnGame
|
||||
from tegnoggaet.themes import load_themes
|
||||
from party.themes import load_themes
|
||||
|
||||
QUESTIONS = [{"id": i, "category_id": i % 3, "category": f"Kat {i % 3}", "prompt": f"Hvad _____ {i}?", "answer": f"svar{i}",
|
||||
"decoys": ["x", "y", "z"]} for i in range(9)]
|
||||
|
||||
@@ -17,7 +17,7 @@ from tegnoggaet.engine import RULES as TEGN_RULES
|
||||
from party.narrator import LINES as FOF_LINES, TEASES, TEASES_FEST, Narrator
|
||||
from party.tegn import COUNT_LINES, FIXED_LINES, LINES, THEME_LINES, TegnRoom, warm_texts
|
||||
from tegnoggaet.engine import Game
|
||||
from tegnoggaet.themes import load_themes
|
||||
from party.themes import load_themes
|
||||
|
||||
STROKE = {"color": "#1d1b2e", "width": 0.01, "points": [[0.1, 0.1], [0.5, 0.5]]}
|
||||
NAMES = ("Qxa", "Zyb", "Wvc") # spillernavne og -ord, der ikke findes i replikkerne
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
"""Temabanken, fælles for spillene: party/data/themes.json.
|
||||
|
||||
Tegn og Gæt bruger alle ordene (eksempel-ordene til "Giv mig et forslag"). Spionen skal bruge ord, det er nemt at give
|
||||
stikord til: konkrete navneord i ét ord. Et tema med "spion": false er ikke med i Spionen, og "spion_skip" udelader
|
||||
enkelte ord.
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
THEMES_FILE = Path(__file__).resolve().parent / "data" / "themes.json"
|
||||
SPY_MIN_WORDS = 15 # et tema skal have mindst så mange gode ord for at være med i Spionen
|
||||
|
||||
|
||||
def load_themes() -> list[dict]:
|
||||
return json.loads(THEMES_FILE.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def spy_words(theme: dict) -> list[str]:
|
||||
if theme.get("spion") is False:
|
||||
return []
|
||||
skip = set(theme.get("spion_skip", []))
|
||||
return [w for w in theme.get("words", []) if " " not in w and w not in skip]
|
||||
|
||||
|
||||
def spy_themes() -> list[dict]:
|
||||
"""Temaerne til Spionen, med words = de gode stikordsord."""
|
||||
out = []
|
||||
for t in load_themes():
|
||||
words = spy_words(t)
|
||||
if len(words) >= SPY_MIN_WORDS:
|
||||
out.append({"id": t["id"], "name": t["name"], "icon": t.get("icon", ""), "words": words})
|
||||
return out
|
||||
@@ -1,45 +0,0 @@
|
||||
[
|
||||
{"id": "dyr", "name": "Dyr", "icon": "🐘", "words": [
|
||||
"kat", "hund", "elefant", "giraf", "pingvin", "krokodille", "blæksprutte", "flodhest", "pindsvin", "edderkop",
|
||||
"sommerfugl", "kænguru", "hval", "ugle", "snegl", "zebra", "papegøje", "isbjørn"]},
|
||||
{"id": "film", "name": "Film og serier", "icon": "🎬", "words": [
|
||||
"løvernes konge", "frost", "star wars", "harry potter", "titanic", "jurassic park", "find nemo", "shrek",
|
||||
"toy story", "ringenes herre", "olsen banden", "spiderman", "batman", "pippi langstrømpe", "minions",
|
||||
"mary poppins", "ghostbusters"]},
|
||||
{"id": "koekken", "name": "Ting i køkkenet", "icon": "🍳", "words": [
|
||||
"gaffel", "pande", "køleskab", "brødrister", "piskeris", "kaffemaskine", "grydeske", "ovn", "mikroovn",
|
||||
"kagerulle", "si", "osteskærer", "opvaskemaskine", "tekande", "skærebræt", "kasserolle", "køkkenrulle"]},
|
||||
{"id": "jul", "name": "Jul", "icon": "🎄", "words": [
|
||||
"juletræ", "julemand", "nisse", "rensdyr", "snemand", "gave", "risalamande", "pebernødder", "stjerne",
|
||||
"kravlenisse", "slæde", "julehjerte", "lys", "and", "juletræsfod", "mandelgave", "kalenderlys", "sne"]},
|
||||
{"id": "sport", "name": "Sport", "icon": "⚽", "words": [
|
||||
"fodbold", "håndbold", "cykelløb", "svømning", "tennis", "golf", "skihop", "boksning", "badminton",
|
||||
"basketball", "bueskydning", "surfing", "ishockey", "kunstskøjteløb", "maraton", "vægtløftning", "ridning"]},
|
||||
{"id": "mad", "name": "Mad", "icon": "🍕", "words": [
|
||||
"pizza", "pandekager", "spaghetti", "hotdog", "frikadeller", "sushi", "burger", "is", "banan", "vandmelon",
|
||||
"æbleskiver", "smørrebrød", "popcorn", "rugbrød", "flæskesteg", "kanelsnegl", "tacos", "lagkage"]},
|
||||
{"id": "strand", "name": "På stranden", "icon": "🏖️", "words": [
|
||||
"sandslot", "parasol", "badebold", "krabbe", "solcreme", "fyrtårn", "bølge", "måge", "badehåndklæde",
|
||||
"vandmand", "luftmadras", "solbriller", "spand og skovl", "muslingeskal", "isbod", "badebukser", "redningsvest"]},
|
||||
{"id": "job", "name": "Job", "icon": "👩🚒", "words": [
|
||||
"brandmand", "læge", "politibetjent", "kok", "pilot", "frisør", "tandlæge", "landmand", "maler", "astronaut",
|
||||
"postbud", "skuespiller", "lærer", "dyrlæge", "tømrer", "dommer", "klovn"]},
|
||||
{"id": "skole", "name": "I skolen", "icon": "🏫", "words": [
|
||||
"tavle", "lommeregner", "skoletaske", "lineal", "blyant", "frikvarter", "madpakke", "globus", "lektier",
|
||||
"viskelæder", "gymnastiksal", "skolebus", "mikroskop", "saks", "atlas", "klokke", "penalhus"]},
|
||||
{"id": "eventyr", "name": "Eventyr", "icon": "🏰", "words": [
|
||||
"drage", "prinsesse", "slot", "trold", "heks", "enhjørning", "havfrue", "trylledrik", "ridder", "frø",
|
||||
"glasko", "den grimme ælling", "tinsoldat", "kejserens nye klæder", "fe", "skattekiste", "tryllestav", "ulv"]},
|
||||
{"id": "transport", "name": "Transport", "icon": "🚂", "words": [
|
||||
"tog", "cykel", "helikopter", "ubåd", "traktor", "rumraket", "sejlbåd", "brandbil", "løbehjul", "luftballon",
|
||||
"skraldebil", "færge", "motorcykel", "flyvemaskine", "rulleskøjter", "taxa", "kran"]},
|
||||
{"id": "musik", "name": "Musik", "icon": "🎸", "words": [
|
||||
"guitar", "trommer", "klaver", "trompet", "violin", "mikrofon", "harmonika", "dirigent", "kor", "koncert",
|
||||
"høretelefoner", "saxofon", "blokfløjte", "rockstjerne", "luftguitar", "kontrabas", "tamburin"]},
|
||||
{"id": "danmark", "name": "Danmark", "icon": "🇩🇰", "words": [
|
||||
"den lille havfrue", "dannebrog", "vikingeskib", "lego", "rundetårn", "tivoli", "cykelsti", "pølsevogn",
|
||||
"kronborg", "dronning", "hygge", "klitter", "vindmølle", "kongekrone", "fastelavn", "sankthans", "kolonihave"]},
|
||||
{"id": "rummet", "name": "Rummet", "icon": "🚀", "words": [
|
||||
"astronaut", "planet", "måne", "rumvæsen", "stjerneskud", "satellit", "sort hul", "saturn", "teleskop",
|
||||
"rumstation", "ufo", "komet", "månelanding", "solsystem", "mars", "rumdragt"]}
|
||||
]
|
||||
@@ -5,7 +5,7 @@ from django.test import SimpleTestCase
|
||||
from fupogfakta.engine import GameError
|
||||
from tegnoggaet import engine
|
||||
from tegnoggaet.engine import Game, clean_drawing
|
||||
from tegnoggaet.themes import load_themes
|
||||
from party.themes import load_themes
|
||||
|
||||
THEMES = [{"id": "dyr", "name": "Dyr", "words": ["kat", "hund", "ko", "gris"]},
|
||||
{"id": "mad", "name": "Mad", "words": ["pizza", "is"]}]
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
"""Temaerne til Tegn og Gæt ligger i data/themes.json (eksempel-ordene bruges til "Giv mig et forslag")."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
THEMES_FILE = Path(__file__).resolve().parent / "data" / "themes.json"
|
||||
|
||||
|
||||
def load_themes() -> list[dict]:
|
||||
return json.loads(THEMES_FILE.read_text(encoding="utf-8"))
|
||||
Reference in New Issue
Block a user