Documents the GA-based seating solver's architecture, config file chain, and setup/usage for both AI assistants and human contributors. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project overview
platz (German: "Sitzplatzverteilung" / seating arrangement) is a genetic-algorithm-based
solver that assigns people to tables ("Tische") for an event, given group memberships, table
sizes/neighbor relationships, and a penalty scheme. It reads an XML order/guest list and INI
table layout, runs a small custom GA framework to search for a good seating, and writes the
result to text/CSV output files.
This is Python 2 code (print statements, ConfigParser, sets.Set, UserList,
string.split, old-style raise Exception, "msg", xrange, dict.has_key,
dict.iteritems). It will not run under Python 3 without a 2to3-style port. There is no
requirements.txt, build system, test suite, or linter configured in this repo — a Python 2
interpreter with only the standard library is sufficient to run it.
Running the program
Entry point is libs/platz.py, invoked via the wrapper scripts in bin/, which set up
environment variables and PYTHONPATH before calling it — the scripts never take a script
argument, they just launch platz.py:
bin/run(bash, for Linux/macOS) — hardcodesPLATZ=/Users/sm/develop/python/platzbin/run.bat(Windows) — hardcodesPLATZ=h:\develop\python\platzand a Python 2.4 interpreter path
Both scripts set PLATZ_CFG, PLATZ_LIBS, PLATZ_WORK and add PLATZ_LIBS to
PYTHONPATH, then run python $PLATZ_LIBS/platz.py. The hardcoded paths at the top of
these scripts must be edited to match wherever this repo is actually checked out before
they will work.
Configuration is driven by cfg/platz.cfg, which points (via $PLATZ_CFG/$PLATZ_WORK
env-var expansion) to:
cfg/zyklus.cfg— defines the GA run schedule ("Zyklus"): a sequence of actions (e=erzeugen/create,s=selektieren/select-best,S=random-select,m=mutieren/mutate,j=behalten/keep parents,z=neue Generation/advance generation) each with a count.cfg/strafen.cfg— the penalty ("Strafpunkte") table: cost of splitting a group across tables (by group size and number of splits), cost of a lone person, and per-table under-utilization penalties.- A per-run working directory under
work/<name>/(e.g.work/test1/,work/test2/) containing: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>(withVorname/Nachname/optionalTitel) 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.- Output:
TischePersonen.txt(table → seated people) andPersonenTische.csv(person → table, sorted).
Architecture
Two library modules under libs/, imported via PYTHONPATH=$PLATZ_LIBS:
ga.py — generic genetic-algorithm scaffolding
Domain-agnostic and reusable in principle:
Loesung("Solution") — base class for anything bred/mutated/selected by the GA. Meant to be subclassed;SitzplatzverteilunginStrukturdaten.pyis the concrete solution type used here.Zyklus("Cycle") — parsesAbfolge/Anzahlstrings (fromzyklus.cfg) into the ordered list of GA actions and their counts for one run.Farm— owns the population (Pool/PoolNeu), and executes aZyklusaction-by-action against instances of a given solution class (passed asKlasseplus its constructor args/kwargs).Bester()returns the fittest (max()) solution found; solutions are ordered via__cmp__onself.value.
Strukturdaten.py — domain model for this specific seating problem
Person,Gruppe(group — aSetof people, splittable viateilen()),Tisch(table — aGruppesubclass with a seat capacity and neighbor-table ids).- Container/index classes:
Personen,Gruppen,Tische, andPlaetze("Seats") which indexes tables by how many free seats they currently have, to answer "give me a table with at least N free seats" or "give me two neighboring tables that together fit two groups of given sizes" efficiently during placement/mutation. Strafliste("Penalty list") — loadsstrafen.cfgand computes penalty points for: splitting a group (gibPunkte('Trennung', ...), recursing to smaller group sizes if no exact rule is configured), a person sitting with no group-mate at their table ('allein'), a person having no group-mate at a neighboring table ('nichtNachbar'), and poor seat utilization at a table ('Tischbesetzung').Sitzplatzverteilung("Seating arrangement") — the actualLoesungsubclass bred by the GA. Constructor seats VIPs first at pinned tables, then randomly seats groups either largest-first or smallest-first (coin flip), splitting a group across two neighboring tables when no single table has enough free seats, recursively splitting further if needed, then callsbewerten()to score the arrangement perStrafliste.mutieren()picks the worst-scoring groups (SchlechteGruppenTopX), evicts them, and reseats them, hoping for a better score.speichern()writes the two output files.XMLConfig— parsesbestellung.xmlintoPersonen/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.
Data flow through platz.py (__main__)
- Read
platz.cfgto locate the other config/data files (env-var expansion viaos.path.expandvars). - Load
Zyklus(GA schedule),Strafliste(penalties),Tische(table layout). - Load
bestellung.xmlviaXMLConfig→ people, groups, VIP group, VIP seat map. - Build a
Farm(Zyklus, Sitzplatzverteilung, Tische=..., Gruppen=..., Strafen=..., VIPListe=..., VIPs=...), which runs the whole GA cycle in its constructor. - Take
Farm.Bester()and call.speichern(...)to write the output files.
Both libs/platz.py and libs/Strukturdaten.py also have self-test code under
if __name__ == '__main__': that exercises the classes directly with hardcoded sample data —
useful as a reference for how the classes are meant to be constructed and used.