Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Randomize und Überprüfung


Avalon - Do 11.03.04 15:03
Titel: Randomize und Überprüfung
Wir haben im Informatikunterricht ein Memory programmiert, aber dieses tolle teil kann nicht mischen....sehr schön, nur gespiegelte Bilder. Der anspruch ließe sich durch Mischen steigern! Also wollen wir eine Random-Funktion einbauen...nur zu dumm, dass unser Lehrer auch nicht weiß, wie! Und dann müsste noch jede Karte garantiert 2 mal da sein, nicht mehr und nicht weniger. Kann jemand sagen, wie das geht??? Bitte!!!
Unser Quelltext:


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:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
unit Unit1;

interface

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

type
    TKarte = class(TImage)
  constructor create(owner:TWinControl; x,y: integer; ICO : String);
        public
        procedure turn(sender: TObject);
        procedure zeigeBild;
        procedure zeigeRueckseite;
        procedure click(sender: TObject);
        private
        isbild: Boolean;
        Bild: TPicture;
        Rueckseite: TPicture;
        bildname:string;
        end;



    TForm1 = class(TForm)
    Rueckseite: TButton;
    Bild: TButton;
    closeButton: TBitBtn;
    procedure FormCreate(Sender: TObject);
    procedure BildClick(Sender: TObject);
    procedure RueckseiteClick(Sender: TObject);
    procedure closeButtonClick(Sender: TObject);
    procedure Playmemory (Sender:TObject);

private

  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  IcoPath: String;
implementation

{$R *.dfm}


constructor TKarte.create(owner:TWinControl; x,y: integer; ICO : String);
begin
inherited create(owner);
parent:= Owner;
Top:= y; Left:= x;
AutoSize:= true;
Rueckseite:=TPicture.create;
Rueckseite.LoadFromFile('u:/delphi-programme/memory/bilder/icon0.ico');
Bild:=TPicture.Create;
Bild.LoadFromFile('U:\Delphi-Programme\Memory\bilder\'+ico);
Picture:=Rueckseite;
IsBild:= false;
onClick:=click;
bildname:= ico;
end;


procedure TKarte.turn;
begin
if isbild then
Zeigerueckseite
else
zeigeBild;
end;


procedure TKarte.zeigeRueckseite;
begin
hide; Picture:=Rueckseite; show; isbild:=false;
end;


procedure TKarte.zeigeBild;
begin
hide; Picture:=Bild; show; isbild:=true;
end;


procedure TForm1.BildClick(Sender: TObject);
var i: integer;
begin
  for i:=0 to Componentcount-1 do
    if Components[i] is TKarte  then (Components[i] as TKarte).zeigeBild;
end;

procedure TForm1.RueckseiteClick(Sender: TObject);
var i: integer;
begin
  for i:=0 to Componentcount-1 do
    if Components[i] is TKarte  then (Components[i] as TKarte).zeigeRueckseite;
end;

procedure TForm1.FormCreate(Sender: TObject);
const IconZahl =20;
Var x, y : integer;
    i : integer;
    icoName: String;

    procedure NextPos(Var x, y: integer);
    begin
    if x >= 320 Then begin
     x := 0; y:= y+40end;
     x:= x+40;
     end;

begin
 x:= 0; y:= 10;
 for i:= 1 to iconZahl do begin
 nextpos(x,y);
 IcoName:='icon' + intToStr(i)+'.ico';
 TKarte.create(Form1, x, y, IcoName);
 end;
 for i:=iconZahl downto 1 do begin
 NextPos(x,y);
 IcoName:='icon' + intToStr(i)+'.ico';
 TKarte.create(Form1, x,y, iconame);
 end;
end;

procedure TForm1.closeButtonClick(Sender: TObject);
begin
close;
end;



 procedure TKarte.Click(Sender:TObject);
 begin
 Form1.Playmemory(Sender);
 if isbild=false then
 Turn(Sender);
 end;

 procedure TForm1.playmemory(sender:TObject);

  procedure Abraeumen;
    var i: integer;
    begin
      i:=0;
      while i < Form1.ComponentCount do
      if Form1.Components[i] is TKarte then
         if TKarte(Form1.Components[i] as TKarte).IsBild then
            TKarte(Form1.Components[i]).free
         else
            inc(i)
      else
         inc(i);
    end;

    function zweiaufgedeckt: boolean;
    var i,n: integer;
    begin
      n:=0;
      for i:=0 to Form1.ComponentCount-1 do
        with  TKarte(Components[i])do
         if Form1.Components[i] is TKarte then
         if IsBild then inc(n);
      zweiaufgedeckt:= n=2;
    end;

    function gleicheBilder: boolean;
    var i: integer;  n: string;
    begin
      n:=''; gleicheBilder:= false;
      for i:=0 to Form1.ComponentCount-1 do
        with  TKarte(Form1.components[i]) do
          if Form1.Components[i] is TKarte then
         if IsBild then
                if BildName <> n then
                   n:= BildName
                else
                   gleicheBilder:= true;
    end;

    procedure AlleRueckseite;
    var i: integer;
    begin
      for i:=0 to Form1.ComponentCount-1 do
        if Form1.Components[i] is TKarte then
        if TKarte(Form1.Components[i]).IsBild then
           TKarte(Form1.Components[i]).zeigeRueckseite;
    end;


       begin
  if zweiaufgedeckt then
     if gleichebilder then
        Abraeumen
     else
        AlleRueckseite;
end;


end.


Danke im Vorraus !
Cu later


Pascal - Do 11.03.04 19:41

Ich würde im Create-Teil die Koordinaten zufällig vergeben, bzw den Koordinaten zufällige Karten geben. dafür würde ich die Kartennummern in eine Stringlist einlesen und dann statt der Laufvariablen eine zufällige Zeile als Kartennummer nehmen und diese dann löschen.

also so:

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:
procedure TForm1.FormCreate(Sender: TObject);
const IconZahl =5;
Var x, y : integer;
    i,i2,rand : integer;
    icoName: String;
    List:TStringlist;

    procedure NextPos(Var x, y: integer);
    begin 
    if x >= 320 Then begin
     x := 0; y:= y+40end;
     x:= x+40;
     end

begin 
 x:= 0; y:= 10;
 list:=TStringlist.create;
 for i:= 1 to iconZahl do list.Add(inttostr(i));

 for i2:= 1 to iconZahl do begin
 randomize;
 rand:=random(list.count);
 i:=strtoint(list[rand]);
 list.Delete(rand);
 nextpos(x,y);
 IcoName:='icon' + intToStr(i)+'.ico';
 TKarte.create(Form1, x, y, IcoName);
 end;
 for i:=iconZahl downto 1 do begin
 NextPos(x,y);
 IcoName:='icon' + intToStr(i)+'.ico';
 TKarte.create(Form1, x,y, iconame);
 end;

list.Free;
end;


Seniman - Do 11.03.04 21:09

Hallo,

ich hatte mal ein ähnlichen Problem, als ich versucht habe ein Kartenspiel zu programmieren. Da sollten alle Karten auch genau ein mal da sein. Ich hab das dann so gelöst:
Erstelle ersteinmal alle Karten in geordneter Reihenfolge. Schreibe dann eine Prozedur, die zwei Karten zufällig auswählt und sie dann vertauscht. Diese Prozedur solltest du dann ca. 1000 mal ausführen, dann sind die Karten gut gemischt.

Grüße
Seniman


Pascal - Do 11.03.04 21:57

Das ist sicher auch eine Möglichkeit, aber ich glaube, die ist in dem Fall schwieriger. Die Frage ist ja wie man bei einer variablen Kartenzahl die zu vertauschende Karte herausfindet. Ich wüsste nur findcomponent().

oder diese Möglichkeit:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TForm1.Button1Click(Sender: TObject);
var t,rnd:integer;list:TStringlist;
begin
list:=TStringlist.Create;
for t:= 0 to componentcount-1 do
if (components[t] is tKarte) then begin
list.add(inttostr((components[t] as tKarte).top));
list.add(inttostr((components[t] as tKarte).left));
end;
for t:= 0 to componentcount-1 do
if (components[t] is tKarte) then begin
randomize;
rnd:=random(list.count div 2);
(components[t] as tKarte).top:=strtoint(list[rnd*2]);
(components[t] as tKarte).left:=strtoint(list[rnd*2+1]);
list.Delete(rnd*2);
list.Delete(rnd*2);
end;
list.Free;

end;

Die vertauscht aber auch gleich alle auf einmal.
Vorteile zu meiner anderen Version ist, dass man diese auch wärend des Programms ausführen kann, dass man Diese Procedure einfach in das Programm einfügen kann und man nichts ersetzen muss und ich finde sie schaut professioneller aus,
was aber auch gleich ein Nachteil ist, denn bisher habe ich noch niemanden gefunden, der sie wirklich verstanden hat.
(Ich habe sie mal für nen Freund geschrieben, der auch so ne Art Memory programmiert hat)


Avalon - Fr 12.03.04 17:19

Vielen vielen Dank.
Jetzt muss ich das nur noch verstehen, einproggen und erklären können, und schon ist mit die 1+ sicher !

Thx very much !
Avalon


catweasel - Fr 12.03.04 21:08

Das gleiche Problem habe ich auch bei meinem Memory gehabt.. Ich hab es folgendermassen gelöst... (So grob in etwa)

Ausgangssituation: Bilderliste mit den Kartenotiven (keine doppelten Bilder)..

Erstellen eines Arrays in die jedes Bild zweimal eingetragen wird...
Es entste also ein array das doppelt so gross ist und jedes Bild zweimal enthält.
Ob man die Bilderliste zweimal hintereinander in einem Rutsch ablegt, (array = bild1,bild2,bild3,bild1,bild2,bild3) oder direkt jedes Bild zweimal (array = bild1,bild1,bild2,bild2,bild3,bild3) ist zunächst erstmal egal...

Dann wird das array per Zufall nurnoch umdortiert. Damit idt die Problemstellung ähnlich dem Ziehen von Lottozahlen ohne doppelte gezogene Zahlen...
(Dazu hatte ich hier auchmal was gepostet, http://www.delphi-forum.de/viewtopic.php?t=20163 )

Danach hast du ein array mit zwei Exemplaren jedes Bildes in einer zufälligen Reihenfolge..
hierbei muss auch nur sovielmal gemischt werden wie Karten vorhanden sind, also nix mit random Schleifen "oft genug" aufgerufen werden müssen...

Ich kann dir mein Memory ja mal schicken..

Bei Interesse einfach ne PN mit emailadresse (hab immernoch keinen Webspace)

Catweasel