diff --git a/CLAUDE.md b/CLAUDE.md
index 8f2b251..6145998 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -39,24 +39,31 @@ Entry point is `libs/platz.py`, invoked via the scripts in `bin/` (each provided
"$PLATZ_LIBS/platz.py"`. This is the actual program entry point (replaces the old
`bin/run` / `bin/run.bat`, which hardcoded absolute paths and have been removed).
-Configuration is driven by `cfg/platz.cfg`, which points (via `$PLATZ_CFG`/`$PLATZ_WORK`
-env-var expansion) to:
+`libs/platz.py` requires a command-line switch `--indir
` (parsed with `optparse`,
+since this is Python 2) pointing at a directory that holds the per-run input files and
+receives the output files — e.g. `work/test1/`, `work/test2/`, or any new folder following
+the same layout:
+- `tische.ini` — table definitions: id, `Nummer`, `Hof` (venue/court), `Plaetze` (seats),
+ `Nachbarliste` (neighbor table ids), `Koordinaten`.
+- `bestellung.xml` — the guest order: `` blocks containing `` (with
+ `Vorname`/`Nachname`/optional `Titel`) and an `` (reservation count per person
+ template — this expands into that many identical bookings), plus optional `` to
+ pin a VIP group to a specific table.
+- Output (written back into the same `--indir` directory): `TischePersonen.txt` (table →
+ seated people) and `PersonenTische.csv` (person → table, sorted).
+
+`cfg/platz.cfg` (still located via `$PLATZ_CFG`, independent of `--indir`) only selects the
+GA cycle/penalty config:
- `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//` (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: `` blocks containing `` (with
- `Vorname`/`Nachname`/optional `Titel`) and an `` (reservation count per person
- template — this expands into that many identical bookings), plus optional `` to
- pin a VIP group to a specific table.
- - Output: `TischePersonen.txt` (table → seated people) and `PersonenTische.csv`
- (person → table, sorted).
+
+`tische.ini`/`bestellung.xml`/`TischePersonen.txt`/`PersonenTische.csv` are fixed filenames
+resolved as `os.path.join(indir, ...)` in `platz.py` — they are no longer configured in
+`platz.cfg`.
## Architecture
@@ -99,13 +106,16 @@ Domain-agnostic and reusable in principle:
that table rather than going through normal GA placement.
### Data flow through `platz.py` (`__main__`)
-1. Read `platz.cfg` to locate the other config/data files (env-var expansion via
+1. Parse `--indir` (required) from the command line via `optparse`.
+2. Read `platz.cfg` to locate `zyklus.cfg`/`strafen.cfg` (env-var expansion via
`os.path.expandvars`).
-2. Load `Zyklus` (GA schedule), `Strafliste` (penalties), `Tische` (table layout).
-3. Load `bestellung.xml` via `XMLConfig` → people, groups, VIP group, VIP seat map.
-4. Build a `Farm(Zyklus, Sitzplatzverteilung, Tische=..., Gruppen=..., Strafen=...,
+3. Load `Zyklus` (GA schedule), `Strafliste` (penalties), `Tische` (table layout, from
+ `/tische.ini`).
+4. Load `/bestellung.xml` via `XMLConfig` → people, groups, VIP group, VIP seat map.
+5. Build a `Farm(Zyklus, Sitzplatzverteilung, Tische=..., Gruppen=..., Strafen=...,
VIPListe=..., VIPs=...)`, which runs the whole GA cycle in its constructor.
-5. Take `Farm.Bester()` and call `.speichern(...)` to write the output files.
+6. Take `Farm.Bester()` and call `.speichern(...)` to write `/TischePersonen.txt` and
+ `/PersonenTische.csv`.
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 —
diff --git a/README.md b/README.md
index 95f5bcc..440beb9 100644
--- a/README.md
+++ b/README.md
@@ -51,18 +51,18 @@ required) by calling `setenv.bat`/`setenv.sh` first.
```bat
:: Windows
bin\activate_venv.bat
-bin\platz.bat
+bin\platz.bat --indir work\test1
```
```bash
# Linux/macOS
source bin/activate_venv.sh
-bin/platz.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`.
+`libs/platz.py`, forwarding any extra arguments (like `--indir`) to it.
Other helper scripts (`bin/setenv.*`, `bin/get_cmd.*`) follow the same environment
convention:
@@ -74,22 +74,8 @@ convention:
### Configuring a run
-`cfg/platz.cfg` selects which cycle/penalty config and which working directory
-(`work//`) to use for a given run:
-
-```ini
-[Config]
-Zyklusdatei=$PLATZ_CFG/zyklus.cfg
-Zyklusart=Easy
-Strafendatei=$PLATZ_CFG/strafen.cfg
-Tischedatei=$PLATZ_WORK/test1/tische.ini
-XMLdatei_Bestellung=$PLATZ_WORK/test1/bestellung.xml
-AusgabeTischePersonen=$PLATZ_WORK/test1/TischePersonen.txt
-AusgabePersonTisch=$PLATZ_WORK/test1/PersonenTische.csv
-```
-
-To run against a different dataset, point the `Tischedatei`/`XMLdatei_Bestellung`/output
-entries at another `work//` folder, or add a new one following the same layout:
+`--indir ` 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`.
@@ -98,6 +84,18 @@ entries at another `work//` folder, or add a new one following the same la
that template into). A `` containing a `` tag is treated as a VIP group
pinned to that table instead of being placed by the GA.
+To run against a different dataset, create a new folder with a `tische.ini` and
+`bestellung.xml` following the same layout and pass it via `--indir`.
+
+`cfg/platz.cfg` still selects the GA cycle/penalty config (independent of `--indir`):
+
+```ini
+[Config]
+Zyklusdatei=$PLATZ_CFG/zyklus.cfg
+Zyklusart=Easy
+Strafendatei=$PLATZ_CFG/strafen.cfg
+```
+
`cfg/zyklus.cfg` defines the GA run schedule ("Zyklus") as an `Abfolge` (sequence of
actions) and matching `Anzahl` (counts): `e` create, `s` select best, `S` select randomly,
`m` mutate, `j` keep parents, `z` advance generation.
@@ -108,7 +106,7 @@ a neighboring table, and per-table seat-utilization penalties.
### Output
-A run writes two files into the configured working directory:
+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.
diff --git a/bin/platz.bat b/bin/platz.bat
index 0bf7533..fe058bf 100644
--- a/bin/platz.bat
+++ b/bin/platz.bat
@@ -5,4 +5,4 @@ REM ================================================================
call "%~dp0setenv.bat"
-python "%PLATZ_LIBS%\platz.py"
+python "%PLATZ_LIBS%\platz.py" %*
diff --git a/bin/platz.sh b/bin/platz.sh
index ea804ec..62e4093 100644
--- a/bin/platz.sh
+++ b/bin/platz.sh
@@ -5,4 +5,4 @@
source "$(dirname "${BASH_SOURCE[0]}")/setenv.sh"
-python "$PLATZ_LIBS/platz.py"
+python "$PLATZ_LIBS/platz.py" "$@"
diff --git a/cfg/platz.cfg b/cfg/platz.cfg
index c3fca62..9bf04b3 100644
--- a/cfg/platz.cfg
+++ b/cfg/platz.cfg
@@ -2,9 +2,5 @@
Zyklusdatei=$PLATZ_CFG/zyklus.cfg
Zyklusart=Easy
Strafendatei=$PLATZ_CFG/strafen.cfg
-Tischedatei=$PLATZ_WORK/test1/tische.ini
-XMLdatei_Bestellung=$PLATZ_WORK/test1/bestellung.xml
-AusgabeTischePersonen=$PLATZ_WORK/test1/TischePersonen.txt
-AusgabePersonTisch=$PLATZ_WORK/test1/PersonenTische.csv
diff --git a/doc/dateiformate.md b/doc/dateiformate.md
index 90376dc..492765e 100644
--- a/doc/dateiformate.md
+++ b/doc/dateiformate.md
@@ -3,6 +3,14 @@
Referenz fuer die Eingabe- und Ausgabedateien eines `platz`-Laufs, mit Beispielen aus
`work/test1/` und `work/test2/`.
+Alle vier Dateien liegen unter dem mit `--indir ` angegebenen Verzeichnis (z.B.
+`work/test1/` oder `work/test2/`) unter festen Namen: `tische.ini`, `bestellung.xml` als
+Eingabe, `TischePersonen.txt` und `PersonenTische.csv` als Ausgabe. Beispielaufruf:
+
+```bash
+bin/platz.sh --indir work/test1
+```
+
## Tischaufstellung: `tische.ini`
Ein INI-File mit einer Sektion pro Tisch. Sektionsname ist die Tisch-Id.
diff --git a/libs/platz.py b/libs/platz.py
index 8b84aa7..32deaa2 100755
--- a/libs/platz.py
+++ b/libs/platz.py
@@ -12,13 +12,29 @@ __license__ = "Python"
from ga import *
from Strukturdaten import *
import ConfigParser
+import optparse
if __name__ == '__main__':
- # lade Vorgaben fuer Optimierungszyklus und
+ # Kommandozeilenoption --indir: Verzeichnis mit den Eingabedateien
+ # (tische.ini, bestellung.xml) und Ziel fuer die Ausgabedateien
+ # (TischePersonen.txt, PersonenTische.csv)
+ parser = optparse.OptionParser()
+ parser.add_option( "--indir", dest="indir", default=None,
+ help="Verzeichnis mit tische.ini und bestellung.xml; "
+ "dort werden auch TischePersonen.txt und PersonenTische.csv abgelegt" )
+ (options, args) = parser.parse_args()
+
+ if options.indir is None:
+ parser.error( "--indir ist erforderlich" )
+ InDir = os.path.expandvars( os.path.expanduser( options.indir ) )
+ if not os.path.isdir( InDir ):
+ parser.error( "--indir '%s' ist kein Verzeichnis" % InDir )
+
+ # lade Vorgaben fuer Optimierungszyklus und
config = ConfigParser.ConfigParser()
- ConfigPath= os.path.join( os.getenv('PLATZ_CFG'), 'platz.cfg')
+ ConfigPath= os.path.join( os.getenv('PLATZ_CFG'), 'platz.cfg')
config.read( os.path.expandvars( ConfigPath ))
Zyklusconfig = os.path.normpath( config.get( 'Config', 'Zyklusdatei' ))
@@ -30,17 +46,13 @@ if __name__ == '__main__':
## print Strafenconfig
# lade Eingabedateien
- Tischconfig = os.path.normpath(config.get( 'Config', 'Tischedatei' ))
- Tischconfig = os.path.expandvars(Tischconfig)
- Bestellung = os.path.normpath(config.get( 'Config', 'XMLdatei_Bestellung' ))
- Bestellung = os.path.expandvars( Bestellung )
+ Tischconfig = os.path.join( InDir, 'tische.ini' )
+ Bestellung = os.path.join( InDir, 'bestellung.xml' )
# lade Ausgabedateien
- AusgabeTP= os.path.normpath(config.get( 'Config', 'AusgabeTischePersonen' ))
- AusgabeTP = os.path.expandvars(AusgabeTP)
- AusgabePT = os.path.normpath(config.get( 'Config', 'AusgabePersonTisch' ))
- AusgabePT = os.path.expandvars(AusgabePT)
-
+ AusgabeTP= os.path.join( InDir, 'TischePersonen.txt' )
+ AusgabePT = os.path.join( InDir, 'PersonenTische.csv' )
+
Z = Zyklus()
Z.laden( Zyklusconfig, Zyklusart )
print Z
@@ -67,7 +79,6 @@ if __name__ == '__main__':
else:
pass
-
-
+