Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Sporadische Abstürze bei Kartenspielprojekt


Vamos - So 07.02.10 12:18
Titel: Sporadische Abstürze bei Kartenspielprojekt
Hallo Ihr Lieben,

ich wollte mal ein Kartenspiel komplett allein und ohne cards.dll programmieren, um einfach ein bisschen in Delphi rumzuspielen. Bin auch bisher ziemlich zufrieden, läuft soweit alles, nur beim ermitteln und mischen der Karten stürzt mein Programm manchmal ab. Keine Fehlermeldung, nur keine Reaktion mehr.

Ich denke, dass der fehler hier sein muss:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
//Karten mischen

for i := 1 to 32 do
  begin
  randomize;
  repeat
  Zahl[i] := Random(48)+11;

    //2 gleiche Karten vermeiden + verbotene Zahlen vermeiden

  doppelt:=false;
  for j :=1 to i-1 do
  begin
  if Zahl[i] = Zahl[j] then doppelt := true
  else if zahl[i] > 48 then doppelt := true
  else if zahl[i] =19 then doppelt := true
  else if zahl[i] =20 then doppelt := true
  else if zahl[i] =29 then doppelt := true
  else if zahl[i] =30 then doppelt := true
  else if zahl[i] =39 then doppelt := true
  else if zahl[i] =40 then doppelt := true
  else if zahl[j] > 48 then doppelt := true
  else if zahl[j] =19 then doppelt := true
  else if zahl[j] =20 then doppelt := true
  else if zahl[j] =29 then doppelt := true
  else if zahl[j] =30 then doppelt := true
  else if zahl[j] =39 then doppelt := true
  else if zahl[j] =40 then doppelt := true;



    //Wenn zwei Karten doppelt sind, wird die boolsche Variable auf true gesetzt.
  end;
  Until not doppelt;
  LBkarten.Items.Add(IntToStr(zahl[i]));
  // Solange wird gesucht, bis keine doppelten mehr vorkommen, also doppelt:=false!
  end;



Ich markiere hier doppelte Karten als ungültig und habe zuätlicha alle nicht möglichen Kartenzahlen als "doppelt" markiert. Wenn mein Programm läuft stimmt auch alles, aber es stürzt eben immer mal wieder ab...

Wo ist mein Fehler?

Danke!


Corpsman - So 07.02.10 12:43

Also was mir ja spontan auffällt, ist das du hier mehrfach auf Zahl[i] in der j schleife zugreifst, d.h. du machst sehr viel doppelt, n-Fach, was total unnütz ist.

Dein Code Schnipsel ist allerdings viel zu wenig, um einen Fehler zu finden. Evtl. postest du ein bischen mehr, wenigstens die Initialisierung des Zahl Arrays. es sieht zwar nach einem Statischen 1..32 array aus, aber wer weis das schon wenn man es nicht sieht ...


Kha - So 07.02.10 12:45

Deine Schleife ist etwas merkwürdig - wozu Zahlen > 48 würfeln lassen, wenn man sie sowieso wegwirft? Der letzte Block mit zahl[j] ... ist auch unsinnig; wenn eine verbotene Karte unter den bereits gewählten liegt, ist es schon zu spät.
Auf jeden Fall gibt es aber einen Mischalgorithmus, der im Gegensatz zu deinem nach einer genauen Anzahl von Schritten terminiert: Fisher-Yates [http://delphi-library.de/viewtopic.php?t=7171].


Vamos - So 07.02.10 13:21

user profile iconCorpsman hat folgendes geschrieben Zum zitierten Posting springen:
Also was mir ja spontan auffällt, ist das du hier mehrfach auf Zahl[i] in der j schleife zugreifst, d.h. du machst sehr viel doppelt, n-Fach, was total unnütz ist.

Dein Code Schnipsel ist allerdings viel zu wenig, um einen Fehler zu finden. Evtl. postest du ein bischen mehr, wenigstens die Initialisierung des Zahl Arrays. es sieht zwar nach einem Statischen 1..32 array aus, aber wer weis das schon wenn man es nicht sieht ...


Danke für die Antwort, also meine initalisierung:


Delphi-Quelltext
1:
 Zahl : Array[1..48of Integer;                    


Das liegt daran, dass ich ein 32-Blatt Spiel versucht habe mit zahlen zu codieren:

Also:


HSieben := 11;
HAcht := 12;
HNeun := 13;
HZehn := 14;
HBube := 15;
HDame := 16;
HKoenig := 17;
HAss := 18;

KSieben := 21;
KAcht := 22;
KNeun := 23;
KZehn := 24;
KBube := 25;
KDame := 26;
KKoenig := 27;
KAss := 28;

...

Das habe ich mir so bereit gelegt, damit ich später beim spielen der Karten eben auch sagen kann welche Karte auf welche folgen soll.


Vamos - So 07.02.10 13:25

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Deine Schleife ist etwas merkwürdig - wozu Zahlen > 48 würfeln lassen, wenn man sie sowieso wegwirft? Der letzte Block mit zahl[j] ... ist auch unsinnig; wenn eine verbotene Karte unter den bereits gewählten liegt, ist es schon zu spät.
Auf jeden Fall gibt es aber einen Mischalgorithmus, der im Gegensatz zu deinem nach einer genauen Anzahl von Schritten terminiert: [url=http://delphi-library.de/viewtopic.php?t=7171]Fisher-Yates[/url].


Naja, zahlen über 48 gibt es bei meiner Radom eingabe zwangsläufig (48)+11

Das habe ich so gestaltet, damit eben keine Zahl < 11 rauskommt.

Zu deinem Hinweis mit dem Algorithmus, danke! Ich werde mir den gleich ansehen, nachdem meiner Funktioniert : )

Vielleicht ein bisschen eigen, aber ich möchte eben einmal alles selbst machen, denke dass mich das weiter bringt, hab da nur irgendwo nen Denkfehler auf den ich net komme...

Im Übrigen: Wenn ich den J-Block weglasse, dann stüzt mein Programm jedes mal ohne Fehlermeldung ab : (


jaenicke - So 07.02.10 15:00

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Naja, zahlen über 48 gibt es bei meiner Radom eingabe zwangsläufig (48 )+11
Schon, aber warum machst du es denn so?

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Das habe ich so gestaltet, damit eben keine Zahl < 11 rauskommt.
Ja, und wenn du Zahlen zwischen 11 und 48 willst, dann musst du von der Obergrenze eben die addierte 11 wieder abziehen...
Bei Random(38) + 11 kommen Zahlen von 11 <= Zahl <= 48 heraus.


Corpsman - So 07.02.10 15:00

Also ehrlich gesagt ist mir das sehr suspekt was du hier machst.

Ich würde es so machen :

1. Init das Array mit allen Karten die du hast. Sauber, und sortiert.
2. While so lange wie du willst
i := random ( high(array) - low(array)) + low(array);
j := random ( high(array) - low(array)) + low(array);
3. Vertausche Array[i] mit array[j]
so wie man eben normalerweise mischt.

Ich denke mit dem Ansatz hast du keine merkwürdigen Fehler mehr.


Kha - So 07.02.10 15:09

Was bei Endlosschleifen immer hilft: Wenn das Programm hängen geblieben ist, halte es mit dem Debugger an und schau dir an, wo du rausgekommen bist und was die Variablen zu sagen haben.

user profile iconCorpsman hat folgendes geschrieben Zum zitierten Posting springen:
2. While so lange wie du willst
n gegen unendlich, oder wie ;) ? Da ist er mit seinem bisherigen Ansatz wirklich besser dran; wenn dieser terminiert, dann wenigstens mit einer statistisch einwandfreien Verteilung.

user profile iconCorpsman hat folgendes geschrieben Zum zitierten Posting springen:
so wie man eben normalerweise mischt.
Nein, tut man nicht ;) .


Corpsman - So 07.02.10 15:33

wenn er in seiner while schleife 100 nimmt, z.b. dann terminiert es auf jeden fall.

und 100 Vertauschungen, gibt auch schon ein ganz gutes gemischtes Ergebnis.

So wie er es gerade hat mischt er ja nur die ersten 32 Karten und die anderen 16 nicht.

bei meiner Variante würde er alle mischen. und wäre sich sicher das er durch seine recht merkwürdige Logik die er da bisher drin hat, keine Fehler mehr macht.


Kha - So 07.02.10 17:19

user profile iconCorpsman hat folgendes geschrieben Zum zitierten Posting springen:
wenn er in seiner while schleife 100 nimmt, z.b. dann terminiert es auf jeden fall.
Hab ich auch nicht bestritten?
Aber warum 100, warum nicht 1000 oder 10? Dein Algorithmus kann keine Garantie für die Verteilung geben und stützt sich daher lieber auf dem "viel hilft viel"-Prinzip.

Um es klar auszudrücken: user profile iconVamos' Code entspricht dem einzigen richtigen Ansatz zum Mischen einer Liste! "Nimm nacheinander ein beliebiges Element aus der verbleibenden Menge, bis diese leer ist" - etwas Anderes macht Fisher-Yates auch nicht, nur ein wenig schlauer.

user profile iconCorpsman hat folgendes geschrieben Zum zitierten Posting springen:
So wie er es gerade hat mischt er ja nur die ersten 32 Karten und die anderen 16 nicht.
Das ist überhaupt die große Frage in diesem Thread: Wozu ein Array mit Länge 48 für 32 Karten? Solange das nicht geklärt ist, kann kein Algorithmus funktionieren.

@user profile iconVamos: Wie wäre es denn mit so etwas?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
type
  TFarbe = fHerz, fKaro, ...
  TWert = wSieben = 7, wAcht, ...
  TKarte = record
    Farbe : TFarbe;
    Wert : TWert;
  end;

...

var Karten : array[0..4 * 8 - 1of TKarte;

for i := 0 to 3 do
  for j := 7 to 14 do
  begin
    Karte.Farbe := TFarbe(i);
    Karte.Wert := TWert(j);
    Karten[i * 8 + j] := Karte;
  end;


Vamos - So 07.02.10 20:24

Danke für eure Kommentare.

Ich mische 48 Karten, weil ich folgendermaßen "codiere"; :

Zahl 11 = Farbe 1, Karte 1
Zahl 21 = Farbe 2, Karte 2
Zahl 31 = Farbe 3, Karte 1
Zahl 48 = Farbe 4, Karte 8

Pro Farbe gibt es bei meinem Spiel 8 Karten: 7, 8, 9, 10, Bube, Dame, König, Ass.

Das mit den Objekten ist pfiffig, bin ich leider aber nicht drauf gekommen und bin zu weit um das zu ändern. Bei meinem Spiel nehme ich also nachher die Zahlen wieder auseinander:

43 = Farbe 4, Karte 3 (9).

Es handelt sich hierbei um mein 1. größeres Projekt, bei dem ich wirklich alles (es sei denn ich komme gar nicht weiter) selber machen möchte. Sonst lernt man's ja net. Ihr seid auch echt super und beantwortet fast alle Fragen. Nur ich möchte nicht mehr fragen müssen : )

99% findet man auch, wenn man ordentlich sucht.

Also meinen Mischalogrithmus möchte ich gerne genau so zum Funktionieren bekommen, ohne ihn komplett anders zu machen. Er funktioniert auch relativ zuverlässig, nur eben manchmal nicht...

Moderiert von user profile iconKha: Zitate entfernt

--- Moderiert von user profile iconKha: Beiträge zusammengefügt ---



user profile iconCorpsman hat folgendes geschrieben Zum zitierten Posting springen:
wenn er in seiner while schleife 100 nimmt, z.b. dann terminiert es auf jeden fall.

und 100 Vertauschungen, gibt auch schon ein ganz gutes gemischtes Ergebnis.

So wie er es gerade hat mischt er ja nur die ersten 32 Karten und die anderen 16 nicht.

bei meiner Variante würde er alle mischen. und wäre sich sicher das er durch seine recht merkwürdige Logik die er da bisher drin hat, keine Fehler mehr macht.


Ah, jetzt verstehe ich... Doch, mach ich, weil zwar 48 zahlen, aber darunter nicht existente Karten.

Also ich mische alle 32 Karten + 16 die ich nicht mischen müsste, weil ich Sie nicht brauche darunter: 0-10, 19, 20, 29, 30, 39 & 40.
Gruße, Vamos


Kha - So 07.02.10 22:58

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Ich mische 48 Karten, weil ich folgendermaßen "codiere"; :
Ja, das haben wir verstanden. Aber auch wenn deine Kartenwerte von 1 bis 48 gehen, warum sollte das Array genauso groß sein? Das macht einfach keinen Sinn, schon beim Mischen lässt du schließlich i nur von 1 bis 32 laufen. Den hinteren Teil des Arrays lässt du unbenutzt, dann kannst du ihn auch gleich weglassen.

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Das mit den Objekten ist pfiffig
Ich seh zwar keine Objekte, aber ok ;) .

PS: Schon ausprobiert?
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Was bei Endlosschleifen immer hilft: Wenn das Programm hängen geblieben ist, halte es mit dem Debugger an und schau dir an, wo du rausgekommen bist und was die Variablen zu sagen haben.


Vamos - Mo 08.02.10 00:13

[quote="user profile iconKha"(594772)]
user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Ich mische 48 Karten, weil ich folgendermaßen "codiere"; :
Ja, das haben wir verstanden. Aber auch wenn deine Kartenwerte von 1 bis 48 gehen, warum sollte das Array genauso groß sein? Das macht einfach keinen Sinn, schon beim Mischen lässt du schließlich i nur von 1 bis 32 laufen. Den hinteren Teil des Arrays lässt du unbenutzt, dann kannst du ihn auch gleich weglassen.
Zitat:




Noe, ich benutze zwar nicht das gesamte array, aber habe auch keine Möglichkeit gefunden es einzuschränken.. bei [11..48] gabs auch nen Fehler.
Meine erste Karte = 11, die letzte 48.

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Das mit den Objekten ist pfiffig
Ich seh zwar keine Objekte, aber ok ;) .

Ups, soviel zu meinem aktuellen Kenntnisstand.

PS: Schon ausprobiert?
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Was bei Endlosschleifen immer hilft: Wenn das Programm hängen geblieben ist, halte es mit dem Debugger an und schau dir an, wo du rausgekommen bist und was die Variablen zu sagen haben.


Hab ich, Fehler:
76AF4E31 85C0 test eax, eax
EAX 00000001
CF 0

Sagt mir jetzt mal gar nix, assembler kann ich leider nicht.


Gravitar - Mo 08.02.10 13:57

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Ihr Lieben,

ich wollte mal ein Kartenspiel komplett allein und ohne cards.dll programmieren, um einfach ein bisschen in Delphi rumzuspielen. Bin auch bisher ziemlich zufrieden, läuft soweit alles, nur beim ermitteln und mischen der Karten stürzt mein Programm manchmal ab....


Hi Vamos,

ich programmiere derzeit einen Poker-Wahrscheinlichkeitsrechner. Dort muss man ebenfalls Karten mischen und austeilen.

Derzeit verzichte ich auf das Mischen komplett!!!

Ich ziehe einfach über Random einzelne Karten aus dem Kartenstapel und verteile diese. Wozu noch mischen, wenn ich sowieso über Random ziehe?

Bei ca. 500.000 Hände, die ich simulieren muss, ist der Verzicht auf das Mischen ein enormer Zeitgewinn.

Als Datenkonstrukt nutze ich eine TList of Records (Kartenwert, Kartenfarbe), da ich nach dem Ziehen diese Karte einfach aus der TList löschen kann und damit sichergestellt ist, dass eine Karte nicht mehrfach gezogen wird.

Vielleicht hilft es ja.

Gruß, Andreas


danielf - Mo 08.02.10 14:04

Hi,

ich habe nur eine Frage: Warum simulierst du 500.00 Hände?

Die Wahrscheinlichkeit lässt sich doch berechnen, dafür brauchst du keine Simulation und das ganze ist noch viel schneller. Mit dem Mischen hast du natürlich recht.

Gruß Daniel


Gravitar - Mo 08.02.10 14:10

user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Hi,

ich habe nur eine Frage: Warum simulierst du 500.00 Hände?

Die Wahrscheinlichkeit lässt sich doch berechnen, dafür brauchst du keine Simulation und das ganze ist noch viel schneller. Mit dem Mischen hast du natürlich recht.

Gruß Daniel


Hi Daniel,

na dann erkläre mir doch mal, wie man bei 9 Teilnehmern und einer gegebenen Starthand die Gewinnwahrscheinlichkeit berechnet ohne den kompletten Spielverlauf zu simulieren?

Gruß Andreas


danielf - Mo 08.02.10 14:30

Nun ja, die Wahrscheinlichkeiten einer bestimmten Hand sind ja bekannt (http://de.wikipedia.org/wiki/Poker). Wenn du nun zum Beispiel: 2 Buben auf der Hand hast, .. du hast recht :D ist wohl komplizierter als eine Simulation.

Dachte irgendwie wenn ich ein Blatt habe und nach dem Flop ich noch Karten x, y brauche.. weiß ich ja wieviel Karte noch im Stampel sind und dementsprechend meine Chancen so eine Karte zu ziehen. Aber wenn man Karten die es nicht mehr gibt Berücksichtigt etc. wird wohl unmöglich.

Gruß Daniel


Gravitar - Mo 08.02.10 14:39

user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Nun ja, die Wahrscheinlichkeiten einer bestimmten Hand sind ja bekannt (http://de.wikipedia.org/wiki/Poker)....


Hi Daniel,

interessant ist, dass in den Referenzen zum Wiki-Artikel unter dem Stichwort "Wahrscheinlichkeiten" folgender Link auftaucht: http://www.pokerworld24.org/de/poker_wahrscheinlichkeiten/

Die dort angegebenen Wahrscheinlichkeiten sind das Ergebnis einer Simulation von 2,6 Millionen Händen.

Insofern scheint der Weg über eine Simulation der einfachere zu sein.

Gruß, Andreas


danielf - Mo 08.02.10 14:42

Ja, einmalig ist das klar. Dachte nur man könnte auf diese simulierte Werte aufbauen. Wielang benötigst du den für die Simulation von 500.000 Händen? Vlt. bietet es sich an, die Ergebnisse zu speichern um das Programm schneller zu machen? See RainbowTables ;)


Gravitar - Mo 08.02.10 14:44

user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Ja, einmalig ist das klar. Dachte nur man könnte auf diese simulierte Werte aufbauen. Wielang benötigst du den für die Simulation von 500.000 Händen?


1,5 Sekunden


Vamos - Di 09.02.10 18:48

user profile iconGravitar hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Ihr Lieben,

ich wollte mal ein Kartenspiel komplett allein und ohne cards.dll programmieren, um einfach ein bisschen in Delphi rumzuspielen. Bin auch bisher ziemlich zufrieden, läuft soweit alles, nur beim ermitteln und mischen der Karten stürzt mein Programm manchmal ab....


Hi Vamos,

ich programmiere derzeit einen Poker-Wahrscheinlichkeitsrechner. Dort muss man ebenfalls Karten mischen und austeilen.

Derzeit verzichte ich auf das Mischen komplett!!!

Ich ziehe einfach über Random einzelne Karten aus dem Kartenstapel und verteile diese. Wozu noch mischen, wenn ich sowieso über Random ziehe?

Bei ca. 500.000 Hände, die ich simulieren muss, ist der Verzicht auf das Mischen ein enormer Zeitgewinn.

Als Datenkonstrukt nutze ich eine TList of Records (Kartenwert, Kartenfarbe), da ich nach dem Ziehen diese Karte einfach aus der TList löschen kann und damit sichergestellt ist, dass eine Karte nicht mehrfach gezogen wird.

Vielleicht hilft es ja.

Gruß, Andreas


Hi Andreas, danke für den Tipp!

Das meinte ich am Anfrag des Threads, als ich die TList mit einem Objekt verwechselt habe... Wäre pfiffig gewesen, aber ist leider zu spät.

Dennoch muss es doch möglich sein herauszufinden, warum der bei meiner Variante ständig abstürzt...

Es wäre super, wenn jemand das wüsste und mir den entscheidenen Hinweis geben würde.

Es ist echt ätzend das programm immer gleich einige Male starten zu müssen, damit ich neue Funtkionen ausprobieren kann..

Danke nochmals!


Vamos - Mi 10.02.10 21:29

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Naja, zahlen über 48 gibt es bei meiner Radom eingabe zwangsläufig (48 )+11
Schon, aber warum machst du es denn so?

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Das habe ich so gestaltet, damit eben keine Zahl < 11 rauskommt.
Ja, und wenn du Zahlen zwischen 11 und 48 willst, dann musst du von der Obergrenze eben die addierte 11 wieder abziehen...
Bei Random(38) + 11 kommen Zahlen von 11 <= Zahl <= 48 heraus.


Oh man, klaro, sorry, hab deinen Beitrag völlig überlesen : (

Nur jetzt wirds noch kurioser...

Bei Random(37)+11 (Karten zwischen 11 und 48 stürzt mein Programm IMMER ab, die entsprechende Filterung wenn zahl > 48 habe ich natrülich rausgenommen.

Bei (38)+11 und der Bedingung zahl = 49 --> dann ungültig, funktioniert es relativ gut mit wenig abstürzen... kann sich da keiner einen Reim Drauf machen?


Vamos - Mi 10.02.10 22:59

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Naja, zahlen über 48 gibt es bei meiner Radom eingabe zwangsläufig (48 )+11
Schon, aber warum machst du es denn so?

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Das habe ich so gestaltet, damit eben keine Zahl < 11 rauskommt.
Ja, und wenn du Zahlen zwischen 11 und 48 willst, dann musst du von der Obergrenze eben die addierte 11 wieder abziehen...
Bei Random(38) + 11 kommen Zahlen von 11 <= Zahl <= 48 heraus.


Oh man, klaro, sorry, hab deinen Beitrag völlig überlesen : (

Nur jetzt wirds noch kurioser...

Bei Random(37)+11 (Karten zwischen 11 und 48 stürzt mein Programm IMMER ab, die entsprechende Filterung wenn zahl > 48 habe ich natrülich rausgenommen.

Bei (38)+11 und der Bedingung zahl = 49 --> dann ungültig, funktioniert es relativ gut mit wenig abstürzen... kann sich da keiner einen Reim Drauf machen?


Btw: Das sagt der Compiler... Kann absolut kein assembler und verstehe nichts...:


Moderiert von user profile iconKha: Bild angehängt.


Xentar - Mi 10.02.10 23:16

Da bist du nur beim Standard Haltepunkt, wenn man ein Projekt pausiert.. hat also absolut nichts mit deinem Quellcode zu tun.

Aber: Wenn du schon weißt, wo die Endlosschleife entsteht, warum setzt du nicht einfach da einen Haltepunkt, und guckst nach, warum der nicht mehr rauskommt? Dann musst du halt mal 10 Schleifendurchläufe oder so mit verfolgen - na und?

Und bitte sprich nicht von "abstürzen". Für mich ist ein Absturz eher ein richtiger Crash mit Exception und allem was dazu gehört. Was du hier hast, ist einfach ein Einfrieren, verursacht durch eine Endlosschleife.


Vamos - Mi 10.02.10 23:20

user profile iconXentar hat folgendes geschrieben Zum zitierten Posting springen:
Da bist du nur beim Standard Haltepunkt, wenn man ein Projekt pausiert.. hat also absolut nichts mit deinem Quellcode zu tun.

Aber: Wenn du schon weißt, wo die Endlosschleife entsteht, warum setzt du nicht einfach da einen Haltepunkt, und guckst nach, warum der nicht mehr rauskommt? Dann musst du halt mal 10 Schleifendurchläufe oder so mit verfolgen - na und?

Und bitte sprich nicht von "abstürzen". Für mich ist ein Absturz eher ein richtiger Crash mit Exception und allem was dazu gehört. Was du hier hast, ist einfach ein Einfrieren, verursacht durch eine Endlosschleife.


Ich werd mal versuchen...

Wie man einen Haltepunkt setzt ist mir bewust, nur wo ich ihn setzen muss oder vielmehr wo ich gucken soll, warum er nicht aus der Schleife kommt, ist mir nicht klar...

Für mich ist ein Absturz, wenn meine CPU mit 99% der Leistung an meinem Programm rumrechnet... dann geht nichts mehr und ich muss es killen. Aber ich lerne ja dazu : )

Danke für die Antwort.


Kha - Mi 10.02.10 23:22

Gott, der Bug hat mich fast in den Wahnsinn getrieben :lol: .
Des Rätsels Lösung: Für i=1 wird deine j-Schleife nicht ausgeführt, also kann in zahl[1] eine ungültige Karte landen. Hättest also nur Corpsman folgen und den ungültige-Karte-Test davor setzen müssen ;) :
user profile iconCorpsman hat folgendes geschrieben Zum zitierten Posting springen:
Also was mir ja spontan auffällt, ist das du hier mehrfach auf Zahl[i] in der j schleife zugreifst, d.h. du machst sehr viel doppelt, n-Fach, was total unnütz ist.



user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Bei Random(37)+11 (Karten zwischen 11 und 48 stürzt mein Programm IMMER ab, die entsprechende Filterung wenn zahl > 48 habe ich natrülich rausgenommen.
Hab doch mal etwas mehr Vertrauen in jaenicke :) . Wie er schon schrieb, [11;48] wird von Random(38) + 11 erzeugt, denn:

Delphi-Quelltext
1:
0 <= Random(n) < n                    

Mit deinem Code hast du also eine Karte zu wenig und das Array kann nie voll werden.


Vamos - Mi 10.02.10 23:26

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Gott, der Bug hat mich fast in den Wahnsinn getrieben :lol: .
Des Rätsels Lösung: Für i=1 wird deine j-Schleife nicht ausgeführt, also kann in zahl[1] eine ungültige Karte landen. Hättest also nur Corpsman folgen und den ungültige-Karte-Test davor setzen müssen ;) :

user profile iconCorpsman hat folgendes geschrieben Zum zitierten Posting springen:
Also was mir ja spontan auffällt, ist das du hier mehrfach auf Zahl[i] in der j schleife zugreifst, d.h. du machst sehr viel doppelt, n-Fach, was total unnütz ist.


Ok, super! Mich treibt das auch langsam zum Wahnsinn : ) Weils ja eben sporadisch funktioniert.

Was heißt das im Detail? Wäre jemand so nett und würde mir das umsortieren? Ich wäre so dankbar!!!


user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:
Bei Random(37)+11 (Karten zwischen 11 und 48 stürzt mein Programm IMMER ab, die entsprechende Filterung wenn zahl > 48 habe ich natrülich rausgenommen.
Hab doch mal etwas mehr Vertrauen in jaenicke :) . Wie er schon schrieb, [11;48] wird von Random(38) + 11 erzeugt, denn:

Delphi-Quelltext
1:
0 <= Random(n) < n                    

Mit deinem Code hast du also eine Karte zu wenig und das Array kann nie voll werden.[/quote]

Des hab ich auch gemerkt *schäm* einfaches addieren ist schon Grundvoraussetzung :-S


Vamos - Sa 13.02.10 18:30

Es ist zum Wahnsinnig werden, es will einfach nicht funktionieren, ich lande immer wieder bei meiner Bebugten Lösung:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
for i := 1 to 32 do
  begin
  randomize;
  repeat
  Zahl[i] := Random(38)+11;


    //2 gleiche Karten vermeiden + verbotene Zahlen vermeiden

  doppelt:=false;
  for j :=1 to i-1 do
    begin
      if Zahl[i] = Zahl[j] then doppelt := true
      else if zahl[i] =19 then doppelt := true
      else if zahl[i] =20 then doppelt := true
      else if zahl[i] =29 then doppelt := true
      else if zahl[i] =30 then doppelt := true
      else if zahl[i] =39 then doppelt := true
      else if zahl[i] =40 then doppelt := true

      else if zahl[j] =19 then doppelt := true
      else if zahl[j] =20 then doppelt := true
      else if zahl[j] =29 then doppelt := true
      else if zahl[j] =30 then doppelt := true
      else if zahl[j] =39 then doppelt := true
      else if zahl[j] =40 then doppelt := true;
      //Wenn zwei Karten doppelt sind, wird die boolsche Variable auf true gesetzt.
    end;

  Until not doppelt;

  LBkarten.Items.Add(IntToStr(zahl[i]));
  // Solange wird gesucht, bis keine doppelten mehr vorkommen, also doppelt:=false!
  end;


Wie muss es ritig ausseen, danke, danke, danke im Voraus


Kha - Sa 13.02.10 18:36

Ich hatte eigentlich gehofft, diese letzte Überlegung würdest du alleine schaffen. Die Vergleiche ohne zahl[j] müssen aus der Schleife raus, schreib sie davor.


Martok - Sa 13.02.10 18:37

Möchte nur mal vorschlagen, wie es denn am schnellsten wäre...

Alle Karten in einen Stapel, Fisher-Yates drauf anwenden, und dann der Reihe nach ziehen. Ist eigentlich das einzige was definitv auch in endlicher Zeit terminiert. Und entspricht auch eher einem Spielablauf.

Dein Code läuft potentiell immer in Quasi-Endlosschleifen (da kenn ich mich aus, ist mal ein Map-Generator dran wegestorben), wenn Random einfach mal ungünstige Folgen liefert.


Vamos - Sa 13.02.10 18:40

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Ich hatte eigentlich gehofft, diese letzte Überlegung würdest du alleine schaffen. Die Vergleiche ohne zahl[j] müssen aus der Schleife raus, schreib sie davor.



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
//Karten mischen

for i := 1 to 32 do
  begin
  randomize;
  repeat
  Zahl[i] := Random(38)+11;
  doppelt:=false;
  if zahl[i] =19 then doppelt := true
  else if zahl[i] =20 then doppelt := true
  else if zahl[i] =29 then doppelt := true
  else if zahl[i] =30 then doppelt := true
  else if zahl[i] =39 then doppelt := true
  else if zahl[i] =40 then doppelt := true;


    //2 gleiche Karten vermeiden + verbotene Zahlen vermeiden


  for j :=1 to i-1 do
    begin
      if Zahl[i] = Zahl[j] then doppelt := true
      else if zahl[j] =19 then doppelt := true
      else if zahl[j] =20 then doppelt := true
      else if zahl[j] =29 then doppelt := true
      else if zahl[j] =30 then doppelt := true
      else if zahl[j] =39 then doppelt := true
      else if zahl[j] =40 then doppelt := true;
      //Wenn zwei Karten doppelt sind, wird die boolsche Variable auf true gesetzt.
    end;

  Until not doppelt;

  LBkarten.Items.Add(IntToStr(zahl[i]));
  // Solange wird gesucht, bis keine doppelten mehr vorkommen, also doppelt:=false!
  end;


?

Edit: Hmmmm, sieht ganz gut aus, muss das leider jetzt er erst 40-50 mal neu starten, da es auch ab und an mal stabil lief. Wenns klappt, kann ich nur nochmal sagen: Danke, danke, danke : )

Sekundär, aber nicht unwichtig, ich versuche immernoch zu verstehen, warum mein Ansatz falsch war, vielleicht nehm ich mir nochmal nen Zettel und nen Stift.


jaenicke - Sa 13.02.10 19:24

user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  if zahl[i] =19 then doppelt := true
  else if zahl[i] =20 then doppelt := true
  else if zahl[i] =29 then doppelt := true
  else if zahl[i] =30 then doppelt := true
  else if zahl[i] =39 then doppelt := true
  else if zahl[i] =40 then doppelt := true;
Wie wäre es so:

Delphi-Quelltext
1:
  doppelt := zahl[i] in [192029303940];                    
;-)
Also insgesamt:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
//Karten mischen

for i := 1 to 32 do
begin
  Randomize;
  repeat
    Zahl[i] := Random(38) + 11;
    doppelt := zahl[i] in [192029303940];

    //2 gleiche Karten vermeiden + verbotene Zahlen vermeiden

    for j := 1 to i - 1 do
      if zahl[j] in [zahl[i], 192029303940then
        doppelt := true
      //Wenn zwei Karten doppelt sind, wird die boolsche Variable auf true gesetzt.
  until not doppelt;

  LBkarten.Items.Add(IntToStr(zahl[i]));
  // Solange wird gesucht, bis keine doppelten mehr vorkommen, also doppelt:=false!
end;


Vamos - Sa 13.02.10 19:26

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconVamos hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  if zahl[i] =19 then doppelt := true
  else if zahl[i] =20 then doppelt := true
  else if zahl[i] =29 then doppelt := true
  else if zahl[i] =30 then doppelt := true
  else if zahl[i] =39 then doppelt := true
  else if zahl[i] =40 then doppelt := true;
Wie wäre es so:

Delphi-Quelltext
1:
  doppelt := zahl[i] in [192029303940];                    
;-)
Also insgesamt:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
//Karten mischen

for i := 1 to 32 do
begin
  Randomize;
  repeat
    Zahl[i] := Random(38) + 11;
    doppelt := zahl[i] in [192029303940];

    //2 gleiche Karten vermeiden + verbotene Zahlen vermeiden

    for j := 1 to i - 1 do
      if zahl[j] in [zahl[i], 192029303940then
        doppelt := true
      //Wenn zwei Karten doppelt sind, wird die boolsche Variable auf true gesetzt.
  until not doppelt;

  LBkarten.Items.Add(IntToStr(zahl[i]));
  // Solange wird gesucht, bis keine doppelten mehr vorkommen, also doppelt:=false!
end;


Cool, danke für den Tipp! "in" hab ich noch nie genutzt, probiere es mal, ist auf jedenfall dann ordentlicher.