Auslosungsproblematik

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
rkgb
Beiträge: 4
Registriert: Mo 21. Mai 2012, 18:49

Auslosungsproblematik

Beitrag von rkgb »

Hallo,
hab seit Jahren nicht mehr programmiert (und davor auch nur ein bisschen), hab jetzt aber zu Lazarus gefunden (hab früher hauptsächlich mit Delphi gespielt..).. (Tolles Ding^^)

Auf jedenfall möchte ich für meinen Dartverein ein Auslosungsprogramm schreiben, dass: eine Gruppe von Spielern für einen Doppelspieltag mischt.
z.b. 10 spielernummern sollen sich zugelost werden, so dass jeder 2 spiele hatt (sich dabei an einem Doppelspieltag aber keines doppelt). Es werden aber auch die vergangenen Spieltage berücksichtigt, damit nicht zufällig immer die selben gegeneinander spielen. (was der Knackpunkt ist warum es überhaupt ein Programm geben soll)

Mein Ansatz ist:
Alle möglichen Kombinationen (für diesen Abend) sollen in Listen gespeichert werden, und nachher werden die Listen anhand der vergangenen Spieltage unterschiedlich bewertet, am ende entscheidet sich das Programm zufällig für eine der Bestbewertesten Listen.

Die Auswertung der Listen habe ich schon fertig programmiert aber bei der Erstellung aller möglichen Listen habe ich irgendwie ein mathematisches Problem (bzw Hänger)..

Habe das so programmiert, damit die in ein Feld eingetragenen Spielernummern/namen (ihre Anzahl variiert) in Listen Arrays nach dem Schema (siehe unten) gespeichert werden: (aber das Schema ist auf jeden Fall sehr unvollständig..)

Spieler: A,B,C,D,E
Liste 1:
A vs B
B vs C
C vs D
D vs E

Liste 2:
A vs C
B vs D
C vs E
D vs A

Liste 3:
A vs D
B vs E
C vs A
D vs B

Liste 4:
A vs E
B vs A
C vs B
D vs C

Ich bräuchte also ein Schema mit dem ich alle denkbaren Kombinationen (bei variabler Spieleranzahl) in Arrays speichern kann.

Meine (funktionierende Auswertung) basiert darauf, dass in einem String Array(X, Y) bei X = 0 einfach alle Anwesenden Spieler stehen, und Bei X = 1 bis X = 100 ihre jeweiligen Gegner (für den Abend)..
Also eine Liste für den Abend wäre bei allen werten: wo X = 0 gegen die werte wo X = 1 oder bei X = 0 gegen X = 2 usw...

Ich hoffe das war jetzt irgendwie grob verständlich und mir kann jemand einen Denkanstoss geben..

Liebe Grüße & Danke
Rolf

u-boot
Beiträge: 306
Registriert: Do 9. Apr 2009, 10:10
OS, Lazarus, FPC: Ubuntu 9.10 (L 0.9.28 FPC 2.2.4)
CPU-Target: 32Bit
Wohnort: 785..

Re: Auslosungsproblematik

Beitrag von u-boot »

Weil mich bei der Problemstellung gerade der Ehrgeiz gepackt hat, habe ich angefangen eine Lösung dazu zu programmieren ... ist aber doch etwas umfangreicher als am Start gedacht und meine Lösung wird noch ein paar tage dauern.
Ubuntu 9.10 (L 0.9.28 FPC 2.4.x)

Keifor
Beiträge: 31
Registriert: Sa 28. Aug 2010, 15:15
OS, Lazarus, FPC: pc-linux-gnu - Funtoo stable, L trunk, FPC trunk
CPU-Target: i686/x86_64

Re: Auslosungsproblematik

Beitrag von Keifor »

Vorab die Warnung: Das folgende ist nicht gerade leicht verdaulich und recht grob. Ich hoffe ich habe das Problem korrekt erkannt und kann Ansatzweise erläutern welche Probleme dies nach sich zieht. Falls fragen bestehen -> Fragen. :mrgreen:

(schnipp)

rkgb hat geschrieben:Ich bräuchte also ein Schema mit dem ich alle denkbaren Kombinationen (bei variabler Spieleranzahl) in Arrays speichern kann.


Aaaaalso. Das Problem klingt sehr interessant und ich hab mich etwas damit beschäftigt. Wenn ich die Beschreibung oben richtig verstehe, dann wird das ein ziemliches Problem werden. Mit Worten der (Theoretischen) Informatik rutscht dein Vorhaben in eine Speicher/Berechnungskomplexe Klasse von Problemen. Da sich kaum einer was darunter Vorstellen kann, hier meine Vorgehensweise und Erläuterung:

1. Formalisieren des Problems und Zerlegen in Teilprobleme.
Wenn ich es richtig verstanden habe, dann wird bei einem solchen Doppelspieltag eine Menge an Spielen abgehalten, so dass unter N Spielern jeweils jeder 2 Spiele
bestreitet. Dafür möchtest du alle möglichen Kombinationen der Gegner-Paare bestimmen.

Ich hab das Problem in 2 Teilprobleme zerlegt. Das erste ist die Gegner-Paar Erstellung, so dass jeder exakt 2 mal spielt. Der Trick ist, die Liste die du bereits aufgezählt hast, wie folgt zu Verallgemeinern (erstmal mathematisch, dann mit richtiger Erklärung)

Code: Alles auswählen

N - Anzahl Spieler (annahme: N >= 2)
Gegner Paarung: {(P[1],P[2]),(P[2],P[3]),..,(P[N-1],P[N]),(P[N],P[1])} wobei P[i] <> P[j] für i,j in {1,...,N}
-> Anzahl Spiele = N


Beispiel: Angenommen es gibt 3 Spieler A,B,C.
Dann sind alle möglichen Kombinationen der Gegner-Paarung für den Spieltag und die N Spiele:

Code: Alles auswählen

P[1]=A,P[2]=B,P[3]=C  also  Spiel1: A vs. B, Spiel2: B vs. C, Spiel3: C vs. A 
P[1]=A,P[2]=C,P[3]=B  also  Spiel1: A vs. C, Spiel2: C vs. B, Spiel3: B vs. A
P[1]=B,P[2]=A,P[3]=C  also  Spiel1: B vs. A, Spiel2: A vs. C, Spiel3: C vs. B
P[1]=B,P[2]=C,P[3]=A  also  Spiel1: B vs. C, Spiel2: C vs. A, Spiel3: A vs. B
P[1]=C,P[2]=A,P[3]=B  also  Spiel1: C vs. A, Spiel2: A vs. B, Spiel3: B vs. C
P[1]=C,P[2]=B,P[3]=A  also  Spiel1: C vs. B, Spiel2: B vs. A, Spiel3: A vs. C


Damit lässt sich das Problem (wenn es denn so korrekt formuliert wurde) abändern auf das bestimmen aller möglichen Permutationen der Liste/des Arrays P welcher alle Spieler enthält.

2. Bestimmung der Komplexität / Durchführbarkeit.
Und da kommen wir auch schon zum Hacken. Mathematisch (genauer, im Teilgebiet der Kombinatorik) ist bekannt das die Anzahl der Permutationen einer Liste von N unterschiedlichen Elementen (das P) gleich Fakultät(N) = N! = 1*2*3*...*(N-1)*N ist.

Angenommen, du speicherst für 10 Spieler jeweils alle Permutationen in je einem Feld ab. Jedes Feld benötigt ca. 10 Byte (Je Element 1 Byte um die Spielernummer zu halten). Es müssen 10! Felder berechnet werden für alle Permutationen.
Für 10 Spieler ist der Speicherverbrauch also bereits ((10 !) * 10) / (1024^2) (ca. 35MB) zum abspeichern der Informationen.
Für 11 Spieler sind es bereits um die 380MB.
Und der 2te Hacken, das aufzählen der Permutationen dauert auch eine weile.

Lösungsansätze:
Im Teilgebiet der Informatik, Algorithmen Entwurf (Algorithmen und Datenstrukturen) schlägt man sich des öfteren mit solchen Problemen rum. Um es kurz zu fassen, es gibt Grundlegend 4 Möglichkeiten das Problem anzugehen.
1. Neuformulieren des Problems und vereinfachen/zerlegen was geht. Beispiel: Auswahl des ersten Spieltags mittels Zufallsbelegung/Strohhalme ziehen, was auch immer.
Nach erstem Spieltag bestimmt eine Score Funktion (Bewertung) welche Spieler auf jedenfall gegenüberstehen müssen, bzw. Gruppen von Spielern die sich gegenüberstehen, wobei dann für jede Gruppe die Paare bestimmt werden. Das Aufzählen aller Permutationen einer solchen kleineren Gruppe ist wesentlich einfacher/schneller. usw. Zusätzliche Beschränkungen oder Vereinfachen können das Problem vereinfachen (können aber auch genau das Gegenteil bewirken).
2. Beschränkung der Eingabe -> mit weniger als 10 Spielern ist das Problem noch recht gut handhabbar, aber arg stark beschränkt.
3. Verschieben der Komplexität. Beispiel: das abspeichern aller Belegungen ist nicht notwendig, wenn die Bewertungs-Funktion lediglich eine kleine Menge Permutation (geordnet) auswählt. Das aufzählen aller Permutationen für N Spieler wird damit das Komplexe (nicht das Abspeichern).
4. Ein Gedankenblitz / ein Bahnbrechender neuer Algorithmus (passiert nicht so häufig :mrgreen: ) oder eine Kombination aus 1-3.

Nichts desto trotz (eigenartige Kombination von Wörtern)
habe ich fix einen Permutationszähler gebastelt, der die Permutationen für ein solches P Feld mit N Spielern generieren kann. Siehe Anhang.
perm.pas
Permutations Zähler
(4.98 KiB) 71-mal heruntergeladen

Kein Gewähr auf Korrektheit. Code ist allgemein Frei.

Es funktioniert recht "Simpel" indem eine Startbelegung 1,2,3,...,N erzeugt wird und dann alle Teilpermutationen generiert werden.
Die Zuweisung der Gegner Paare ist nicht enthalten. Die Maximale Zahl N ist 255, allerdings wird man bereits weniger als ~10 schon eine weile warten müssen.
Ich habe es in einen Zähler umgebaut, damit man für jede Permutation gleich eine Bewertung einbauen kann um das abspeichern zu verhindern. Allerdings lässt sich da noch viel Optimieren etc. pp.

Funktion des Permutationszählers (Achtung.. hier wird es schwierig):
Am besten ruhig nen Kaffee/Tee aufsetzen, Stift/Papier nehmen und nachprüfen.. wenn der Kopf schon raucht, am besten überspringen.
Die genaue Beschreibung/Beweis der Korrektheit würde zu lange dauern.
Kurz, es werden immer wieder Teil-Permutationen erzeugt.
Knackige mathematische Erklärung: für jede feste Belegung der ersten 0 <= i < N stellen wird die Permutation der restlichen N-i Stellen erzeugt. Der Algorithmus Terminiert wenn alle (Teil)Permutationen der "restlichen" N-0 Stellen erzeugt wurden. :shock:

Beispiel an 5 Spielern.
Man wählt initial den Vektor 1,2,3,4,5. Die erste Teilpermutation ist 2 Elementig (die letzten beiden Zahlen) und ist ein simpler Tausch -> 1,2,3,5,4
Damit haben wir die letzten 2 Stellen permutiert und gehen auf die letzten 3 Stellen über, wobei die 3te Stelle als nächst größere "Freie" Zahl gewählt wird (alles ab der gewählten Stelle ist "Frei" und wird als Elemente für die nächsten Teilpermutationen genommen).
"Frei"=4,5; "Fest"=1,2; 3 fällt raus, nach der Auswahl ist die 3 Frei. Ausgewhält wird 4 (nächst größere als 3 und Frei)
Ergo: 1,2,4 -> Initial Belegung der Teilpermutation mit aufsteigend, freien Zahlen -> 1,2,4,3,5
Dann wieder Permutation der letzten 2 Stellen: 1,2,4,5,3 -> Auswahl der Stelle 3...
...

1,5,4,2,3 nach letzter auswahl der 2ten Stelle
1,5,4,3,2 nach permutation der letzten 2 Stellen
"Frei" = 2,3,4,5; "Fest" = -; 1 ist gewählt -> nächste ist 2
2, -> inital aufsteigend... -> 2,1,3,4,5
...

Algorithmus Terminiert bei 5,4,3,2,1 und hat alle (Teil)Permutationen von 1,2,3,4,5 bis 5,4,3,2,1 durchgezählt. (Lediglich kurz geprüft mit eingaben 4/5 ob Zählung und Anzahl Elemente korrekt ist, sollte also auch für größere Eingaben korrekt sein)

(Berechnungs-) Komplexität: Es werden N! Belegungen aufgezählt. Alle 2 Schritte wird ein Rückschritt geprüft der grob mit O(N*N) einschlägt. Alle 2 Schritte wird ein Rückschritt durchgeführt der Grob O(N) benötigt. -> grob O(N!*N*N) bzw. O(N!*N^2) bzw. O(N!) für N >= 4 (richtig gewürfelt? :mrgreen:, sollte passen -> 2*3*4 > 4*4) da N! den Term N^2 dominiert.

O(N!) bedeutet so viel wie, "arbeitet bereits mit kleinen eingaben jahrelang".
Beispiel: 15 Spieler. Wir nehmen an, pro Sekunde können 1.000.000 (1 Million) Belegungen erzeugt werden (was schon sehr großzügig ist)
Macht ((((1*2*3*4*5*6*7*8*9*10*11*12*13*14*15) / 1000000) / 60sek) / 60min) / 24stunden = ca. 15 Tage.
Bei 16 Spielern: ca. 242 Tage
Bei 17 Spielern: ca. 11 Jahre
...

Zugegeben, der Algorithmus im Anhang ist nicht gerade das Optimum, aber die Komplexität bleibt bestehen auch mit verschiedensten Optimierungen, sollange die Aufzählung N! Elemente erzeugt.

*PUNKT*

PS:
Wow.. wer hat es geschafft sich bis hier durch zu kämpfen? :shock:

"Literatur":
http://de.wikipedia.org/wiki/Abz%C3%A4h ... n_Objekten - Kombinatorik / Permutation einer Menge unterscheidbarer Element
http://de.wikipedia.org/wiki/Landau-Symbole - O Notation
http://de.wikipedia.org/wiki/Permutation - Mit Vorsicht zu genießen.. wesentlich Theoretischer und aufgeblähter als eigentlich notwendig

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Auslosungsproblematik

Beitrag von Socke »

Keifor hat geschrieben:Wow.. wer hat es geschafft sich bis hier durch zu kämpfen? :shock:

Hier, ich. Das ist dann wohl auch der Grund, warum ich die Kombinatorik im Studium so geliebt habe ...

Keifor hat geschrieben:Nichts desto trotz (eigenartige Kombination von Wörtern)
Nichtsdestotrotz ist dies immer noch ein Wort ;-)
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6209
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Auslosungsproblematik

Beitrag von af0815 »

+1 für den Super erklärenden Beitrag. Auch ich habe es durch geschafft :-)

Ist es nicht einfacher eine feste Reihe von Spielen/Spielen/... zu nehmen und diese einfach nur zu mischen. Damit ist die Mächtigkeit auf ein Minimum reduziert.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Keifor
Beiträge: 31
Registriert: Sa 28. Aug 2010, 15:15
OS, Lazarus, FPC: pc-linux-gnu - Funtoo stable, L trunk, FPC trunk
CPU-Target: i686/x86_64

Re: Auslosungsproblematik

Beitrag von Keifor »

af0815 hat geschrieben:+1 für den Super erklärenden Beitrag. Auch ich habe es durch geschafft :-)

Danke. Auch fürs Durchkämpfen. :oops:
Ich hoffe nur, ich habe den Themenstarter nicht verschreckt.

Socke hat geschrieben:
Keifor hat geschrieben:Wow.. wer hat es geschafft sich bis hier durch zu kämpfen? :shock:

Hier, ich. Das ist dann wohl auch der Grund, warum ich die Kombinatorik im Studium so geliebt habe ...

Keifor hat geschrieben:Nichts desto trotz (eigenartige Kombination von Wörtern)
Nichtsdestotrotz ist dies immer noch ein Wort ;-)


Hmm.. In der Tat. Du darfst den Rechtschreibfehler behalten. :wink:
Ja, Kombinatorik ist eine lustige Sache. Und je nachdem wie man ein "Sprachlich formuliertes" Problem interpretiert kommen andere Zahlen raus. :lol:

Nebenbei, ich habe mittlerweile eine 2te Lösung geschrieben die genau da ansetzt. Das Problem ist, ich war mir nicht sicher ob die Spielabfolge relevant ist, daher gibts nun noch einen (unwesentlich komplexeren - was auch immer das bedeuten mag) Algorithmus der Doppelmatches für N Spieler bestimmt ohne die Reihenfolge zu beachten.

Ich fasse es diesmal kürzer. (Obwohl man noch viel mehr darüber schreiben könnte)
Ähnlich der festen Matchkombination (Match = 2 unterschiedliche Spieler treten gegeneinander an) benutzt der Algorithmus eine Spezifische Kombination jeweils für N Spieler, die allerdings nicht mehr eindeutig ist.
Beispiel:

Code: Alles auswählen

..
  3 Spieler: 1 vs. 2 - 1 vs. 3 - 2 vs. 3
  4 Spieler: 1 vs. 2 - 1 vs. 3 - 1 vs. 4 - 2 vs. 3 - 2 vs. 4 - 3 vs. 4
..

Wie man sieht, kann man das locker weiterführen. Exakt gibt es davon (N^2 - (N*(N+1))/2) Matches für N Spieler. Das neue Problem ist, eine Teilmenge davon zu wählen so dass jeweils jeder Spieler (exakt) 2 mal spielt. Der neue Algorithmus wählt jeweils aufsteigend einen Spieler und prüft ob die Matches für den Spieler möglich sind (bspw. für 1 -> 1 vs. 2, 1 vs. 3 ...). Dann wird rekursiv für ein solches Spiel, die Kombination für den nächsten Spieler bestimmt usw.

Der Algorithmus ist stark verwandt mit Branch-and-Bound Algorithmen wie sie bei anderen Optimierungsproblemen eingesetzt werden. Nur so als Lese/Stöber/Literatur Hinweis. (Optimierungsprobleme haben nebenbei auch nichts mit Optimierung von Algorithmen zu tun.)

Komplexität usw.
Ich habs diesmal nicht mehr so stark getestet und berechnet, da es wesentlich aufwendiger ist, vor allem mit den Optimierungen.
Auffällig ist, das für N Spieler jeweils 2^(N-3) mögliche Kombinationen erzeugt werden und da kommt der Speicherverbrauch und die Laufzeit ins Spiel. Die Anzahl der Kombinationen steigt Exponentiell zur Eingabe (Spielerzahl) an und damit auch der Speicherverbrauch und die Laufzeit.

Mit 30+ Spielern ist also quasi nicht mehr möglich. Aber < 25 konnte ich auf meinem Rechner locker in unter 1min. (für < 20 in unter 1sek.) Berechnen.

So, zum Testen und Spielen (alles Gemeinfrei + ohne Gewähr):
vs2solve.pas
Unit mit Berechnung der Spielkombinationen
(10.37 KiB) 69-mal heruntergeladen


Haupt Programm:

Code: Alles auswählen

program pgame;
 
{$MODE OBJFPC}{$H+}
 
uses Classes, Sysutils, vs2solve;
 
var
  players,i,m: Integer;
  game: TGame2VSConstraints;
  g: TGameSingleCoded;
 
begin
  if ParamCount <> 1 then
    Halt;
  players := StrToIntDef(ParamStr(1),2);
  if players < 2 then
    players := 2;
  WriteLn('Calculating Games for ',players,' player');
  game := TGame2VSConstraints.Create(players);
  game.SolveGames;
 
  for i := 0 to game.GameCount-1 do
    begin
      g := game.Game[i];
      WriteLn('  Game Combination ',i);
      for m := 0 to g.MatchCount-1 do
        begin
          if g.Match[m] then
            WriteLn('    ',m,' - Player ',g.MatchPlayer1[m],' vs. Player ',g.MatchPlayer2[m]);
        end;
    end;
  WriteLn('Nr Games: ', game.GameCount);
end.


So.. das sollte dann weitestgehend alles sein und ich verliere mein Interesse an dem Thema..

rkgb
Beiträge: 4
Registriert: Mo 21. Mai 2012, 18:49

Re: Auslosungsproblematik

Beitrag von rkgb »

Jesus christus...
Erst einmal Dankeschön für die erstklassigen Beiträge..

Ich habe gerade relativ viel um die Ohren und werde erst am Wochenende dazukommen mich weiter gehend damut zu beschäftigen..

Tatsächlich haben wir beim darten 2 bis 3 nach spielstärke (anhand der Rangliste) sortierte gruppen, was unser N normal um die 10 hält..

Also schon mal vielen dank und ich freu mich schon darauf alles durchzu arbeiten..


Lg rolf

Keifor
Beiträge: 31
Registriert: Sa 28. Aug 2010, 15:15
OS, Lazarus, FPC: pc-linux-gnu - Funtoo stable, L trunk, FPC trunk
CPU-Target: i686/x86_64

Re: Auslosungsproblematik

Beitrag von Keifor »

rkgb hat geschrieben:Jesus christus...
Erst einmal Dankeschön für die erstklassigen Beiträge..

Ich habe gerade relativ viel um die Ohren und werde erst am Wochenende dazukommen mich weiter gehend damut zu beschäftigen..

Tatsächlich haben wir beim darten 2 bis 3 nach spielstärke (anhand der Rangliste) sortierte gruppen, was unser N normal um die 10 hält..


Hehe, Danke. :oops:
Ich bin weniger ein Forum-Poster. Das ganze hat mich stark an meine letzten Jahre im Studium erinnert, wo man in 3-5 Fächern irgend ein (P/NP) Problem vorgesetzt bekommt und einer sagt: "In 1-2 Wochen will ich die Lösung + funktionierendem Code + x-seitige Erläuterung". :roll:
Lass dir Zeit und stell Fragen. Bin über das Wochenende eh auf Tour und weiß nicht ob ich da Internet habe.

2 kleine Anmerkungen noch.
1. Für "um die 10 Spieler" bietet sich die 2te Variante an, bei der ersten wird es schon knifflig mit mehr als 10.
2. Die Testprogramme sind eher pur in Lazarus geschrieben. Für das erste (perm.pas), am besten ein neues Projekt anlegen (Neu->Projekt->Programm) und es dann reinkopieren. Für das 2te Hauptprogramm ebenfalls, abspeichern und vs2solve.pas in das entsprechende Verzeichnis ablegen oder neue Unit anlegen und vs2solve reinkopieren.
Beides sind Konsolen Programme, also muss das ganze gegebenenfalls von Konsole gestartet werden um die Ausgabe zu sehen. Das 2te Programm will auch noch eine Zahl als Parameter.

Viel Spaß beim rumprobieren und studieren. :mrgreen:

rkgb
Beiträge: 4
Registriert: Mo 21. Mai 2012, 18:49

Re: Auslosungsproblematik

Beitrag von rkgb »

puuuuuuuuuuh... :shock:

Hi, also mit dem Permutationscode, lass ich mir grade 1 milliarde -1 (10 Teilnehmer?!?) Möglichkeiten ausspucken.. (dauert etwas..)..
Und der Code#2 ist mir etwas zu unvollständig von den Möglichkeiten.. Wirft z.B. bei 4 Teilnehmern nur 2 möglichkeiten aus, da er immer Spieler 1 vs Spieler 2 setzt.. Was mir vom Teilbereich keine große Hilfe ist, denke ich.

So nebenbei fehlen mir die mathematischen Voraussetzungen leider.. :cry:

Ich denke ich entscheide mich für variante 4 den kleinen Geistesblitz :lol:

In form einer praktikablen Brute Force Lösung..
Ich lose eine variante (über das Permutationsschema mit einem Random wert) aus und wenn sie in meinem Bewertungsschema perfekt abschneidet nehme ich sie..
Falls nicht, lost er eine weitere aus, bewertet sie, schneidet sie besser ab, wird sie gemerkt..
Und auf die art lasse ich Losen, bis eine Lösung perfekt abschneidet oder die aktuell beste, die in einer art Vorschau angezeigt wird, akzeptiert wird.

Ich denke das sollte ein schöner Mittelweg aus Rechenzeit und Praktikabilität werden.

Vielen Dank für die freundlichen Beiträge und euer Engagement.

Liebe Grüße,
Rolf

rkgb
Beiträge: 4
Registriert: Mo 21. Mai 2012, 18:49

Re: Auslosungsproblematik

Beitrag von rkgb »

Hi
hier wäre mal mein Code..

Auf dem Rechner schaff ich jetzt damit 300.000 Auslosungen und Bewertungen pro Sekunde (Bei 10 Teilnehmern und 8 Spieltagen).. Was an und für sich ja wahrscheinlich ausreicht.. Aber bei einem BruteForce Ansatz kann man ja nie schnell genug sein..
Vielleicht hat jemand noch einen Tipp wie man meinen "grässlichen" Code etwas Optimieren kann..

Danke schön..

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var helfer, zufallszahl : Integer;
    randomchecker : Array[0..30] of Integer;
    abbruch, abbruchMassetest, abbruchrunner, abbruchcounter : Integer;
    testlauf : Integer;
    runner, testrunner, testrunner2 : Integer;
 
 
    runde2reseter : Integer;
 
begin
 
  //* Spieler aus MemoPlayers zählen: (Anwesende Spieler)
      for PlayersCounter := -1 to 999 do
      begin
      Losung[0, PlayersCounter] := MemoPlayers.Lines[PlayersCounter]; // Referenzgruppe Losung[0,x] schreiben
      If MemoPlayers.Lines[PlayersCounter] = 'x' then Break;
      If MemoPlayers.Lines[PlayersCounter] = 'X' then Break;
      end;
      Label1.caption := 'Spieleranzahl: ' + InttoStr(PlayersCounter);
 
      abbruchcounter := 0;
 
      //* Spieler aus MemoAltePartien1L zählen und in Array AltePartien1L und 1R lade:
      for AltePartien1Counter := 0 to 999 do
      begin
 
      Altepartien1L[AltePartien1Counter-1] := MemoAltePartien1L.Lines[AltePartien1Counter-1];
      Altepartien1R[AltePartien1Counter-1] := MemoAltePartien1R.Lines[AltePartien1Counter-1];
         If MemoAltePartien1L.Lines[AltePartien1Counter-1] = 'x' then Break;
      If MemoAltePartien1L.Lines[AltePartien1Counter-1] = 'X' then Break;
      end;
 
 
      for Testlauf := 0 to 10000000 do
       begin
       abbruchmassetest := 0;
      score := 0;
 
  //# Spieler aus MemoPlayers sind gezählt und in PlayersCounter abgelegt
  //# Ausserdem ist Losung[0,x] mit den Spielernummern gefüllt..
 
  //* Lose Gegner für die Runden willkürlich aus aber ohne direkte Wiederholungen
      For helfer := 0 to PlayersCounter   do randomchecker[helfer] := 0; //reset vom randomchecker
    //  For helfer := 0 to PlayersCounter  do gruppenchecker[helfer] := 0; //reset vom randomchecker
 
      helfer := 0; //helfer reset
      While helfer < PlayersCounter do
       begin
 
       //auslosung
       zufallszahl := random(Playerscounter {div 2});
      // gruppencheck := 1;
      // gruppenversuch := 0;
 
 
     // while gruppencheck = 1 do
     //    begin
 
       //wiederholung der auslosung falls eine zahl ausgelost wurde, die schonmal drann war..
       While randomchecker[zufallszahl] = 1 do zufallszahl := Random(PlayersCounter {div 2});
 
 
       //setzung der Losung auf Probe
       Losung[1,helfer] := Losung[0, zufallszahl];
 
        // Losverfahren ist gescheitert beim letzten wert: also reset
        // If bedeutet wenn letzte zahl ausgelost wird.. (abfrage weil nicht geht: 10 vs 10)
     If (helfer = Playerscounter -1) and (Losung[0, helfer] = Losung[1, helfer])  then  abbruch := 1;
     {begin
       { For abbruchrunner := 0 to Playerscounter  do if randomchecker[abbruchrunner-1] = 0 then  abbruch := abbruchrunner+100;}

{ Ist überflüssig da jetzt ja schon oben die letzte freie zahl gesetzt wurde.. //   zufallszahl  := abbruch -101; //letzte freie zufallszahl wird automatisch gesetzt
        Losung[1,helfer] := Losung[0, zufallszahl];
        //abbruch kriterium: letzte runde siehe oben.. und 2 gleiche gelost }

        If (Losung[0, helfer] = Losung[1, helfer]) { and (abbruch = ((helfer+1)+100)) or (abbruch = (((helfer+1)/2)+100))} then  abbruch := 1;
     end;         }
 
       // Losverfahren ist beim vorletzen wert gescheitert test durch 50/50 Auslosungswiederholungen
     if (helfer = Playerscounter -2) then abbruchMassetest := abbruchMassetest +1;
      If abbruchmassetest = 15 then abbruch := 1;
 
       // wenn if erfüllt wird war zufallszahl oder Spieler A vs A ... bei else wird die zufallszahl genommen und gesperrt..
       If {(randomchecker[zufallszahl] = 1) or }(Losung[0,helfer] = Losung[1, helfer]) then helfer := helfer -1
         else
         begin
       //  For runner := -1 to helfer do
       //    begin
       //      If (Losung[0, helfer] = Losung[1, runner]) or (Losung[1, helfer] = Losung[0, runner]) then gruppenchecker[helfer] := gruppenchecker[helfer] +1;
      //       If gruppenchecker[helfer] < 2 then randomchecker[zufallszahl] := 1 else helfer := helfer -1;
 
           randomchecker[zufallszahl] := 1;          //heisst zahl wurde jetzt 1x gewürfelt
 
       //    end
         end;
    helfer := helfer +1;
   // if helfer = PlayersCounter div 2 then for Runde2reseter := helfer downto 0 do randomchecker[Runde2reseter] := 0;
 
      {//Schönerauslosungsfehler debugger
          For testrunner2 := 0 to PlayersCounter Do
          begin
          Memo1.Lines[testrunner2] := IntToStr(randomchecker[testrunner2]);
          Memo2.Lines[testrunner2] := Losung[1, testrunner2];
          Memo3.Lines[0] := 'Hoechste freie Zufalslzahl ist: ' + Inttostr(Abbruch-100);
          Memo3.Lines[1] := 'Helferwert ist: ' +Inttostr(helfer);
                  Memo3.Lines[2] := 'Testlauf nummero: ' + Inttostr(Testlauf);
                      memo3.lines[3] := 'Abbruchcounter: ' + Inttostr(abbruchcounter);
         // sleep(10);
          end;
     }

 
       If abbruch = 1 then   //Auslosung ist gescheitert, reset der auslose variablen
       begin
         For helfer := 0 to PlayersCounter  do randomchecker[helfer] := 0; //reset vom randomchecker
      //   For helfer := 0 to PlayersCounter do gruppenchecker[helfer] := 0; // reset gruppenchecker
         abbruchcounter := abbruchcounter +1;
     //       Sleep(10000); // fürs Debuggen
         helfer := 0;
         abbruch := 0;
         abbruchmassetest := 0;
        end;
 
       end;
  //# Frei ausgelost mit wiederholungsstop und dopplungstop
 
  //test von mehrern spieltagen bewertungen
 
  for mehrspieltagefuntest := 0 to 7 do
    begin
 
  //* check ob die alte partie schonmal vorkam
 
     // Label3.caption := 'Alte Spiele: ' + InttoStr(AltePartien1Counter);
      //# Spieler aus MemoPlayers sind gezählt und in AltePartien1Counter abgelegt
  helfer := 0;
  for helfer := 0 to AltePartien1Counter do
   begin
    If (Losung[0, helfer] = AltePartien1l[helfer]) and (Losung[1,helfer] = AltePartien1r[helfer]) then Score := Score +1;
    If (Losung[0, helfer] = AltePartien1r[helfer]) and (Losung[1,helfer] = AltePartien1l[helfer]) then Score := Score +1;
   end;
  //# Alte Partie1 check abgeschlossen, ergebnis wird in Score abgelegt.
  //Label2.Caption := 'Score ist: ' + IntToStr(Score);
  end;
 
  end;
 
 
       For testrunner2 := 0 to PlayersCounter Do
          begin
          Memo1.Lines[testrunner2] := IntToStr(randomchecker[testrunner2]);
          Memo2.Lines[testrunner2] := Losung[1, testrunner2];
          Memo3.Lines[0] := 'Hoechste freie Zufalslzahl ist: ' + Inttostr(Abbruch-100);
          Memo3.Lines[1] := 'Helferwert ist: ' +Inttostr(helfer);
          Memo3.Lines[2] := 'Testlauf nummero: ' + Inttostr(Testlauf);
          memo3.lines[3] := 'Abbruchcounter: ' + Inttostr(abbruchcounter);
  end;
 
end;
Zuletzt geändert von Lori am Fr 1. Jun 2012, 19:22, insgesamt 1-mal geändert.
Grund: richtiger Highlighter

Antworten