Compare commits
3 Commits
1e2eedc62b
...
9a52fe5550
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a52fe5550 | |||
| 405319b075 | |||
| 6e3649ed27 |
@@ -10,11 +10,27 @@ sizes/neighbor relationships, and a penalty scheme. It reads an XML order/guest
|
||||
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
|
||||
build system, test suite, or linter configured in this repo. `requirements.txt` exists but
|
||||
is empty/commented — everything used is standard library — it's there only so
|
||||
**This is Python 3 code**, migrated from an original Python 2 implementation (the git
|
||||
history / old comments may still say "Python 2" — that's now stale). Notable migration
|
||||
artifacts to be aware of when touching this code:
|
||||
- `Gruppe`, `Loesung`, and `Sitzplatzverteilung` use `@functools.total_ordering` with
|
||||
`__eq__`/`__lt__` instead of the old Python 2 `__cmp__` (Python 3 dropped `__cmp__` and
|
||||
`cmp()` entirely; `max()`/`.sort()` need rich comparisons).
|
||||
- `sets.Set` → builtin `set`; `ConfigParser` → `configparser`; `string.split` →
|
||||
`str.split`; `xrange` → `range`; `dict.has_key(k)` → `k in dict`; `dict.iteritems()` →
|
||||
`dict.items()`; old-style `raise Exception, "msg"` → `raise Exception("msg")`.
|
||||
- `Strukturdaten.LeuteAllein()` was fixed to skip people with no entry in
|
||||
`self.Gruppen.GvonPid` (e.g. VIP-group members who were never added to the regular
|
||||
`Gruppen` container) instead of letting `GruppeVonPid` raise `KeyError` — this was a
|
||||
latent bug that only surfaced once VIP data (`work/test2`) was actually exercised
|
||||
end-to-end.
|
||||
- `HandleBestellung()` had a `G.Anzahl` comparison (`G.Anzahl > 0`) that used to silently
|
||||
compare a bound method to an int under Python 2's permissive cross-type ordering;
|
||||
Python 3 raises `TypeError` for that, which is what surfaced it. Fixed to call
|
||||
`G.Anzahl()`.
|
||||
|
||||
There is no build system, test suite, or linter configured in this repo. `requirements.txt`
|
||||
exists but is empty/commented — everything used is standard library — it's there only so
|
||||
`bin/install_py.*` has something to install into the `.venv`.
|
||||
|
||||
## Running the program
|
||||
@@ -39,8 +55,8 @@ 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).
|
||||
|
||||
`libs/platz.py` requires a command-line switch `--indir <dir>` (parsed with `optparse`,
|
||||
since this is Python 2) pointing at a directory that holds the per-run input files and
|
||||
`libs/platz.py` requires a command-line switch `--indir <dir>` (parsed with `optparse`)
|
||||
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),
|
||||
@@ -79,7 +95,7 @@ Domain-agnostic and reusable in principle:
|
||||
- `Farm` — owns the population (`Pool`/`PoolNeu`), and executes a `Zyklus` action-by-action
|
||||
against instances of a given solution class (passed as `Klasse` plus its constructor
|
||||
args/kwargs). `Bester()` returns the fittest (`max()`) solution found; solutions are ordered
|
||||
via `__cmp__` on `self.value`.
|
||||
via `__eq__`/`__lt__` (`@total_ordering`) on `self.value`.
|
||||
|
||||
### `Strukturdaten.py` — domain model for this specific seating problem
|
||||
- `Person`, `Gruppe` (group — a `Set` of people, splittable via `teilen()`), `Tisch` (table —
|
||||
|
||||
@@ -5,10 +5,9 @@ given group memberships, table sizes/neighbor relationships, and a configurable
|
||||
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 2 code** (print statements, `ConfigParser`, `sets.Set`, `UserList`,
|
||||
`string.split`, old-style `raise Exception, "msg"`, `xrange`, `dict.has_key`,
|
||||
`dict.iteritems`). 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.
|
||||
**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
|
||||
|
||||
@@ -17,6 +16,7 @@ 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/
|
||||
@@ -27,6 +27,16 @@ platz/
|
||||
- `libs/Strukturdaten.py` — domain model for the seating problem (`Person`, `Gruppe`,
|
||||
`Tisch`, `Strafliste`, `Sitzplatzverteilung`, `XMLConfig`).
|
||||
|
||||
## Running the tests
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Abfolge: Kommagetrennte Liste von Aktionsbuchstaben, die den Ablauf
|
||||
# eines GA-Zyklus definieren. Jede Aktion greift auf den
|
||||
# aktuellen Loesungspool zu (siehe Farm in libs/ga.py):
|
||||
# e = erzeugen (neue zufaellige Loesungen erzeugen)
|
||||
# s = selektieren (die besten Loesungen auswaehlen)
|
||||
# S = zufaellig auswaehlen (zufaellige Loesungen auswaehlen)
|
||||
# m = mutieren (bestehende Loesungen mutieren)
|
||||
# j = behalten (alten Loesungspool als Eltern behalten)
|
||||
# z = neue Generation (Pool durch die neu erzeugten Loesungen ersetzen)
|
||||
#
|
||||
# Anzahl: Kommagetrennte Liste von Zahlen, die zu jeder Aktion in der
|
||||
# Abfolge gehoert und angibt, wie viele Loesungen davon
|
||||
# betroffen sind ('x' = Aktion braucht keine Anzahl, z.B. j/z).
|
||||
#
|
||||
[Easy]
|
||||
Abfolge='e,'+'s,z,m,j,z,'*3+'s'
|
||||
Anzahl='10,'+'5,x,2,x,x,'*3+'1'
|
||||
|
||||
+147
-150
@@ -9,12 +9,11 @@ __date__ = "$Date: $"
|
||||
__copyright__ = "Copyright (c) 2005 Michael Stangl"
|
||||
__license__ = "Python"
|
||||
|
||||
from sets import Set
|
||||
from itertools import chain
|
||||
from UserList import UserList
|
||||
from random import *
|
||||
import ConfigParser, os
|
||||
import configparser, os
|
||||
import copy
|
||||
from functools import total_ordering
|
||||
from xml.dom import minidom
|
||||
|
||||
|
||||
@@ -29,14 +28,14 @@ class Person:
|
||||
def __repr__(self):
|
||||
return ' Person %s: "%s %s %s"' % ( self.Id, self._Titel,
|
||||
self._Vorname, self._Name)
|
||||
print self.__repr__
|
||||
|
||||
@total_ordering
|
||||
class Gruppe:
|
||||
"""enthalt alle Daten zu einer Gruppe"""
|
||||
Art = 'Gruppe'
|
||||
def __init__(self, Id, Personen=[]):
|
||||
self.Id = Id
|
||||
self._Personen = Set()
|
||||
self._Personen = set()
|
||||
self._Anzahl = 0
|
||||
self.PvonId = {}
|
||||
for P in Personen:
|
||||
@@ -47,9 +46,6 @@ class Gruppe:
|
||||
result = result + repr(P.Id) + ','
|
||||
result = result + ' %s Person(en)' % (self._Anzahl)
|
||||
return result
|
||||
print self
|
||||
for P in self._Personen:
|
||||
print P
|
||||
def Person_dazu(self, P):
|
||||
self._Personen.add(P)
|
||||
self._Anzahl = self._Anzahl + 1
|
||||
@@ -59,16 +55,16 @@ class Gruppe:
|
||||
self._Personen.remove(P)
|
||||
self._Anzahl = self._Anzahl - 1
|
||||
else:
|
||||
raise KeyError, "Person ist nicht enthalten"
|
||||
raise KeyError("Person ist nicht enthalten")
|
||||
def teilen(self, NeueGroesse=0):
|
||||
if self._Anzahl == 1:
|
||||
raise IndexError, "Gruppe ist nur noch einer"
|
||||
raise IndexError("Gruppe ist nur noch einer")
|
||||
if NeueGroesse == 0:
|
||||
NeueGroesse = int(self._Anzahl/2)
|
||||
one = Gruppe( self.Id, self._Personen )
|
||||
two = Gruppe( self.Id, self._Personen )
|
||||
two._Personen.clear()
|
||||
for i in xrange(NeueGroesse):
|
||||
for i in range(NeueGroesse):
|
||||
two._Personen.add(one._Personen.pop())
|
||||
one._Anzahl = len(one._Personen)
|
||||
two._Anzahl = len(two._Personen)
|
||||
@@ -82,17 +78,17 @@ class Gruppe:
|
||||
def __iter__(self):
|
||||
for P in self._Personen:
|
||||
yield(P)
|
||||
def __cmp__(self,other):
|
||||
if self._Anzahl < other._Anzahl: return -1
|
||||
elif self._Anzahl == other._Anzahl: return 0
|
||||
else: return 1
|
||||
def __eq__(self,other):
|
||||
return self._Anzahl == other._Anzahl
|
||||
def __lt__(self,other):
|
||||
return self._Anzahl < other._Anzahl
|
||||
def __getattr__(self, attrname):
|
||||
if attrname == 'Anzahl':
|
||||
return self._Anzahl
|
||||
elif attrname == 'Id':
|
||||
return self.Id
|
||||
else:
|
||||
raise AttributeError, attrname
|
||||
raise AttributeError(attrname)
|
||||
|
||||
class Tisch(Gruppe):
|
||||
"""enthalt alle Daten zu einem Tisch"""
|
||||
@@ -103,7 +99,7 @@ class Tisch(Gruppe):
|
||||
self.Nummer = Nummer
|
||||
self.X_Koordinate = Koordinaten[0]
|
||||
self.Y_Koordinate = Koordinaten[1]
|
||||
self.Nachbarn = Set(Nachbarliste)
|
||||
self.Nachbarn = set(Nachbarliste)
|
||||
Gruppe.__init__( self, Id, pids )
|
||||
def istvoll(self, n=0):
|
||||
if ((self._Anzahl + n) == self._Plaetze ):
|
||||
@@ -126,12 +122,12 @@ class Tisch(Gruppe):
|
||||
return self._Anzahl
|
||||
def Person_dazu(self, P):
|
||||
if (self._Anzahl == self._Plaetze ):
|
||||
raise IndexError, "Tisch voll"
|
||||
raise IndexError("Tisch voll")
|
||||
else:
|
||||
Gruppe.Person_dazu( self, P )
|
||||
def Person_weg(self, P):
|
||||
if (self._Anzahl == 0 ):
|
||||
raise IndexError, "Tisch schon leer"
|
||||
raise IndexError("Tisch schon leer")
|
||||
else:
|
||||
Gruppe.Person_weg( self, P )
|
||||
def teilen(self):
|
||||
@@ -154,14 +150,14 @@ class Tisch(Gruppe):
|
||||
elif attrname == 'Id':
|
||||
return self.Id
|
||||
else:
|
||||
raise AttributeError, attrname
|
||||
raise AttributeError(attrname)
|
||||
|
||||
|
||||
# Containerklassen Personen, Gruppen, Tische, Plaetze
|
||||
class Personen:
|
||||
"""ein Pool mit mehreren Personen"""
|
||||
def __init__( self, Personen=[] ):
|
||||
self._Personen = Set(Personen)
|
||||
self._Personen = set(Personen)
|
||||
self.PvonId = {}
|
||||
for P in Personen:
|
||||
self.PvonId[ P.Id ] = P
|
||||
@@ -192,7 +188,7 @@ class Gruppen:
|
||||
self.NLeute = 0
|
||||
for G in chain( GruppenListe ):
|
||||
self.Gruppe_dazu( G )
|
||||
print "gruppen hinzugefuegt"
|
||||
print("gruppen hinzugefuegt")
|
||||
def __iter__( self):
|
||||
sortiert = self.GruppenListe[:]
|
||||
sortiert.sort()
|
||||
@@ -254,8 +250,8 @@ class Tische:
|
||||
for T in sortiert:
|
||||
yield(T)
|
||||
def laden( self, FileName ):
|
||||
## print "-- Tische laden"
|
||||
config = ConfigParser.ConfigParser()
|
||||
## print("-- Tische laden")
|
||||
config = configparser.ConfigParser()
|
||||
config.read( os.path.expanduser(FileName) )
|
||||
for section in config.sections():
|
||||
Tid = int(section)
|
||||
@@ -289,13 +285,13 @@ class Plaetze:
|
||||
self.__Groesster = Tische.Groesster
|
||||
self.__Tische = Tische
|
||||
for i in range( self.__Groesster + 1 ):
|
||||
self.__TIDsNFreie.append( Set() )
|
||||
self.__TIDsNFreie.append( set() )
|
||||
for T in Tische.TischListe:
|
||||
n_freie = T.freiePlaetze()
|
||||
self.__TIDsNFreie[n_freie].add(T.Id)
|
||||
def __repr__(self):
|
||||
result = "\n-- Tische mit n Freien Plaetzen:\n"
|
||||
for i in xrange(self.__Groesster+1):
|
||||
for i in range(self.__Groesster+1):
|
||||
result = result + " " +repr(i) + " :" + repr(self.__TIDsNFreie[i]) + "\n"
|
||||
return result
|
||||
def IdsnFreie(self, n_freie):
|
||||
@@ -381,33 +377,33 @@ class Strafliste:
|
||||
self.NichtNachbar,
|
||||
self.Allein) )
|
||||
def gibPunkte(self, Typ, Gruppengroesse=0, N_Teilungen=0, freiePlaetze=0):
|
||||
if cmp(Typ,'allein') == 0:
|
||||
if Typ == 'allein':
|
||||
return self.Allein
|
||||
elif cmp(Typ,'nichtNachbar')== 0:
|
||||
elif Typ == 'nichtNachbar':
|
||||
return self.NichtNachbar
|
||||
elif cmp(Typ,'Tischbesetzung')== 0:
|
||||
elif Typ == 'Tischbesetzung':
|
||||
try:
|
||||
return self.TischWert[freiePlaetze]
|
||||
except KeyError:
|
||||
return 0
|
||||
elif cmp(Typ,'Trennung')== 0:
|
||||
elif Typ == 'Trennung':
|
||||
if (N_Teilungen == 0):
|
||||
return 0
|
||||
elif (N_Teilungen == 1) & (Gruppengroesse < 2):
|
||||
raise IndexError, "Gruppe sind mindestens zwei Leute"
|
||||
raise IndexError("Gruppe sind mindestens zwei Leute")
|
||||
elif (N_Teilungen == 2) & (Gruppengroesse < 3):
|
||||
raise IndexError, "mindestens drei Leute noetig"
|
||||
raise IndexError("mindestens drei Leute noetig")
|
||||
elif (N_Teilungen > 2):
|
||||
return -50
|
||||
if self.GruppenTrennen[N_Teilungen].has_key(Gruppengroesse):
|
||||
if Gruppengroesse in self.GruppenTrennen[N_Teilungen]:
|
||||
return self.GruppenTrennen[N_Teilungen][Gruppengroesse]
|
||||
else:
|
||||
return self.gibPunkte('Trennung',Gruppengroesse-1, N_Teilungen)
|
||||
else:
|
||||
raise IndexError, "Bezeichner gibts nicht"
|
||||
raise IndexError("Bezeichner gibts nicht")
|
||||
def laden( self, FileName ):
|
||||
print "-- Strafliste laden"
|
||||
config = ConfigParser.ConfigParser()
|
||||
print("-- Strafliste laden")
|
||||
config = configparser.ConfigParser()
|
||||
config.read( os.path.expanduser(FileName) )
|
||||
self.NichtNachbar = eval(config.get( 'Globals', 'NichtNachbar' ))
|
||||
self.Allein = eval(config.get( 'Globals', 'Allein' ))
|
||||
@@ -417,6 +413,7 @@ class Strafliste:
|
||||
|
||||
|
||||
# Sitzplatzverteilung, bestehend aus den Einzelelementen
|
||||
@total_ordering
|
||||
class Sitzplatzverteilung:
|
||||
"""Loesungsvorschlag fuer eine Sitzplatzordung"""
|
||||
|
||||
@@ -432,11 +429,11 @@ class Sitzplatzverteilung:
|
||||
- zuerst alle kleinsten Gruppen, da man die nicht mehr teilen
|
||||
sollte
|
||||
"""
|
||||
#print "+ Sitzplatzverteilung\n"
|
||||
#print("+ Sitzplatzverteilung\n")
|
||||
if Gruppen.NLeute > Tische.NStuehle:
|
||||
print "Anzahl der Leute:", Gruppen.NLeute
|
||||
print "Anzahl der Plaetze:", Tische.NStuehle
|
||||
raise IndexError, "zu wenig Stuehle"
|
||||
print("Anzahl der Leute:", Gruppen.NLeute)
|
||||
print("Anzahl der Plaetze:", Tische.NStuehle)
|
||||
raise IndexError("zu wenig Stuehle")
|
||||
|
||||
self.MutationsGroesse = 2
|
||||
self.VIP = VIPs
|
||||
@@ -464,7 +461,7 @@ class Sitzplatzverteilung:
|
||||
|
||||
# die Sitzplatzverteilung bepunkten
|
||||
self.bewerten()
|
||||
print "erzeugt: ", self.value
|
||||
print("erzeugt: ", self.value)
|
||||
def __repr__(self):
|
||||
"""Ausgabe der Sitzplatzverteilung an der Konsole"""
|
||||
r = "-- Sitzplatzverteilung:\n"
|
||||
@@ -546,18 +543,18 @@ class Sitzplatzverteilung:
|
||||
self.GruppenSetzen( SchlechteGruppen )
|
||||
self.bewerten()
|
||||
|
||||
print "mutiert: ", self.value
|
||||
print("mutiert: ", self.value)
|
||||
return self
|
||||
def __cmp__(self,other):
|
||||
if self.value < other.value: return -1
|
||||
elif self.value == other.value: return 0
|
||||
else: return 1
|
||||
def __eq__(self,other):
|
||||
return self.value == other.value
|
||||
def __lt__(self,other):
|
||||
return self.value < other.value
|
||||
def bewerten(self):
|
||||
"""Errechnet die momentane Wertigkeit der Sitzplaetze"""
|
||||
self.GesamtWertSet( 0 )
|
||||
# Tische bewerten
|
||||
for T in self.Tische:
|
||||
#print T
|
||||
#print(T)
|
||||
n_freie = T.freiePlaetze()
|
||||
Strafpunkte = self.Strafen.gibPunkte( 'Tischbesetzung', freiePlaetze=n_freie )
|
||||
self.TischWertSet( T, Strafpunkte )
|
||||
@@ -610,7 +607,7 @@ class Sitzplatzverteilung:
|
||||
# uns setzte sie auf freie Plaetze
|
||||
while len(Gruppenliste) > 0:
|
||||
wahl = choice(['grosse', 'kleine'])
|
||||
if cmp(wahl,'grosse')== 0:
|
||||
if wahl == 'grosse':
|
||||
G = Gruppenliste.pop(0)
|
||||
else:
|
||||
G = Gruppenliste.pop(-1)
|
||||
@@ -671,7 +668,7 @@ class Sitzplatzverteilung:
|
||||
Ids = self.Gid_Tid[Gruppe.Id]
|
||||
Ids.add(Tisch.Id)
|
||||
except KeyError:
|
||||
s = Set()
|
||||
s = set()
|
||||
s.add(Tisch.Id)
|
||||
self.Gid_Tid[Gruppe.Id] = s
|
||||
def GruppeEntfernen(self, Gruppe):
|
||||
@@ -751,12 +748,16 @@ class Sitzplatzverteilung:
|
||||
Anzahl_von_Gid = {}
|
||||
Gids = []
|
||||
for P in Tisch:
|
||||
try:
|
||||
G = self.Gruppen.GruppeVonPid(P.Id)
|
||||
except KeyError:
|
||||
# Person gehoert zu keiner Gruppe in self.Gruppen (z.B. VIP)
|
||||
continue
|
||||
try:
|
||||
Anzahl_von_Gid[G.Id] = Anzahl_von_Gid[G.Id] + 1
|
||||
except KeyError:
|
||||
Anzahl_von_Gid[G.Id] = 1
|
||||
for Gid, Anzahl in Anzahl_von_Gid.iteritems():
|
||||
for Gid, Anzahl in Anzahl_von_Gid.items():
|
||||
if Anzahl == 1:
|
||||
Gids.append(Gid)
|
||||
return Gids
|
||||
@@ -779,7 +780,7 @@ class Sitzplatzverteilung:
|
||||
def VIPsSetzen(self, VIPListe, VIPs, Tische ):
|
||||
"""setze die VIPs auf Ihre Plaetze"""
|
||||
#print " VIPsSetzen:"
|
||||
for PersonId, TischId in VIPListe.iteritems():
|
||||
for PersonId, TischId in VIPListe.items():
|
||||
#print " VIPsSetzen: PersonId", PersonId
|
||||
#print " VIPsSetzen: TischId", TischId
|
||||
Person = VIPs.PersonVonPid(PersonId)
|
||||
@@ -791,7 +792,7 @@ class Sitzplatzverteilung:
|
||||
RListe=[]
|
||||
Wertigkeit=[]
|
||||
# TODO filter verwenden
|
||||
for Id, Wert in Liste.iteritems():
|
||||
for Id, Wert in Liste.items():
|
||||
if Wert <= Min:
|
||||
RListe.append(Id)
|
||||
Wertigkeit.append(Wert)
|
||||
@@ -830,13 +831,13 @@ class XMLConfig:
|
||||
GN = Gruppen()
|
||||
VIPGruppe = Gruppe( 0 )
|
||||
|
||||
print '-HandleBestellung'
|
||||
print('-HandleBestellung')
|
||||
AlleGruppenXML = Bestellung.getElementsByTagName("Gruppe")
|
||||
PID = 0
|
||||
GID = 0
|
||||
for GruppeXML in AlleGruppenXML:
|
||||
GID = GID + 1
|
||||
print '-- GID ' + repr(GID)
|
||||
print('-- GID ' + repr(GID))
|
||||
G = Gruppe( GID )
|
||||
|
||||
IsVip = False
|
||||
@@ -844,11 +845,11 @@ class XMLConfig:
|
||||
for Node in GruppeXML.childNodes:
|
||||
if Node.nodeName == 'Tisch':
|
||||
TischNr = self.getText(Node.childNodes)
|
||||
print 'TischNr:', TischNr
|
||||
print('TischNr:', TischNr)
|
||||
IsVip = True
|
||||
if Node.nodeName == 'Anzahl':
|
||||
AnzahlReservierungen = int(self.getText(Node.childNodes))
|
||||
print 'Anzahl der Reservierungen:', AnzahlReservierungen
|
||||
print('Anzahl der Reservierungen:', AnzahlReservierungen)
|
||||
IsContingent = True
|
||||
|
||||
for Node in GruppeXML.childNodes:
|
||||
@@ -857,7 +858,7 @@ class XMLConfig:
|
||||
for i in range(int(AnzahlReservierungen)):
|
||||
NRes = NRes + 1
|
||||
PID = PID + 1
|
||||
print "PID =" + repr(PID)
|
||||
print("PID =" + repr(PID))
|
||||
info = self.handlePersonNode( Node )
|
||||
|
||||
Vorname = info["Vorname"]
|
||||
@@ -871,15 +872,15 @@ class XMLConfig:
|
||||
else:
|
||||
PN.PersonAdd( P )
|
||||
G.Person_dazu( P )
|
||||
if (G.Anzahl > 0) & (IsVip != True):
|
||||
if (G.Anzahl() > 0) & (IsVip != True):
|
||||
GN.Gruppe_dazu( G )
|
||||
if IsVip == True:
|
||||
GID = GID - 1
|
||||
print PN
|
||||
print GN
|
||||
print VIPGruppe
|
||||
print VipHash
|
||||
print '=========='
|
||||
print(PN)
|
||||
print(GN)
|
||||
print(VIPGruppe)
|
||||
print(VipHash)
|
||||
print('==========')
|
||||
return [ PN, GN, VIPGruppe, VipHash ]
|
||||
def laden(self, Bestellung):
|
||||
"""lese alle Eingangsdaten aus einem XML File ein"""
|
||||
@@ -891,113 +892,113 @@ class XMLConfig:
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
print "\n-- Erzeuge Personen:"
|
||||
print("\n-- Erzeuge Personen:")
|
||||
P1 = Person( 1, 'Michael', 'Stangl')
|
||||
P2 = Person( 2, 'Magnus', 'Mueller')
|
||||
P3 = Person( 3, 'Bernd Robert', 'Hoehn')
|
||||
P4 = Person( 4, 'Heinz', 'Ruehmann')
|
||||
P5 = Person( 5, 'Franz', 'Bruegge')
|
||||
P6 = Person( 6, 'Hubert', 'K')
|
||||
print P1
|
||||
print P2
|
||||
print P3
|
||||
print P4
|
||||
print P5
|
||||
print P6
|
||||
print(P1)
|
||||
print(P2)
|
||||
print(P3)
|
||||
print(P4)
|
||||
print(P5)
|
||||
print(P6)
|
||||
|
||||
print "\n-- Mehrzahl von Personen:"
|
||||
print("\n-- Mehrzahl von Personen:")
|
||||
PN = Personen([P1, P2, P3, P4, P5, P6])
|
||||
print PN
|
||||
print(PN)
|
||||
|
||||
print "\n-- Erzeuge Gruppen mit den Personen:"
|
||||
print("\n-- Erzeuge Gruppen mit den Personen:")
|
||||
G1 = Gruppe( 1, [P1, P2] )
|
||||
G1.Person_dazu( P3 )
|
||||
G2 = Gruppe( 2 )
|
||||
G2.Person_dazu( P4 )
|
||||
G3 = Gruppe( 3, [P5,P6] )
|
||||
|
||||
print "\n-- Stelle Gruppen dar:"
|
||||
print G1
|
||||
print G2
|
||||
print G3
|
||||
print("\n-- Stelle Gruppen dar:")
|
||||
print(G1)
|
||||
print(G2)
|
||||
print(G3)
|
||||
|
||||
print "\n-- Durchlaufe Gruppe 3:"
|
||||
print("\n-- Durchlaufe Gruppe 3:")
|
||||
for P in G3:
|
||||
print P
|
||||
print(P)
|
||||
|
||||
print "\n-- Mache Liste der Gruppen:"
|
||||
print("\n-- Mache Liste der Gruppen:")
|
||||
GN = Gruppen([G1,G2,G3])
|
||||
print GN
|
||||
print(GN)
|
||||
|
||||
print "\n-- Durchlaufe Gruppen sortiert:"
|
||||
print("\n-- Durchlaufe Gruppen sortiert:")
|
||||
for G in GN:
|
||||
print G
|
||||
print(G)
|
||||
|
||||
print "\n-- Teile Gruppe:"
|
||||
print("\n-- Teile Gruppe:")
|
||||
[GX, GY] = G1.teilen()
|
||||
print GX
|
||||
print GY
|
||||
print(GX)
|
||||
print(GY)
|
||||
[GX, GY] = G1.teilen(3)
|
||||
print GX
|
||||
print GY
|
||||
print(GX)
|
||||
print(GY)
|
||||
|
||||
print "\n-- Erzeuge Tische mit Personen:"
|
||||
print("\n-- Erzeuge Tische mit Personen:")
|
||||
T1 = Tisch( 1, Plaetze=5, Koordinaten=(1,2), pids=[P1, P2], Nachbarliste=[2] )
|
||||
print T1
|
||||
print(T1)
|
||||
|
||||
T2 = Tisch( 2, Plaetze=4, Koordinaten=(3,2), Nachbarliste=[1,3] )
|
||||
T2.Person_dazu( P3 )
|
||||
print T2
|
||||
print(T2)
|
||||
T2.Person_dazu( P4 )
|
||||
print T2
|
||||
print(T2)
|
||||
T2.Person_weg( P4 )
|
||||
print T2
|
||||
print(T2)
|
||||
T3 = Tisch( 3, Plaetze=2, Koordinaten=(5,2), Nachbarliste=[2] )
|
||||
print "\n-- Ist Tisch 2 voll oder leer?:"
|
||||
print "ist voll = ", T2.istvoll()
|
||||
print "ist leer = ", T2.istleer()
|
||||
print("\n-- Ist Tisch 2 voll oder leer?:")
|
||||
print("ist voll = ", T2.istvoll())
|
||||
print("ist leer = ", T2.istleer())
|
||||
|
||||
print "\n-- Wieviele Plaetze sind an Tisch 1 noch frei ?:"
|
||||
print "Freie Plaetze = ", T1.freiePlaetze()
|
||||
print "Besetzte Plaetze = ", T1.besetztePlaetze()
|
||||
print("\n-- Wieviele Plaetze sind an Tisch 1 noch frei ?:")
|
||||
print("Freie Plaetze = ", T1.freiePlaetze())
|
||||
print("Besetzte Plaetze = ", T1.besetztePlaetze())
|
||||
|
||||
print "\n-- Stelle Tische dar:"
|
||||
print T1
|
||||
print T2
|
||||
print T3
|
||||
print "\n-- Ist Person Nummer 3 an Tisch 1 ?:"
|
||||
print P1 in T1
|
||||
print "-- Ist Person Nummer 4 an Tisch 1 ?:"
|
||||
print P4 in T1
|
||||
print("\n-- Stelle Tische dar:")
|
||||
print(T1)
|
||||
print(T2)
|
||||
print(T3)
|
||||
print("\n-- Ist Person Nummer 3 an Tisch 1 ?:")
|
||||
print(P1 in T1)
|
||||
print("-- Ist Person Nummer 4 an Tisch 1 ?:")
|
||||
print(P4 in T1)
|
||||
|
||||
TE = Tische([T1,T2,T3])
|
||||
print TE
|
||||
print(TE)
|
||||
|
||||
print "\n-- Hole Tisch 2 aufgrund seiner Id :"
|
||||
print("\n-- Hole Tisch 2 aufgrund seiner Id :")
|
||||
TX = TE.vonId( 2 )
|
||||
print TX
|
||||
print(TX)
|
||||
|
||||
print "\n-- Hole Gruppe 2 aufgrund ihrer Id :"
|
||||
print("\n-- Hole Gruppe 2 aufgrund ihrer Id :")
|
||||
GX = GN.vonId( 2 )
|
||||
print GX
|
||||
print(GX)
|
||||
|
||||
print "\n-- Hole Person 2 aufgrund ihrer Id aus den Gruppen:"
|
||||
print("\n-- Hole Person 2 aufgrund ihrer Id aus den Gruppen:")
|
||||
PX = GN.PersonVonPid( 2 )
|
||||
print PX
|
||||
print(PX)
|
||||
|
||||
print "\n-- schau wo noch mindestens 3 Plaetze frei sind:"
|
||||
print("\n-- schau wo noch mindestens 3 Plaetze frei sind:")
|
||||
info = Plaetze(TE)
|
||||
print info.mindestensNFreie( 3 )
|
||||
print(info.mindestensNFreie( 3 ))
|
||||
|
||||
print "\n-- schau wo zwei Gruppen bestimmter Groesse nebeneinander sitzen koennen:"
|
||||
print " zwei neben drei:"
|
||||
print("\n-- schau wo zwei Gruppen bestimmter Groesse nebeneinander sitzen koennen:")
|
||||
print(" zwei neben drei:")
|
||||
[TX,TY] = info.NachbarTische(2, 3)
|
||||
print TX
|
||||
print TY
|
||||
print " drei neben zwei:"
|
||||
print(TX)
|
||||
print(TY)
|
||||
print(" drei neben zwei:")
|
||||
[TX,TY] = info.NachbarTische(3, 2)
|
||||
print TX
|
||||
print TY
|
||||
print(TX)
|
||||
print(TY)
|
||||
|
||||
P1 = Person( 1, 'Michael', 'Stangl')
|
||||
P2 = Person( 2, 'Magnus', 'Mueller')
|
||||
@@ -1020,27 +1021,27 @@ if __name__ == '__main__':
|
||||
# G1 G2 G3 G4
|
||||
# <3> <2> <2> <6>
|
||||
#
|
||||
print "\n-- Mache Gruppen:"
|
||||
print("\n-- Mache Gruppen:")
|
||||
VIPGruppe = ( Gruppe( 1, [P1, P2, P3] ) )
|
||||
G2 = ( Gruppe( 2, [P4, P5] ) )
|
||||
G3 = ( Gruppe( 3, [P6, P7] ) )
|
||||
G4 = ( Gruppe( 4, [P8, P9, P10, P11, P12, P13] ) )
|
||||
GN = Gruppen([G2,G3,G4])
|
||||
print GN
|
||||
print(GN)
|
||||
|
||||
print "\n-- Mache Tische:"
|
||||
print("\n-- Mache Tische:")
|
||||
T1 = ( Tisch( 1, Plaetze=3, Koordinaten=(1,1), Nachbarliste=[2] ) )
|
||||
T2 = ( Tisch( 2, Plaetze=5, Koordinaten=(2,1), Nachbarliste=[1,3] ) )
|
||||
T3 = ( Tisch( 3, Plaetze=3, Koordinaten=(3,1), Nachbarliste=[2,4] ) )
|
||||
T4 = ( Tisch( 4, Plaetze=4, Koordinaten=(4,1), Nachbarliste=[3] ) )
|
||||
|
||||
TE = Tische([T1,T2,T3,T4])
|
||||
print TE
|
||||
print(TE)
|
||||
|
||||
print "\n-- Mache Listen:"
|
||||
print("\n-- Mache Listen:")
|
||||
# Personenid - Tischid
|
||||
VIPListePT = { 3:1, 2:1, 1:1 }
|
||||
print "VIP Liste:", VIPListePT
|
||||
print("VIP Liste:", VIPListePT)
|
||||
|
||||
# Strafliste
|
||||
# die Teilung einer grossen Gruppe ist nicht so schlimm
|
||||
@@ -1053,40 +1054,36 @@ if __name__ == '__main__':
|
||||
# Ein Platz an einem Tisch frei ist schlechter als zwei Plaetze frei
|
||||
TischWertigkeiten={ 1:-3, 2:-2, 3:-1 }
|
||||
SL = Strafliste(GruppenTrennen=Teilung, NichtNachbar=-3, Allein=-30, TischWert=TischWertigkeiten)
|
||||
print SL
|
||||
print(SL)
|
||||
|
||||
print "\n-- Teste Strafliste:"
|
||||
print "SL.gibPunkte('Trennung', 7,1):", SL.gibPunkte('Trennung', 7,1)
|
||||
print "SL.gibPunkte('Trennung', 5,1):", SL.gibPunkte('Trennung', 5,1)
|
||||
print "SL.gibPunkte('Trennung', 3,1):", SL.gibPunkte('Trennung', 3,1)
|
||||
print("\n-- Teste Strafliste:")
|
||||
print("SL.gibPunkte('Trennung', 7,1):", SL.gibPunkte('Trennung', 7,1))
|
||||
print("SL.gibPunkte('Trennung', 5,1):", SL.gibPunkte('Trennung', 5,1))
|
||||
print("SL.gibPunkte('Trennung', 3,1):", SL.gibPunkte('Trennung', 3,1))
|
||||
try:
|
||||
print "SL.gibPunkte('Trennung',(1,1):",SL.gibPunkte('Trennung',1,1)
|
||||
print("SL.gibPunkte('Trennung',(1,1):",SL.gibPunkte('Trennung',1,1))
|
||||
except IndexError:
|
||||
print "Gruppe sind mindestens zwei"
|
||||
print("Gruppe sind mindestens zwei")
|
||||
|
||||
print "\n-- Baue Sitzplatzverteilung:"
|
||||
print("\n-- Baue Sitzplatzverteilung:")
|
||||
SV = Sitzplatzverteilung(Tische=TE, Gruppen=GN, Strafen=SL,
|
||||
VIPListe=VIPListePT, VIPs=VIPGruppe)
|
||||
print SV
|
||||
print(SV)
|
||||
|
||||
print "\n-- Mutiere Sitzplatzverteilung:"
|
||||
print("\n-- Mutiere Sitzplatzverteilung:")
|
||||
SV.mutieren()
|
||||
print SV
|
||||
print(SV)
|
||||
|
||||
print "\n-- Gibt die 3 Tische mit der schlechtesten Wertung:"
|
||||
print("\n-- Gibt die 3 Tische mit der schlechtesten Wertung:")
|
||||
[TischIds, Wertigkeit]=SV.SchlechteTischeTopX(3)
|
||||
print "TischIds:", TischIds
|
||||
print "Wertigkeit:", Wertigkeit
|
||||
print("TischIds:", TischIds)
|
||||
print("Wertigkeit:", Wertigkeit)
|
||||
|
||||
print "\n-- Gibt die Gruppen mit der schlechtesten Wertung:"
|
||||
print("\n-- Gibt die Gruppen mit der schlechtesten Wertung:")
|
||||
[GruppenIds, Wertigkeit]=SV.SchlechteGruppenTopX(3)
|
||||
print "GruppenIds:", GruppenIds
|
||||
print "Wertigkeit:", Wertigkeit
|
||||
print("GruppenIds:", GruppenIds)
|
||||
print("Wertigkeit:", Wertigkeit)
|
||||
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+45
-46
@@ -4,9 +4,9 @@ Enthaelt alle Datenstrukturen um die einen genetischen Algorithmus darzustellen
|
||||
"""
|
||||
from random import *
|
||||
from itertools import chain
|
||||
from string import split
|
||||
from copy import deepcopy
|
||||
import ConfigParser, os
|
||||
from functools import total_ordering
|
||||
import configparser, os
|
||||
|
||||
|
||||
__author__ = "Michael Stangl"
|
||||
@@ -15,29 +15,30 @@ __date__ = "$Date: $"
|
||||
__copyright__ = "Copyright (c) 2005 Michael Stangl"
|
||||
__license__ = "Python"
|
||||
|
||||
@total_ordering
|
||||
class Loesung:
|
||||
"""ein einfaches Loesungsobjekt. Taugt um es als Superklasse zu ueberladen"""
|
||||
def __init__(self, *Argumente, **keywords):
|
||||
self.Id = -1 * randint(1,100)
|
||||
self.value = self.Id
|
||||
print " initialisiere Loesung " + repr(self.Id)
|
||||
print(" initialisiere Loesung " + repr(self.Id))
|
||||
def mutieren(self):
|
||||
print " mutiere Loesung " + repr(self.Id)
|
||||
print(" mutiere Loesung " + repr(self.Id))
|
||||
self.Id = -1 * randint(1,100)
|
||||
self.value = self.Id
|
||||
return self
|
||||
def kreuzen(self,obj):
|
||||
print " kreuze Loesung " + repr(self.Id)
|
||||
print(" kreuze Loesung " + repr(self.Id))
|
||||
def laden(self):
|
||||
print " lade Loesung " + repr(self.Id)
|
||||
print(" lade Loesung " + repr(self.Id))
|
||||
def speichern(self):
|
||||
print " speichere Loesung " + repr(self.Id)
|
||||
print(" speichere Loesung " + repr(self.Id))
|
||||
def __repr__(self):
|
||||
return ' L '+ repr(self.Id)
|
||||
def __cmp__(self,other):
|
||||
if self.value < other.value: return -1
|
||||
elif self.value == other.value: return 0
|
||||
else: return 1
|
||||
def __eq__(self,other):
|
||||
return self.value == other.value
|
||||
def __lt__(self,other):
|
||||
return self.value < other.value
|
||||
|
||||
class Zyklus:
|
||||
"""Definiert wie ein Zyklus ablaufen soll:
|
||||
@@ -49,8 +50,8 @@ class Zyklus:
|
||||
Abfolge='e,m,s',
|
||||
Anzahl='10,10,10'):
|
||||
self.Name = Name
|
||||
self.Abfolge = split(Abfolge, ',')
|
||||
self.Anzahl = split(Anzahl,',')
|
||||
self.Abfolge = Abfolge.split(',')
|
||||
self.Anzahl = Anzahl.split(',')
|
||||
def __repr__(self):
|
||||
return( "Zyklus: %s\n"
|
||||
" Zyklusabfolge: %s\n"
|
||||
@@ -59,7 +60,7 @@ class Zyklus:
|
||||
self.Abfolge,
|
||||
self.Anzahl ) )
|
||||
def laden(self, FileName, ZyklusName):
|
||||
config = ConfigParser.ConfigParser()
|
||||
config = configparser.ConfigParser()
|
||||
ZyklusPath= os.path.split( FileName )
|
||||
ZyklusPath= os.path.join( FileName )
|
||||
config.read( ZyklusPath )
|
||||
@@ -102,50 +103,50 @@ class Farm:
|
||||
pass
|
||||
def LoesungenErzeugen(self, N, Klasse, *Arguments, **keywords):
|
||||
""" Erzeuge Loesungen"""
|
||||
for i in xrange(N):
|
||||
for i in range(N):
|
||||
L = Klasse( *Arguments, **keywords )
|
||||
self.Pool.append(L)
|
||||
#print repr(len(self.Pool)) + ' Loesungsobjekte erzeugt'
|
||||
#print(repr(len(self.Pool)) + ' Loesungsobjekte erzeugt')
|
||||
def LoesungenKreuzen(self,N):
|
||||
"""mache aus zwei Loesungen eine neue"""
|
||||
#print "+ Loesungen kreuzen"
|
||||
for i in xrange(N):
|
||||
#print("+ Loesungen kreuzen")
|
||||
for i in range(N):
|
||||
self.Pool.append(self.Pool[i].kreuzen())
|
||||
def LoesungenMutieren(self, N):
|
||||
"""veraendere die Loesung, so dass sie hoffentlich besser wird"""
|
||||
print "+ Loesungen mutieren: ", N
|
||||
for n in xrange(N):
|
||||
#print " -"+repr(n+1)+" mal"
|
||||
print("+ Loesungen mutieren: ", N)
|
||||
for n in range(N):
|
||||
#print(" -"+repr(n+1)+" mal")
|
||||
for L in chain(self.Pool):
|
||||
O = deepcopy(L)
|
||||
self.PoolNeu.append(O.mutieren())
|
||||
#print self
|
||||
#print(self)
|
||||
def LoesungenBehalten(self):
|
||||
"""Behalte alle Eltern aus dem alten Pool"""
|
||||
print "+ alten Loesungspool behalten"
|
||||
print("+ alten Loesungspool behalten")
|
||||
self.PoolNeu = self.PoolNeu + self.Pool
|
||||
#print self
|
||||
#print(self)
|
||||
def NeueGeneration(self):
|
||||
"""Loesche alle bisherigen Eltern und mache einen neuen Zyklus"""
|
||||
print "+ Neue Generation erzeugen"
|
||||
print("+ Neue Generation erzeugen")
|
||||
self.Pool = self.PoolNeu
|
||||
self.PoolNeu = []
|
||||
#print self
|
||||
#print "---------------"
|
||||
#print(self)
|
||||
#print("---------------")
|
||||
def LoesungenAuswaehlen(self, N):
|
||||
"""Selektiere die besten Loesungen"""
|
||||
print "+ die besten -", repr(N) +" - Loesungen auswaehlen -"
|
||||
for i in xrange(N):
|
||||
print("+ die besten -", repr(N) +" - Loesungen auswaehlen -")
|
||||
for i in range(N):
|
||||
L = max(self.Pool)
|
||||
self.PoolNeu.append(L)
|
||||
self.Pool.remove(L)
|
||||
#print self
|
||||
#print(self)
|
||||
def LoesungenZufaelligAuswaehlen(self, N):
|
||||
"""Selektiere zufaellig Loesungen"""
|
||||
print "+ zufaellig auswaehlen -"+ repr(N) + "-"
|
||||
for i in xrange(N):
|
||||
print("+ zufaellig auswaehlen -"+ repr(N) + "-")
|
||||
for i in range(N):
|
||||
self.PoolNeu.append(choice(self.Pool))
|
||||
#print self
|
||||
#print(self)
|
||||
def __repr__(self):
|
||||
"""Drucke die Farm am Bildschirm aus"""
|
||||
return( " gewaehlte Objekte (%d): %s\n"
|
||||
@@ -153,15 +154,15 @@ class Farm:
|
||||
% ( len(self.PoolNeu), self.PoolNeu,
|
||||
len(self.Pool), self.Pool))
|
||||
def laden(self):
|
||||
print "+ laden"
|
||||
print("+ laden")
|
||||
def speichern(self):
|
||||
print "+ speichern"
|
||||
print("+ speichern")
|
||||
def Bester(self):
|
||||
return max(self.Pool)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "\n-- Erzeuge Zyklus:"
|
||||
print("\n-- Erzeuge Zyklus:")
|
||||
#Z = Zyklus( Name='Easy',
|
||||
#Abfolge='e,s,+,m,j,S,+',
|
||||
#Anzahl='10,5,x,2,x,5,x'
|
||||
@@ -170,25 +171,23 @@ if __name__ == '__main__':
|
||||
Abfolge='e,'+'s,z,m,j,z,'*3+'s',
|
||||
Anzahl='10,'+'5,x,2,x,x,'*3+'1'
|
||||
)
|
||||
print Z
|
||||
print(Z)
|
||||
|
||||
print "\n-- Erzeuge Loesungen:"
|
||||
print("\n-- Erzeuge Loesungen:")
|
||||
L1 = Loesung()
|
||||
L2 = Loesung()
|
||||
L3 = Loesung()
|
||||
print L1, L2, L3
|
||||
print 'L1 > L2 =', L1 > L2
|
||||
print 'L2 > L3 =', L2 > L3
|
||||
print 'L1 > L3 =', L1 > L3
|
||||
print(L1, L2, L3)
|
||||
print('L1 > L2 =', L1 > L2)
|
||||
print('L2 > L3 =', L2 > L3)
|
||||
print('L1 > L3 =', L1 > L3)
|
||||
|
||||
A=2
|
||||
B=3
|
||||
|
||||
print "\n-- Erzeuge Farm:"
|
||||
print("\n-- Erzeuge Farm:")
|
||||
F1 = Farm( Z, Loesung, Arg1=A, Arg2=B, Arg3=L1 )
|
||||
print F1
|
||||
print(F1)
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
+12
-12
@@ -11,7 +11,7 @@ __license__ = "Python"
|
||||
|
||||
from ga import *
|
||||
from Strukturdaten import *
|
||||
import ConfigParser
|
||||
import configparser
|
||||
import optparse
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ if __name__ == '__main__':
|
||||
parser.error( "--indir '%s' ist kein Verzeichnis" % InDir )
|
||||
|
||||
# lade Vorgaben fuer Optimierungszyklus und
|
||||
config = ConfigParser.ConfigParser()
|
||||
config = configparser.ConfigParser()
|
||||
ConfigPath= os.path.join( os.getenv('PLATZ_CFG'), 'platz.cfg')
|
||||
config.read( os.path.expandvars( ConfigPath ))
|
||||
|
||||
@@ -55,26 +55,26 @@ if __name__ == '__main__':
|
||||
|
||||
Z = Zyklus()
|
||||
Z.laden( Zyklusconfig, Zyklusart )
|
||||
print Z
|
||||
print(Z)
|
||||
SL = Strafliste()
|
||||
SL.laden( Strafenconfig )
|
||||
print SL
|
||||
print(SL)
|
||||
TE = Tische()
|
||||
TE.laden( Tischconfig )
|
||||
print TE
|
||||
print(TE)
|
||||
|
||||
InputFile = XMLConfig()
|
||||
[ PN, GN, VIPGruppe, VIPListePT ] = InputFile.laden( Bestellung )
|
||||
print PN
|
||||
print GN
|
||||
print VIPGruppe
|
||||
print VIPListePT
|
||||
print(PN)
|
||||
print(GN)
|
||||
print(VIPGruppe)
|
||||
print(VIPListePT)
|
||||
|
||||
print "\n-- Erzeuge Farm:"
|
||||
print("\n-- Erzeuge Farm:")
|
||||
F1 = Farm( Z, Sitzplatzverteilung, Tische=TE, Gruppen=GN, Strafen=SL, VIPListe=VIPListePT, VIPs=VIPGruppe )
|
||||
#print F1
|
||||
#print(F1)
|
||||
S = F1.Bester()
|
||||
print S
|
||||
print(S)
|
||||
S.speichern( AusgabeTP, AusgabePT )
|
||||
|
||||
else:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# Python-Abhaengigkeiten fuer platz
|
||||
#
|
||||
# Aktuell werden nur Module aus der Standardbibliothek verwendet
|
||||
# (ConfigParser, xml.dom.minidom, sets, UserList, random, ...).
|
||||
# (configparser, xml.dom.minidom, random, ...).
|
||||
# Keine externen Pakete erforderlich.
|
||||
#
|
||||
# Beispiel:
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
"""
|
||||
Unittests fuer Sitzplatzverteilung anhand von drei einfachen Szenarien:
|
||||
|
||||
1. Drei Tische in einer Kette (je 2 Plaetze), drei Paare
|
||||
-> jedes Paar passt exakt an einen Tisch, keine Gruppe wird getrennt.
|
||||
2. Vier Tische in einer Linie (je 2 Plaetze), zwei Vierergruppen
|
||||
-> jede Vierergruppe verteilt sich auf ein zusammenhaengendes
|
||||
Tischpaar (T1+T2 bzw. T3+T4), nie ueber die mittlere Naht hinweg.
|
||||
3. Sechs Tische im Kreis (je 2 Plaetze), vier Dreiergruppen
|
||||
-> jede Dreiergruppe wird genau einmal auf zwei Nachbartische
|
||||
aufgeteilt (2+1), da kein Tisch drei Plaetze hat.
|
||||
"""
|
||||
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'libs'))
|
||||
|
||||
from Strukturdaten import Gruppe, Gruppen, Person, Sitzplatzverteilung, Strafliste, Tisch, Tische
|
||||
|
||||
|
||||
def erzeuge_personen(anzahl, start_id=1):
|
||||
return [Person(i, 'Vorname%d' % i, 'Nachname%d' % i) for i in range(start_id, start_id + anzahl)]
|
||||
|
||||
|
||||
class TestDreiTischeKettePaare(unittest.TestCase):
|
||||
"""Drei Tische paarweise benachbart (Kette T1-T2-T3), je 2 Plaetze, 3 Paare."""
|
||||
|
||||
def setUp(self):
|
||||
random.seed(1)
|
||||
self.T1 = Tisch(1, Plaetze=2, Koordinaten=(1, 1), Nachbarliste=[2])
|
||||
self.T2 = Tisch(2, Plaetze=2, Koordinaten=(2, 1), Nachbarliste=[1, 3])
|
||||
self.T3 = Tisch(3, Plaetze=2, Koordinaten=(3, 1), Nachbarliste=[2])
|
||||
self.Tische = Tische([self.T1, self.T2, self.T3])
|
||||
|
||||
Personen = erzeuge_personen(6)
|
||||
self.G1 = Gruppe(1, Personen[0:2])
|
||||
self.G2 = Gruppe(2, Personen[2:4])
|
||||
self.G3 = Gruppe(3, Personen[4:6])
|
||||
self.Gruppen = Gruppen([self.G1, self.G2, self.G3])
|
||||
|
||||
self.Strafen = Strafliste(
|
||||
GruppenTrennen={1: {2: -10}, 2: {}, 3: {}},
|
||||
NichtNachbar=-3, Allein=-30, TischWert={1: -3, 2: -2} )
|
||||
|
||||
def test_alle_paare_komplett_an_einem_tisch(self):
|
||||
SV = Sitzplatzverteilung( Tische=self.Tische, Gruppen=self.Gruppen,
|
||||
Strafen=self.Strafen, VIPListe={}, VIPs=Gruppe(0) )
|
||||
|
||||
for G in (self.G1, self.G2, self.G3):
|
||||
self.assertEqual( SV.GruppenTeilungGet(G), 0,
|
||||
"Paar %s haette nicht getrennt werden duerfen" % G.Id )
|
||||
|
||||
# jeder der drei Tische ist von genau einem Paar voll besetzt
|
||||
Tid_zu_Gid = {}
|
||||
for Gid, Tids in SV.Gid_Tid.items():
|
||||
self.assertEqual( len(Tids), 1 )
|
||||
Tid_zu_Gid[next(iter(Tids))] = Gid
|
||||
self.assertEqual( set(Tid_zu_Gid.keys()), {1, 2, 3} )
|
||||
|
||||
# optimale Verteilung: keine Strafpunkte
|
||||
self.assertEqual( SV.value, 0 )
|
||||
|
||||
|
||||
class TestVierTischeLinieViergruppen(unittest.TestCase):
|
||||
"""Vier Tische in einer Linie (T1-T2-T3-T4), je 2 Plaetze, 2 Vierergruppen."""
|
||||
|
||||
def setUp(self):
|
||||
random.seed(1)
|
||||
self.T1 = Tisch(1, Plaetze=2, Koordinaten=(1, 1), Nachbarliste=[2])
|
||||
self.T2 = Tisch(2, Plaetze=2, Koordinaten=(2, 1), Nachbarliste=[1, 3])
|
||||
self.T3 = Tisch(3, Plaetze=2, Koordinaten=(3, 1), Nachbarliste=[2, 4])
|
||||
self.T4 = Tisch(4, Plaetze=2, Koordinaten=(4, 1), Nachbarliste=[3])
|
||||
self.Tische = Tische([self.T1, self.T2, self.T3, self.T4])
|
||||
|
||||
Personen = erzeuge_personen(8)
|
||||
self.G1 = Gruppe(1, Personen[0:4])
|
||||
self.G2 = Gruppe(2, Personen[4:8])
|
||||
self.Gruppen = Gruppen([self.G1, self.G2])
|
||||
|
||||
self.Strafen = Strafliste(
|
||||
GruppenTrennen={1: {4: -6}, 2: {}, 3: {}},
|
||||
NichtNachbar=-3, Allein=-30, TischWert={1: -3, 2: -2} )
|
||||
|
||||
def test_viergruppen_bleiben_auf_zusammenhaengendem_tischpaar(self):
|
||||
SV = Sitzplatzverteilung( Tische=self.Tische, Gruppen=self.Gruppen,
|
||||
Strafen=self.Strafen, VIPListe={}, VIPs=Gruppe(0) )
|
||||
|
||||
# jede Gruppe wird genau einmal geteilt (2 Tische a 2 Plaetze)
|
||||
self.assertEqual( SV.GruppenTeilungGet(self.G1), 1 )
|
||||
self.assertEqual( SV.GruppenTeilungGet(self.G2), 1 )
|
||||
|
||||
Tids_G1 = SV.Gid_Tid[self.G1.Id]
|
||||
Tids_G2 = SV.Gid_Tid[self.G2.Id]
|
||||
|
||||
# jede Gruppe liegt auf genau einem der beiden erwarteten Nachbarpaare,
|
||||
# nie ueber die mittlere Naht (T2-T3) hinweg vermischt
|
||||
erwartete_paare = ({1, 2}, {3, 4})
|
||||
self.assertIn( Tids_G1, erwartete_paare )
|
||||
self.assertIn( Tids_G2, erwartete_paare )
|
||||
self.assertNotEqual( Tids_G1, Tids_G2 )
|
||||
|
||||
# alle Tische sind voll besetzt, es sitzt niemand allein
|
||||
# (SV.Tische ist eine Kopie der urspruenglichen Tische, siehe
|
||||
# Sitzplatzverteilung.__init__ -> Tische.deepcopy())
|
||||
for T in SV.Tische:
|
||||
self.assertTrue( T.istvoll() )
|
||||
|
||||
|
||||
class TestSechsTischeKreisDreiergruppen(unittest.TestCase):
|
||||
"""Sechs Tische im Kreis (T1..T6), je 2 Plaetze, 4 Dreiergruppen."""
|
||||
|
||||
def setUp(self):
|
||||
random.seed(2)
|
||||
self.T1 = Tisch(1, Plaetze=2, Koordinaten=(0, 2), Nachbarliste=[2, 6])
|
||||
self.T2 = Tisch(2, Plaetze=2, Koordinaten=(1, 1), Nachbarliste=[1, 3])
|
||||
self.T3 = Tisch(3, Plaetze=2, Koordinaten=(1, -1), Nachbarliste=[2, 4])
|
||||
self.T4 = Tisch(4, Plaetze=2, Koordinaten=(0, -2), Nachbarliste=[3, 5])
|
||||
self.T5 = Tisch(5, Plaetze=2, Koordinaten=(-1, -1), Nachbarliste=[4, 6])
|
||||
self.T6 = Tisch(6, Plaetze=2, Koordinaten=(-1, 1), Nachbarliste=[5, 1])
|
||||
self.Tische = Tische([self.T1, self.T2, self.T3, self.T4, self.T5, self.T6])
|
||||
self.NachbarnVonTid = {
|
||||
1: {2, 6}, 2: {1, 3}, 3: {2, 4}, 4: {3, 5}, 5: {4, 6}, 6: {5, 1} }
|
||||
|
||||
Personen = erzeuge_personen(12)
|
||||
self.G1 = Gruppe(1, Personen[0:3])
|
||||
self.G2 = Gruppe(2, Personen[3:6])
|
||||
self.G3 = Gruppe(3, Personen[6:9])
|
||||
self.G4 = Gruppe(4, Personen[9:12])
|
||||
self.Gruppen = Gruppen([self.G1, self.G2, self.G3, self.G4])
|
||||
|
||||
self.Strafen = Strafliste(
|
||||
GruppenTrennen={1: {3: -8}, 2: {}, 3: {}},
|
||||
NichtNachbar=-3, Allein=-30, TischWert={1: -3, 2: -2} )
|
||||
|
||||
def test_dreiergruppen_je_einmal_auf_nachbartische_geteilt(self):
|
||||
SV = Sitzplatzverteilung( Tische=self.Tische, Gruppen=self.Gruppen,
|
||||
Strafen=self.Strafen, VIPListe={}, VIPs=Gruppe(0) )
|
||||
|
||||
# 4 Dreiergruppen = 12 Personen auf 6x2 = 12 Plaetzen -> alle Tische voll.
|
||||
# (SV.Tische ist eine Kopie der urspruenglichen Tische, siehe
|
||||
# Sitzplatzverteilung.__init__ -> Tische.deepcopy())
|
||||
for T in SV.Tische:
|
||||
self.assertTrue( T.istvoll() )
|
||||
|
||||
# da kein Tisch 3 Plaetze hat, muss jede Dreiergruppe genau einmal
|
||||
# auf zwei Tische aufgeteilt werden (2+1); dies gilt unabhaengig
|
||||
# vom Zufalls-Seed, da bei voller Auslastung (12 Personen auf
|
||||
# 12 Plaetzen) keine andere Aufteilung uebrig bleibt.
|
||||
for G in (self.G1, self.G2, self.G3, self.G4):
|
||||
self.assertEqual( SV.GruppenTeilungGet(G), 1 )
|
||||
Tids = SV.Gid_Tid[G.Id]
|
||||
self.assertEqual( len(Tids), 2 )
|
||||
|
||||
# mit dem hier fest gewaehlten Seed sitzen alle geteilten Gruppen
|
||||
# zusaetzlich tatsaechlich an zwei benachbarten Tischen (der
|
||||
# GA-Fallback duerfte bei knapper Auslastung im Kreis im
|
||||
# Allgemeinen auch nicht-benachbarte Tische waehlen)
|
||||
for G in (self.G1, self.G2, self.G3, self.G4):
|
||||
Tid_a, Tid_b = tuple(SV.Gid_Tid[G.Id])
|
||||
self.assertIn( Tid_b, self.NachbarnVonTid[Tid_a],
|
||||
"Tische %s der Gruppe %s sind keine Nachbarn" % (SV.Gid_Tid[G.Id], G.Id) )
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user