Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Mastermind: 4 verschieden zufällige Variablen benötigt


Poerslasher - Mi 29.04.09 17:49
Titel: Mastermind: 4 verschieden zufällige Variablen benötigt
Ich brauche für ein Spiel (Mastermind) 4 verschiedene zufällige Variablen im Bereich von 0-7. Ist es irgendwie möglich sicherzustellen, dass die Zahl jedes mal eine andere ist?


Delphi-Quelltext
1:
2:
3:
4:
5:
Randomize;
VorgabeA := Random(8);
VorgabeB := Random(8);
VorgabeC := Random(8);
VorgabeD := Random(8);


Es soll gelten: VorgabeA = VorgabeB = VorgabeC = VorgabeD

Gruß Poerslasher


jakobwenzel - Mi 29.04.09 17:50

Man könnte jetzt solang neue Zahlen würfeln bis es eine is die noch nich dabei war, den richtigen Weg gibts aber hier:
http://www.delphi-library.de/topic_perfektes+Mischen+nach+FisherYates+perfect+shuffle_71713.html


Poerslasher - Mi 29.04.09 18:21

Dankeschön, ich verstehs nur irgendwie nicht so ganz^^
wie kann ich denn jetzt in dem bestimmten Fall meine 4 Variablen die gewürfelten Werte zuweisen?


Dude566 - Mi 29.04.09 18:25

Du weist jeder der Zahlen eine Farbe zu, und wenn die Zahl noch nicht gewürfelt wurde kannst du sie verwenden.
Du musst eine Abfrage machen, ob die Zahl schon einmal gefallen ist, wenn ja dann den Vorgang wiederholen, solange bis eine Zahl kommt die noch nicht gefallen ist.


jakobwenzel - Mi 29.04.09 18:35

Genau das ist der falsche Weg, Dude566
Du schmeißt die Zahlen in ein Array, durchmischst das nach dem Mischalgorithmus den ich vorhin gepostet hab und nimmst dir dann die ersten vier Zahlen raus. Die Begründung warum das besser ist steht auch bei dem Link. ;)


Dude566 - Mi 29.04.09 18:50

Ja, aber es ginge doch auch so wie ich geschrieben habe oder?


jaenicke - Mi 29.04.09 19:09

Gehen tut es schon, aber es kann ggf. sehr lange dauern, wenn du Pech hast. Gerade bei so wenigen möglichen Zahlen kann das passieren, wenn zufällig immer schon benutzte getroffen werden (was ja nicht unwahrscheinlich ist einige Male).

Und nebenbei ist es von der Programmierung her auch aufwendiger und schwieriger. ;-)


Poerslasher - Mi 29.04.09 19:19

Ich schaffs irgendwie nicht das zum laufen zu bringen^^
Wie muss ich denn das array deklarieren? Ich habs jetzt als globale variable deklariert:

Delphi-Quelltext
1:
2:
var
  TArray: array [1..8of integer;


passt das so? Wo muss ich das TarrayElement deklarieren?


jaenicke - Mi 29.04.09 19:27

Das Element im Array ist bei dir ja einfach nur ein Integer, und diese Deklaration steht doch exakt als Beispiel ganz oben im Beitrag drin. ;-)


Poerslasher - Mi 29.04.09 19:33

Und wo muss ich das deklarieren?


jaenicke - Mi 29.04.09 19:51

Schau oben einmal hin, da steht schon eine Typdeklaration, nämlich die deines Formulars. Du schreibst jetzt einfach oberhalb von TForm1 = ... die weitere Definition hin.


Poerslasher - Mi 29.04.09 20:12

Jo gut, ich habs unter TForm1 deklariert, das hat nicht funktioniert.

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:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
unit MastermindUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
    TArrayElement = Integer;
    TArray = array of TArrayElement;
  TForm1 = class(TForm)
    VorgabeAEdit: TEdit;
    A1: TEdit;
    NeuesSpiel: TButton;
    VorgabeBEdit: TEdit;
    VorgabeCEdit: TEdit;
    VorgabeDEdit: TEdit;
    Test: TLabel;
    Fertig: TButton;
    B1: TEdit;
    C1: TEdit;
    D1: TEdit;
    procedure FertigClick(Sender: TObject);
    procedure NeuesSpielClick(Sender: TObject);

  private
    { Private-Deklarationen}

  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  VorgabeA, VorgabeB, VorgabeC, VorgabeD :Integer;



implementation

{$R *.dfm}


procedure TForm1.NeuesSpielClick(Sender: TObject);
 var  i,j: Integer;
      tmp: TArrayElement;
      aArray : Tarray;
begin
   Randomize;

     // alle Elemente des Feldes durchlaufen
  for i := Low(aArray) to High(aArray) do begin
    // neue, zufällig Position bestimmen
    j := i +Random(Length(aArray) -i);
    // Element Nr. i mit Nr. j vertauschen (3ecks-Tausch)
    tmp := aArray[j];
    aArray[j] := aArray[i];
    aArray[i] := tmp;
  end;

     VorgabeA := aArray[1];
     VorgabeB := aArray[2];
     VorgabeC := aArray[3];
     VorgabeD := aArray[4];

end;

end.


Wo muss ich denn nun die Länge des Arrays also [1..8] angeben?


jaenicke - Mi 29.04.09 20:15

Du musst vor der Verwendung diese mit SetLength setzen.

Delphi-Quelltext
1:
SetLength(aArray, ...);                    
So musst du die Größe des Arrays nicht bereits im Quelltext ganz festlegen, sondern die Größe auch zur Laufzeit setzen.


Poerslasher - Sa 02.05.09 10:33

Ok, jetzt hats geklappt ;-)
Das Problem war dass ich vergessen hatte meinem Array Werte zuzuweisen.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
// perfektes Mischen nach Fisher-Yates (angelehnt an einen Vorschlag von alzaimar)
procedure ShuffleFisherYates(var aArray: TArray);
  var
    i,j: Integer;
    tmp: TArrayElement;
begin
   aArray[1]:=1;
   aArray[2]:=2;
       .
       .
       .
  // alle Elemente des Feldes durchlaufen
  for i := Low(aArray) to High(aArray) do begin
    // neue, zufällig Position bestimmen
    j := i +Random(Length(aArray) -i);
    // Element Nr. i mit Nr. j vertauschen (3ecks-Tausch)
    tmp := aArray[j];
    aArray[j] := aArray[i];
    aArray[i] := tmp;
  end;
end;


Danke für alle antworten! ;-)


jaenicke - Sa 02.05.09 14:53

Das solltest du aber machen bevor du es an ShuffleFisherYates übergibst, schließlich heißt das ja Shuffle und nicht Wertzuweisung und Shuffle. ;-)