Entwickler-Ecke

Sonstiges (Delphi) - Programmierung Türme von Hanoi


nairolf92 - Di 09.02.10 16:58
Titel: Programmierung Türme von Hanoi
Hallo,

ich soll von der Schule aus das Spiel "Die Türme von Hanoi" programmieren. Als Türme und Scheiben hab ich jeweils Leinwände benutzt. Ich kann auch schon die scheiben bewegen, indem ich die ausgewählte anklicke und dann in ein Edit feld eine Zahl reinschreibe.
Jetzt habe ich aber das Problem, dass ich nicht weiß wie ich schreiben kann, ob ein Turm schon von einer oder zwei Scheibe/n besetzt wurde. In diesem Fall soll die dahin gezogene Scheibe seine top-Position verändern (-32).

Habt ihr Ideen oder Lösungen zu diesem Problem? Wäre euch echt dankbar;)

MfG
Florian


Xion - Di 09.02.10 17:20

user profile iconnairolf92 hat folgendes geschrieben Zum zitierten Posting springen:
Als Türme und Scheiben hab ich jeweils Leinwände benutzt.


Leinwände? Vielleicht steh ich nur grad aufm Schlauch weil mir das passende englische Wort nicht einfällt, dass mir da was sagen würde...*LEO nachguck*...aaah, Canvas ^^ Das sagt mir was :D

Ok, das Problem ist, so wie ich das verstehe, dass du unten im Stapel was rausnimmst und die andren müssten "runterfallen".

Kannst du mal zeigen, wie du die Scheiben zeichnest?


Dude566 - Di 09.02.10 17:27

Ich glaube bei dem Spiel kann man keine Scheiben von unten rausnehmen, nur die Oberste oder?


nairolf92 - Di 09.02.10 17:27

Ja mein Lehrer benutzt immer den Begriff Leinwände :D.
Nicht ganz. Ich möchte das ich, wenn schon eine Scheibe auf einem Turm liegt, die andere darauf legen können. Bisher ist es aber so, dass sie die andere überdeckt. Ich hab auch schon einen Lösungsansatz aber der funktiniert nicht so wirklich. Hab mal mein Programm angehangen.


Xion - Di 09.02.10 17:36

user profile iconDude566 hat folgendes geschrieben Zum zitierten Posting springen:
Ich glaube bei dem Spiel kann man keine Scheiben von unten rausnehmen, nur die Oberste oder?

Jo, das weiß ich auch...ist aber je kein Grund es nicht zu tun, oder? :P

user profile iconnairolf92 hat folgendes geschrieben Zum zitierten Posting springen:
Ich möchte das ich, wenn schon eine Scheibe auf einem Turm liegt, die andere darauf legen können. Bisher ist es aber so, dass sie die andere überdeckt.


Achso, das ist einfach...

Du speicherst einfach, auf welchem Stapel wieviele liegen.


Delphi-Quelltext
1:
2:
3:
  Stapel1ScheibenAnzahl:=3;
  Stapel2ScheibenAnzahl:=0;
  Stapel3ScheibenAnzahl:=0;


Und immer wenn du eine verschiebst, machst du ca so:
(Bsp von Stapel 1 nach 2)

Delphi-Quelltext
1:
2:
3:
Scheibe1.Top:=x+32*Stapel2ScheibenAnzahl;
Stapel2ScheibenAnzahl:=Stapel2ScheibenAnzahl+1;
Stapel1ScheibenAnzahl:=Stapel1ScheibenAnzahl-1;


Hab deinen SourceCode nur mal überflogen, das ist ziemlich wirr eingerückt


nairolf92 - Di 09.02.10 18:28

Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

Danke, habs geschafft ;)


nairolf92 - Mo 15.02.10 18:23

So, hab nun erneut ein Problem bei dem ich eure Hilfe benötige.
Ich soll eine Prozedur erstellen, in der ich nur den Anfangs und Endpunkt angeben soll und dann die Scheiben automatisch dahin bewegt werden. Hab schonmal ein Lösungsansatz:

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:
procedure bewegen(start,ziel:integer) ;
var safe,Auswahl1,Auswahl2,Auswahl3,a,s1a,s2a,s3a:integer;
begin
s1a := strtoint(edit5.text);
s2a := 0;
s3a := 0;
Auswahl1 :=s1a;
Auswahl2 :=s2a;
Auswahl3 :=s3a;


if (start = 1and (ziel = 2then
  safe:=12;
 if safe=12 then
 begin image(Auswahl1).top := (408-32*s2a);
       image(Auswahl1).left := image(Auswahl1).left+184;
       s1a:=s1a-1;
       s2a:=s2a+1;


       end;
 if (start=1and (ziel=3then
 safe:=13;
 if safe=13 then
 begin
 image(Auswahl1).top := (408-32*s3a);
 image(Auswahl1).left := image(Auswahl1).left+368;
 s1a:=s1a-1;
       s3a:=s3a+1;

  if (start=2and (ziel=3then
 safe:=23;
 if safe=23 then
 begin
 image(Auswahl2).top := (408-32*s3a);
 image(Auswahl2).left := image(Auswahl2).left+184;
 s2a:=s2a-1;
       s3a:=s3a+1;

  if (start=2and (ziel=1then
 safe:=21;
 if safe=21 then
 begin
 image(Auswahl2).top := (408-32*s1a);
 image(Auswahl2).left := image(Auswahl2).left-184;
 s2a:=s1a-1;
       s1a:=s1a+1;

  if (start=3and (ziel=1then
 safe:=31;
 if safe=31 then
 begin
 image(Auswahl).top := (408-32*s1a);
 image(Auswahl).left := image(Auswahl).left-368;
 s3a:=s3a-1;
       s1a:=s1a+1;

  if (start=3and (ziel=2then
 safe:=32;
 if safe=32 then
 begin
 image(Auswah)l.top := (408-32*s1a);
 image(Auswahl).left := image(Auswahl).left-184;
 s3a:=s3a-1;
       s2a:=s2a+1;
       end;

die zahlen (bei start und ziel stehen für die türme, s1a soll Stapel1Anzahl heißen, also die Anzahl der Scheiben die auf Stapel 1 liegen und edit5 ist das feld in den man diese Anzahl von 1-8 festlegen kann). Ich merke grad, dass die variable safe unnütz ist, aber abgesehen davon zeigt er noch ziemlich viele fehlermeldungen an.
darf man bei einer prozedur nicht auf die edit- und image felder zurückgreifen? wenn ja wie könnte ich es anders schreiben?


Blackheart666 - Mo 15.02.10 18:27

Gib doch beim nächsten mal den Crosspost mit an
http://www.delphipraxis.net/topic173335_programmierung+tuerme+von+hanoi.html


Jakob_Ullmann - Mo 15.02.10 18:57

Also auf jeden Fall solltest du deinen Code besser einrücken, so ist es total unleserlich. Und ich glaube auch, dass es für dich einfacher sein würde, wenn du folgendes Konzept verwendest (so habe ich das mal relativ schnell geschafft):

- nimm ein array of TColor und speichere Farben für jede Scheibe ab.
- nimm eine Zeichenfläche und male darauf die Scheiben mit Canvas.Ellipse
- dann musst du nur noch Start- und Zielstapel bei OnMouseUp und OnMouseDown abfragen und verschiebst nur die oberste Scheibe.

So hat man am wenigsten Code, schafft es schön schnell und sauber und es ist gewährleistet, dass die Regeln eingehalten werden.


nairolf92 - Mo 15.02.10 21:18

Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

Ok, was genau bewirkt OnMouseUp und OnMouseDown?


MaPsTaR - Mo 15.02.10 21:30

OnMouseDown wird aufgerufen, wenn du, auf dem Objekt, die Maustaste drückst.
OnMouseUp wird aufgerufen, wenn du die Maustaste wieder loslässt.


nairolf92 - Mo 15.02.10 23:31

user profile iconMaPsTaR hat folgendes geschrieben Zum zitierten Posting springen:
OnMouseDown wird aufgerufen, wenn du, auf dem Objekt, die Maustaste drückst.
OnMouseUp wird aufgerufen, wenn du die Maustaste wieder loslässt.

Ach so, dann hilft mir der Vorschlag von Jakob leider nicht weiter, da ich eine Prozedur programmieren soll, die ich in einer anderen verwenden kann, d.h. sie muss ohne Interaktionen auf dem Feld auskommen.


nairolf92 - Mi 17.02.10 19:19

so hab die prozedur jetz ein bisschen verändert:

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:
var
    Scheibenbild: Array [1..8,1..3of timage;
    sa: Array[1..3of integer;



procedure TForm1.FormCreate(Sender: TObject);
var n : integer;
begin

  For n := 1 to 8 do
  Begin
   sa[1] := n;
   sa[2] := 0;
   sa[3] := 0;
  end;

Scheibenbild[1,1] := Scheibe4;
Scheibenbild[2,1] := Scheibe5;
Scheibenbild[3,1] := Scheibe6;
Scheibenbild[4,1] := Scheibe7;
Scheibenbild[5,1] := Scheibe8;
Scheibenbild[6,1] := Scheibe9;
Scheibenbild[7,1] := Scheibe10;
Scheibenbild[8,1] := Scheibe11;


end;
procedure bewegen(start,ziel:boolean);
var a,q,s:boolean;
begin

if ((start=q) and (ziel=a)) then
       begin Scheibenbild[sa[1],1].top := (408-32*sa[2]);
       Scheibenbild[sa[1],1].left := Scheibenbild[sa[1],1].left+184;
       sa[1]:=sa[1]-1;
       sa[2]:=sa[2]+1;
       end;

if (start=q) and (ziel=s) then
       begin Scheibenbild[sa[1],1].top := (408-32*sa[3]);
       Scheibenbild[sa[1],1].left := Scheibenbild[sa[1],1].left+184;
       sa[1]:=sa[1]-1;
       sa[3]:=sa[3]+1;
       end;

if (start=a) and (ziel=s) then
       begin Scheibenbild[sa[2],1].top := (408-32*sa[3]);
       Scheibenbild[sa[2],1].left := Scheibenbild[sa[2],1].left+184;
       sa[2]:=sa[2]-1;
       sa[3]:=sa[3]+1;
       end;

if (start=a) and (ziel=q) then
       begin Scheibenbild[sa[2],1].top := (408-32*sa[1]);
       Scheibenbild[sa[2],1].left := Scheibenbild[sa[2],1].left+184;
       sa[2]:=sa[2]-1;
       sa[1]:=sa[1]+1;
       end;

if (start=s) and (ziel=q) then
       begin Scheibenbild[sa[3],1].top := (408-32*sa[1]);
       Scheibenbild[sa[3],1].left := Scheibenbild[sa[3],1].left+184;
       sa[3]:=sa[3]-1;
       sa[1]:=sa[1]+1;
       end;

if (start=s) and (ziel=a) then
       begin Scheibenbild[sa[3],1].top := (408-32*sa[2]);
       Scheibenbild[sa[3],1].left := Scheibenbild[sa[3],1].left+184;
       sa[3]:=sa[3]-1;
       sa[2]:=sa[2]+1;
       end;

end;

tatsächlich zeigt er bei der prozedur keinen fehler mehr an, jedoch wenn ich diese mit "bewegen(q,a)" auf einem button abrufen will. Die Fehlermeldung sagt: Operator oder Simikolon fehlt.
was könnte der fehler sein? ist es falsch mit z.b. if (start=s) and (ziel=a) then anzufangen?


COMMANDER86 - Mi 17.02.10 21:46

Moin,

also ich muss gestehen, dass ich das Spiel jetzt nicht wirklich kenne, aber ich verstehe schon nicht, was Du da vorhast. ;)

1. Warum übergibst Du der Prozedur Start und Ziel als boolean?

2. In der Prozedur vergleichst Du mit den drei Variablen a, q und s in diversen Kombinationen. Das sind lokale Variablen und die Wertzuweisung habe ich nicht wirklich gefunden. Sprich: a, q und s haben immer den Default-Wert. Ohne eine Zuweisung sind die recht... sinnfrei an der Stelle. ;)

3.

user profile iconnairolf92 hat folgendes geschrieben Zum zitierten Posting springen:
tatsächlich zeigt er bei der prozedur keinen fehler mehr an, jedoch wenn ich diese mit "bewegen(q,a)" auf einem button abrufen will. Die Fehlermeldung sagt: Operator oder Simikolon fehlt.


Die Fehlermeldung kommt bei der Zeile in der Prozedur des Buttons? In dem Codeteil sehe ich nun keinen solchen Fehler. Hm...


Delphi-Quelltext
1:
2:
3:
4:
procedure Button1Click(Sender: TObject);
begin
  bewegen(True, False);
end;


Das sollte für den Aufruf ja genügen.

Zitat:
ist es falsch mit z.b. if (start=s) and (ziel=a) then anzufangen?


Nein, eigentlich nicht. Kannste halten wie ein Dachdecker. Ich sehe bloß den Sinn (s.o.) nicht in diesen Vergleichen.


nairolf92 - Do 18.02.10 00:27

die prozedur soll bewirken dass jenachdem welchen buchstaben dieser 3 ich hinschreibe eine timage scheibe von dem einen turm zum anderen bewegt werden soll. D.h. q steht für den Turm Quelle, a für abeitsbereich und s für senke. ich dachte man kann dann wenn man die prozedur aufrufen will z.b. mit "bewegen(q,s)" bewirken, dass eine scheibe von der quelle zur senke bewegt wird. und dafür reicht true und false nicht aus.
deshalb auch " if start=q and ziel=s then: damit wollte ich sagen, dass wenn der 1. buchstabe in der klammer q ist und der 2. s dann soll eine scheibe von der quelle zur senke bewegt werden.


COMMANDER86 - Do 18.02.10 01:02

Heyho,

user profile iconnairolf92 hat folgendes geschrieben Zum zitierten Posting springen:
die prozedur soll bewirken dass jenachdem welchen buchstaben dieser 3 ich hinschreibe eine timage scheibe von dem einen turm zum anderen bewegt werden soll. D.h. q steht für den Turm Quelle, a für abeitsbereich und s für senke.

also... das Spielprinzip werde ich mir mal anschauen müssen.

user profile iconnairolf92 hat folgendes geschrieben Zum zitierten Posting springen:
ich dachte man kann dann wenn man die prozedur aufrufen will z.b. mit "bewegen(q,s)" bewirken, dass eine scheibe von der quelle zur senke bewegt wird. und dafür reicht true und false nicht aus.

Okay, wie gesagt, ich habe mich mit dem Spiel an sich noch nicht beschäftigt. Boolean ist ja aber dann der falsche Datentyp; der kann nur True und False. Da Du die Prozedur ja ohnehin ausgelagert hast, würde ich hier drei Variablen übergeben: WAS muss von WO WOHIN. Die schnellste Lösung wäre es wohl, die Dinger als Strings zu übergeben. Macht den Quelltext was lesbarer, aber geht sicherlich auch schicker. Was adäquates fällt mir da ad hoc aber nicht ein.

user profile iconnairolf92 hat folgendes geschrieben Zum zitierten Posting springen:

deshalb auch " if start=q and ziel=s then: damit wollte ich sagen, dass wenn der 1. buchstabe in der klammer q ist und der 2. s dann soll eine scheibe von der quelle zur senke bewegt werden.

Wenn Du Strings als Variablen verwendet, dass kannst Du das schon fast so stehen lassen:

Delphi-Quelltext
1:
2:
if (start = 'q'and (ziel = 's'then
//...


LG
Fabian