Files
Michael Stangl 740c420900 Loesungs-Ids wieder als fortlaufende Nummern 1..N (Vorgaenger separat)
- Farm._WurzelId/_KindId ersetzt durch _NeueId: jede Loesung bekommt eine
  einfache fortlaufende Nummer (Wurzeln wie Mutationskinder gleich)
- die Abstammung steckt nicht mehr in der Id, sondern im schon vorher
  gemerkten Vorgaenger (Abstammung-Knoten 'eltern'); der Baum und die
  Hervorhebung des Sieger-Astes funktionieren unveraendert
- Tests auf das neue Id-Schema umgestellt (Nummern 1..N, Abstammung ueber
  Vorgaenger), README/CLAUDE.md aktualisiert
- Beispiele neu berechnet

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 22:48:49 +02:00

6.2 KiB

platz

A genetic-algorithm-based solver that assigns people to tables ("Tische") for an event, given group memberships, table sizes/neighbor relationships, and a configurable penalty scheme. It reads a guest list (XML) and a table layout (INI), searches for a good seating using a small custom GA framework, and writes the result to text/CSV output files.

This is Python 3 code (migrated from an original Python 2 implementation). There are no third-party dependencies (standard library only), so requirements.txt is empty — it exists only so bin/install_py has something to install.

Project structure

platz/
├── bin/           # environment + launcher scripts (.bat + .sh pairs)
├── cfg/           # GA cycle definition and penalty scheme
├── libs/          # the two Python modules (ga.py, Strukturdaten.py, platz.py)
├── tests/         # unittest suite for Strukturdaten.py
└── work/          # per-run input (table layout, guest list) and output
    ├── test1/
    └── test2/
  • libs/platz.py — entry point; wires together config, input data, and the GA run.
  • libs/ga.py — generic genetic-algorithm scaffolding (Loesung, Zyklus, Farm, Entwicklung).
  • libs/Strukturdaten.py — domain model for the seating problem (Person, Gruppe, Tisch, Strafliste, Sitzplatzverteilung, JSONConfig).

Running the tests

python -m unittest discover -s tests -p "test_*.py" -v

If a stray global PYTHONPATH entry shadows the standard-library tests package name (unrelated to this project), clear it for the command, e.g. PYTHONPATH= python -m unittest discover -s tests -p "test_*.py" -v.

Setup

  1. Install a Python interpreter (py on Windows / python3 on Linux/macOS must be on PATH).

  2. Run the installer for your platform to create a .venv and install requirements.txt:

    :: Windows
    bin\install_py.bat
    
    # Linux/macOS
    bin/install_py.sh
    

All bin/ scripts derive PLATZ automatically from their own location (no path editing required) by calling setenv.bat/setenv.sh first.

Running

:: Windows
bin\activate_venv.bat
bin\platz.bat --indir work\test1
# Linux/macOS
source bin/activate_venv.sh
bin/platz.sh --indir work/test1

bin/platz.bat / bin/platz.sh call setenv to set PLATZ, PLATZ_CFG, PLATZ_LIBS, PLATZ_WORK, PLATZ_IN, PLATZ_OUT, add PLATZ_LIBS to PYTHONPATH, and then run libs/platz.py, forwarding any extra arguments (like --indir) to it.

Other helper scripts (bin/setenv.*, bin/get_cmd.*) follow the same environment convention:

  • setenv — sets all PLATZ_* environment variables and creates missing folders; sourced by every other script, not normally called directly.
  • activate_venv — activates the .venv created by install_py.
  • get_cmd — opens a new shell with the PLATZ_* environment already set.

Configuring a run

--indir <dir> is required and points at a directory containing the input files and receiving the output files for one run — e.g. work/test1/ or work/test2/:

  • tische.ini — one section per table: Nummer, Hof (venue/court), Plaetze (seat count), Nachbarliste (neighboring table ids), Koordinaten.
  • bestellung.json{ "gruppen": [ ... ] }, each group with a "personen" list (vorname/nachname/optional titel), an optional "anzahl" (how many bookings to expand each person into), an optional "name" (display label) and an optional "tisch" (pins the group as a VIP group to that table instead of placing it via the GA).

To run against a different dataset, create a new folder with a tische.ini and bestellung.json following the same layout and pass it via --indir.

The GA cycle and penalty scheme are read directly from $PLATZ_CFG/zyklus.cfg and $PLATZ_CFG/strafen.cfg (independent of --indir); there is no longer a platz.cfg indirection. The GA profile is selected with the --zyklus-art <name> switch (default: Adaptiv).

cfg/zyklus.cfg defines the GA profiles. Two styles exist:

  • static profiles (Easy, Simple) give an explicit Abfolge (sequence of actions) and matching Anzahl (counts): e create, s select best, S select randomly, m mutate, j keep parents, z advance generation.
  • the adaptive profile (Adaptiv, the default) has no fixed action list. It is recognised by a Start field and runs a generation loop: a large starting population that shrinks each generation (Schrumpfung, down to MinPopulation) and stops once the best score fails to improve by at least Schwelle for Geduld generations (or after MaxGenerationen).

Select a different profile per run, e.g. bin/platz.bat --indir work/test2 --zyklus-art Easy.

cfg/strafen.cfg defines the penalty scheme: cost of splitting a group across tables (by group size and number of splits), cost of a person sitting alone or without a group-mate at a neighboring table, and per-table seat-utilization penalties.

Output

A run writes two files into the --indir directory:

  • TischePersonen.txt — table → seated people, with venue/table/seat numbers.
  • PersonenTische.csv — person → table, sorted alphabetically by name.

Pass --tosvg to additionally write Sitzplatzverteilung.svg into the --indir directory: tables are drawn as white circles, people as colored circles inside their table's circle (color = group). See doc/docu_tests.md for example renderings.

Two more optional graphs go into the --indir directory:

  • --show-developmentEntwicklung.svg: the course of the search (best/average/worst value over time, plus a panel with the number of solutions in the pool per step).
  • --show-lineageAbstammung.svg: the mutation tree of every solution. The final best solution's ancestral branch is highlighted and labelled with its id. Every solution gets a plain running number (1..N); the ancestry is recorded via each node's stored predecessor (parent id), not encoded in the id itself, and is followed back along the highlighted branch.

Further details

See CLAUDE.md for a deeper architectural walkthrough of the GA framework and domain model, intended for AI coding assistants but equally useful for human contributors.