Bei Verwendung der VCL wird das automatisch erledigt, weil Viele es sändig vergessen.
(in der Initialisierung der VCL wird einmal Randomize ausgeführt)
Ich weiß nicht, auf welche Delphiversion bzw. ab welcher Delphiversion Du Dich beziehst, aber bis Delphi 7, das ich zur Compilierung meines Sortieranimationsprogrammes benutze, ist es sehr wohl unterschiedlich, ob ich randomize (im Initialisationsteil der ersten VCL-Unit) aufrufe oder es unterlasse. Verzichte ich auf diesen Befehl, sind die Zufallszahlen nach jedem Programmstart die gleichen.
Edit: Ein "automatisches" Randomize ist ein zweischneidiges Schwert. Wie will man "vernünftig", "produktiv" debuggen, wenn man keine reproduzierbaren Ergebnisse erhält?
Geändert von Delphi-Laie ( 2. Sep 2017 um 17:45 Uhr)
Edit: Ein "automatisches" Randomize ist ein zweischneidiges Schwert. Wie will man "vernünftig", "produktiv" debuggen, wenn man keine reproduzierbaren Ergebnisse erhält?
Nicht mit Zufalls werten arbeiten, oder vorher den Test "ordentlich" initialisieren (RandSeed), wenn es nötig ist.
Das mit der Automatik wurde nicht gleich zu beginn eingebaut.
Dachte bei D7 ist es schon da, aber spätestens mit XE ist es so.
AW: Tipps und Ratschläge für Spiel & für effizientes Programmieren
3. Sep 2017, 20:50
Ja es wird alles beachtet was beim Plazieren der Schiffe notwenig ist; dass es aus dem Feld nicht herausragt, dass dieses Schiff mit anderen nicht kollidiert oder sie sich berühren. Und solange nicht all diese Bedingungen erfüllt sind, wird das Schiff zufällig neu plaziert. Und mir ist schon unverständlich wie man da aus der Schleife rauskommt, solange noch nicht alle Schiffe plaziert worden sind^^
Wenn ich randomize in FormCreate (wird ja nur einmal aufgerufen) auskommentiere, bleibt der Fehler weiterhin.
procedure TForm1.SetzeFlotte(ofPlayer: boolean); var
zahl, i, j, k, fehlenNoch, vofPlayer: Integer;
done, alleProbiert: Boolean;
richtungProbiert: array[0..3] of Boolean; begin
vofPlayer:=StrToInt(BoolToStr(ofPlayer, false)) + 1;
flotte[vofPlayer].Free;
flotte[vofPlayer]:=TFlotte.Create(flottengroesse[5], flottengroesse[4],
flottengroesse[3], flottengroesse[2], flottengroesse[1]); for i:=5 downto 1 do begin
j:=1;
fehlenNoch:=flotte[vofPlayer].AnzahlFehlenderSchiffeDerGroesse(i); while j <= fehlenNoch do begin
done:=false; repeat
zahl:=random(feldgroesse * feldgroesse) + 1; for k:=0 to 3 do richtungProbiert[k]:=false;
a:=Point(((zahl - 1) mod feldgroesse) + 1, ((zahl - 1) div feldgroesse) + 1); repeat
k:=random(4);
alleProbiert:=true; case k of
0: if a.Y >= i then b:=Point(a.X, a.Y - i + 1);
1: if a.Y + i - 1 <= feldgroesse then b:=Point(a.X, a.Y + i - 1);
2: if a.X >= i then b:=Point(a.X - i + 1, a.Y);
3: if a.X + i - 1 <= feldgroesse then b:=Point(a.X + i - 1, a.Y); end; ifnot richtungProbiert[k] then done:=flotte[vofPlayer].SetzeSchiff(a, b);
richtungProbiert[k]:=true; for k:=0 to 3 do ifnot richtungProbiert[k] then alleProbiert:=false; until alleProbiert or done; until done;
Inc(j); end; end;
FeldPlayer.Repaint; end;
Hier die darin benutzte boolsche Funktion SetzeSchiff(a, b: TPoint) aus der Klasse TFlotte, die genau dann true zurückgibt, wenn das Platzieren des Schiffes im Feld unter den bekannten Regeln erfolgreich war:
function TFlotte.SetzeSchiff(a: TPoint; b: TPoint): boolean; var
laenge, vmin, vmax, i: integer; begin if IstGueltig(a, b) then begin if a.X=b.X then laenge:=max(a.Y,b.Y)-min(a.Y,b.Y)+1 else laenge:=max(a.X,b.X)-min(a.X,b.X)+1; if laenge>1 then Inc(schiffsanzahl);
SetLength(vSchiff[laenge],Length(vSchiff[laenge])+1);
vSchiff[laenge,high(vSchiff[laenge])]:=TSchiff.Create; if a.X=b.X then begin
vmin:=min(a.Y,b.Y); vmax:=max(a.Y,b.Y); for i:=vmin to vmax do if laenge=1 then feld[a.X-1,i-1]:=3 else feld[a.X-1,i-1]:=1;
result:=vSchiff[laenge,high(vSchiff[laenge])].SetzeSchiff(Point(a.X,vmin),Point(a.X,vmax)); endelse if a.Y=b.Y then begin
vmin:=min(a.X,b.X); vmax:=max(a.X,b.X); for i:=vmin to vmax do if laenge=1 then feld[i-1,a.Y-1]:=3 //Setze Mine else feld[i-1,a.Y-1]:=1;
result:=vSchiff[laenge,high(vSchiff[laenge])].SetzeSchiff(Point(vmin,a.Y),Point(vmax,a.Y)); end else
result:=false end else
result:=false end;
Und hier zuletzt die darin benutzte boolsche Funktion SetzeSchiff(a, b: TPoint) aus der Klasse TSchiff, die bei Erfolg ebenfalls true liefert:
function TSchiff.SetzeSchiff(a,b: TPoint): boolean; var
istSchiff: boolean;
i: integer; begin
istSchiff:=(a.X=b.X) and (abs(a.Y-b.Y)<5) or (a.Y=b.Y) and (abs(a.X-b.X)<5); if istSchiff then begin
vStart:=a; vEnde:=b; if a.X=b.X then laenge:=abs(a.Y-b.Y)+1 else laenge:=abs(a.X-b.X)+1;
vWaagerecht:=a.Y=b.Y;
SetLength(vSchiff,laenge); for i:=1 to laenge do vSchiff[i-1]:=false; end;
result:=istSchiff; end;
So und jetzt kommt das Irre: bleibt die äußerste Zählschleife in SetzeFlotte als i:=5 downto 1, wird in manchen Fällen das 5er Schiff nicht gezeichnet, die Flotte besteht also nur aus dem 3er (linkes Bild im Anhang). Ändere ich die Zählschleife aber in i:=1 to 5, wird (wenn auch noch seltener) das 3er Schiff vergessen und nur das 5er Schiff plaziert (rechtes Bild im Anhang).
Edit: Ein "automatisches" Randomize ist ein zweischneidiges Schwert. Wie will man "vernünftig", "produktiv" debuggen, wenn man keine reproduzierbaren Ergebnisse erhält?
Nicht mit Zufalls werten arbeiten, oder vorher den Test "ordentlich" initialisieren (RandSeed), wenn es nötig ist.
Das mit der Automatik wurde nicht gleich zu beginn eingebaut.
Dachte bei D7 ist es schon da, aber spätestens mit XE ist es so.
Nein, und auch bei Turbo-Delphi (das wohl intern einem Delphi 2006 entsprechen dürfte) gibt es noch kein "automatisches" Randomize.