/** * Die Feingliederung der Kapitel II bis IV – Vertrag und Zugriff. * * ## Wozu * * Der amtliche Katalog gliedert **nur Kapitel I** in Abschnitte. Für 230 * Fragen aus den Kapiteln II, III und IV steht `abschnitt` auf `null`, und * alles, was auf Bereichen aufsetzt, arbeitet für sie zwangsläufig auf * Kapitelebene: Wer in der Simulation an Munitionskunde scheitert, sah bis * 0.22.0 nur „Kapitel II schwach“ und konnte nur das ganze Kapitel nachüben – * 92 Fragen. * * ## Redaktionell, nicht amtlich * * Die Gliederung ist eine Einschätzung dieser Software und steht deshalb in * einer eigenen Datei, nicht im Katalog – genau wie Erklärungen und Glossar. * Der amtliche Katalog bleibt unangetastet, und die Oberfläche sagt dazu, * woher die Gruppen stammen. * * ## Vollständigkeit * * `data-pipeline/themen_bauen.py` schreibt die Datei nur, wenn **jede** Frage * der Kapitel II bis IV in genau einer Gruppe liegt. Eine lückenhafte * Gliederung wäre schlimmer als keine: „Thema üben“ überginge dann Fragen, * ohne es zu sagen. */ /** Eine Themengruppe innerhalb eines Kapitels. */ export interface Themengruppe { /** Kennung wie „II.7“ – von dieser Software vergeben, nicht amtlich. */ readonly id: string; /** Kapitel, zu dem die Gruppe gehört. */ readonly kapitel: string; readonly titel: string; readonly fragen: readonly string[]; } export interface ThemenMeta { readonly version: number; readonly stand: string; readonly hinweis: string; } export interface Themen { readonly meta: ThemenMeta; readonly gruppen: readonly Themengruppe[]; } export const THEMEN_LEER: Themen = Object.freeze({ meta: Object.freeze({ version: 0, stand: '', hinweis: '' }), gruppen: Object.freeze([]), }); /** Die Gruppen eines Kapitels, in der Reihenfolge der Datei. */ export function gruppenZuKapitel(themen: Themen, kapitelId: string): Themengruppe[] { return themen.gruppen.filter((gruppe) => gruppe.kapitel === kapitelId); } /** * Die Gruppe, in der eine Frage liegt – oder `null`. * * `null` ist der Regelfall für Kapitel I: Dort gibt es die amtlichen * Abschnitte, und eine zweite Gliederung daneben wäre eine Zahl, die * auseinanderläuft. */ export function gruppeZuFrage(themen: Themen, frageId: string): Themengruppe | null { return themen.gruppen.find((gruppe) => gruppe.fragen.includes(frageId)) ?? null; }