Web-M1-Ausbau: JSON-Gaesteliste, GA-Verlauf, Python-Serversteuerung, tische.ini-Upload

- bestellung.xml -> bestellung.json: neuer JSONConfig (loest XMLConfig ab),
  alle work-Beispiele konvertiert, Doku (CLAUDE/README/dateiformate) umgestellt
- ga.py: Beobachtungsobjekt Entwicklung zeichnet den Loesungsverlauf auf,
  neuer Schalter --show-development erzeugt Entwicklung.svg (beste/mittlere/
  schlechteste Wertigkeit ueber die Zyklus-Aktionen)
- web/main.py: neuer Endpunkt /tische-datei (tische.ini-Upload, ast.literal_eval),
  Frontend kann jetzt eine tische.ini laden
- libs/webserver.py: plattformunabhaengige start/stop/status-Steuerung der
  Web-Testinstanz (ersetzt run_web_helper.ps1), raeumt auch verwaiste
  --reload-Prozessbaeume zuverlaessig auf
- Sicherheit/Modernisierung: eval() -> ast.literal_eval in Tische/Strafliste,
  sicherer Mini-Auswerter fuer die String-Ausdruecke in zyklus.cfg,
  defaultdict(set) in Plaetze
- SVG: Tischnummer fett zentriert im Tischkreis statt "Tisch x" darueber
- Tests: JSONConfig, Entwicklung und der Zyklus-Auswerter abgedeckt (9 Tests)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Michael Stangl
2026-07-11 12:49:42 +02:00
parent 00dffc59eb
commit 9de80d2f2a
41 changed files with 5054 additions and 4033 deletions
+14 -10
View File
@@ -62,10 +62,11 @@ receives the output files — e.g. `work/test1/`, `work/test2/`, or any new fold
the same layout:
- `tische.ini` — table definitions: id, `Nummer`, `Hof` (venue/court), `Plaetze` (seats),
`Nachbarliste` (neighbor table ids), `Koordinaten`.
- `bestellung.xml` — the guest order: `<Gruppe>` blocks containing `<Person>` (with
`Vorname`/`Nachname`/optional `Titel`) and an `<Anzahl>` (reservation count per person
template — this expands into that many identical bookings), plus optional `<Tisch>` to
pin a VIP group to a specific table.
- `bestellung.json` — the guest order: `{ "gruppen": [ ... ] }`, each group holding a
`"personen"` list (each with `vorname`/`nachname`/optional `titel`), an optional
`"anzahl"` (reservation count — expands every person in the group into that many identical
bookings), an optional `"name"` (display label), and an optional `"tisch"` to pin a VIP
group to a specific table. Replaces the old `bestellung.xml`/`XMLConfig`.
- Output (written back into the same `--indir` directory): `TischePersonen.txt` (table →
seated people) and `PersonenTische.csv` (person → table, sorted).
@@ -78,7 +79,7 @@ GA cycle/penalty config:
tables (by group size and number of splits), cost of a lone person, and per-table
under-utilization penalties.
`tische.ini`/`bestellung.xml`/`TischePersonen.txt`/`PersonenTische.csv` are fixed filenames
`tische.ini`/`bestellung.json`/`TischePersonen.txt`/`PersonenTische.csv` are fixed filenames
resolved as `os.path.join(indir, ...)` in `platz.py` — they are no longer configured in
`platz.cfg`.
@@ -130,10 +131,12 @@ Domain-agnostic and reusable in principle:
touching, people as colored circles (color = group, via `SVGGruppenFarben`) placed evenly
around the inside of their table's circle. The table-to-table grid spacing is derived
from the largest table radius so tables never overlap regardless of their `Koordinaten`.
- `XMLConfig` — parses `bestellung.xml` into `Personen`/`Gruppen`/VIP-group/VIP-seat-map,
expanding each `<Person>` template by its sibling `<Anzahl>` into that many individual
bookings, and treating any `<Gruppe>` containing a `<Tisch>` tag as a VIP group pinned to
that table rather than going through normal GA placement.
- `JSONConfig` — parses `bestellung.json` into
`Personen`/`Gruppen`/VIP-group/VIP-seat-map/group-names, expanding each person by the
group's `"anzahl"` into that many individual bookings, and treating any group with a
`"tisch"` key as a VIP group pinned to that table rather than going through normal GA
placement. Returns a 5th element (`GruppenNamen`, `{Gid: display name}`) that the older
`XMLConfig` did not; `CSVConfig` (the web CSV adapter) returns the same 5-tuple.
### Data flow through `platz.py` (`__main__`)
1. Parse `--indir` (required) from the command line via `optparse`.
@@ -141,7 +144,8 @@ Domain-agnostic and reusable in principle:
`os.path.expandvars`).
3. Load `Zyklus` (GA schedule), `Strafliste` (penalties), `Tische` (table layout, from
`<indir>/tische.ini`).
4. Load `<indir>/bestellung.xml` via `XMLConfig` → people, groups, VIP group, VIP seat map.
4. Load `<indir>/bestellung.json` via `JSONConfig` → people, groups, VIP group, VIP seat
map, group names.
5. Build a `Farm(Zyklus, Sitzplatzverteilung, Tische=..., Gruppen=..., Strafen=...,
VIPListe=..., VIPs=...)`, which runs the whole GA cycle in its constructor.
6. Take `Farm.Bester()` and call `.speichern(...)` to write `<indir>/TischePersonen.txt` and