Entwickler-Ecke
Multimedia / Grafik - Domino - Abgelegte Steine verwalten
galagher - Fr 04.06.10 15:53
Titel: Domino - Abgelegte Steine verwalten
Hallo!
Ich möchte ein Domino-Programm schreiben, habe bisher aber nur die Steine und 1 Bitmap, mit dem ich diese über das Spielfeld bewegen und um 90° drehen kann. Das Spielfeld ist ebenfalls ein Bitmap. Durch Mausklick wird der "Stein" abgelegt, indem er einfach an der aktuellen Position auf das Spielfeld-Bitmap gezeichnet wird:
Delphi-Quelltext
1:
| Board.Canvas.Draw(imgStein.Left, imgStein.Top, imgStein.Picture.Graphic); |
Ich denke, das ist recht gut und einfach gelöst so, denn abgelegte Steine werden ja nicht mehr bewegt.
Doch nun weiss ich nicht weiter: Wie merke ich mir im Programm, wo welcher Stein abgelegt wurde und wieviele Punkte er jeweils hat, damit ich weiss, wo und wie (senk- oder waagrecht) ich neue Steine anfügen kann?
Ich dachte zunächst an ein Array oder eine Liste mit Angaben wie X-, Y-Position, Anzahl der Punkte, senk- oder waagrechte Lage, so etwas in der Art. Aber ich komme nicht weiter.
Habt ihr Ideen, wie man eine einfache Steine-Verwaltung machen könnte?
Stundenplan - Fr 04.06.10 16:22
Mach einfach ein Array von einem Record:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| type TDirection = (dWaagerecht, dSenkrecht); type TDominostein = record X, Y: Integer; Points: Integer; Direction: TDirection; end;
var Dominos: array of TDominostein; |
Grüße,
Stundenplan.
galagher - Fr 04.06.10 16:58
Stundenplan hat folgendes geschrieben : |
Mach einfach ein Array von einem Record: |
Danke für deinen Tipp! Ich fürchte aber, ich weiss nicht so recht, wie ich das handhaben soll, was dort eingetragen wird und wie. Vor allem, wie ich abfragen soll, ob ein anderer Stein passt.
Im Moment habe ich keinen Plan...
Bergmann89 - Fr 04.06.10 18:07
Hey,
ich würd mir ein 2D-Array so groß wie das Spielfeld machen, un da dann sie Punkte eintragen. Und befvor du einen neuen Stein ablegst, guckst du im Array ob die 2 anliegenden Felder belegt sind, wenn ja dann musst du noch gucken ob die Zahl stimm. Wenn das auch der Fall ist, dann kannst du den Stein dort ablegen und die 2 Zahlen des Steins im Array ablegen.
MfG Bergmann
galagher - Fr 04.06.10 18:15
Bergmann89 hat folgendes geschrieben : |
ich würd mir ein 2D-Array so groß wie das Spielfeld machen, un da dann sie Punkte eintragen. |
Daran habe ich auch schon gedacht, es aber wieder verworfen, denn dabei muss das Spielfeld dem Array entsprechen, wie beim Schach, oder? Ich will nämlich Steine ablegen, wo ich will - es gibt keine Felder, die einem "Platz" im Array entsprechen würden.
Bergmann89 - Fr 04.06.10 18:19
Hey,
das geht auch. DU musst dir dann halt nur ne Prozedur schreiben, die das Array an der entsprechenden Stelle vergrößert un die Daten ggf. verschiebt. Wenn du rechts bzw. unten erweitern willst, dann is das ganz einfach, einfach die Größe des Array ändern. Wenn du oben bzw. links erweitern willst, dann musst du erst das Array vergrößern un dann die Daten nach rechts bzw. unten erschieben. So schwer is das eig gar nich ;)
MfG Bergmann
galagher - Fr 04.06.10 18:42
Bergmann89 hat folgendes geschrieben : |
das geht auch. DU musst dir dann halt nur ne Prozedur schreiben, die das Array an der entsprechenden Stelle vergrößert un die Daten ggf. verschiebt. Wenn du rechts bzw. unten erweitern willst, dann is das ganz einfach, einfach die Größe des Array ändern. Wenn du oben bzw. links erweitern willst, dann musst du erst das Array vergrößern un dann die Daten nach rechts bzw. unten erschieben. So schwer is das eig gar nich ;) |
Ich weiss nicht, wie ich das machen soll! Es ist einfach, das Image mit dem jeweiligen Stein zu platzieren, aber es ist dann ja nur noch eine Zeichnung.
Ich möchte nur ein einziges Image zum Setzen der Steine verwenden, ziehe es dann an sie richtige Position und klicke darauf, um den Stein abzulegen. Dann wird die Grafik auf das Board gezeichnet und das Stein-Image wird leer, damit man einen neuen Stein aufnehmen kann.
Ich kriege die Grafik mit dem Array im Kopf nicht zusammen. Das Array an sich ist keine grosse Sache, es muss nicht mal dynamisch erweiterbar sein, sondern nur soviele Positionen haben, wie es Steine gibt. Alles, was im Array kein Stein ist, ist eben leer. Logisch.
Ich muss, denke ich, beim Ablegen jedesmal folgende Werte hineinschreiben: X- Y-Position des Steins, waag- oder senkrecht, Punktanzahl links bzw. oben, rechts bzw. unten.
Aber:
1. Wo im Array schreibe ich das? 1. Stein, 1. Position im Array, 2. Stein, 2. Position, 3.-3., 4.-4. usw.?
2. Wie soll das Programm am Board erkennen, wo welcher Stein liegt? Es ist ja alles bloss eine Grafik ohne Koordinaten!
Bergmann89 - Fr 04.06.10 18:51
@1: rischtisch
@2: Eben weil es bloß eine Grafik ist speichert man die Daten ja im Array. Wen du es mit TDominostein machen willst, wie Stundenplan es geschriben hat, dann reicht ein eindimensionales Array, mit der Größe gleich der Anzahl der Steine. Mithilfe der Daten im Array prüfst du dann ob ein Stein abgelegt werden darf oder nicht, wenn ja legst du ihn so ab wie du das grad beschrieben hast und trägst einen neuen Stein ins Array ein. Wenn der Stein nicht passt machst du einfach nix, bzw. sagst dem User, das er da keinen Stein ablegen darf.
galagher - Fr 04.06.10 19:06
Bergmann89 hat folgendes geschrieben : |
Wen du es mit TDominostein machen willst, wie Stundenplan es geschriben hat, dann reicht ein eindimensionales Array, mit der Größe gleich der Anzahl der Steine. |
Soweit klar!
Bergmann89 hat folgendes geschrieben : |
Mithilfe der Daten im Array prüfst du dann ob ein Stein abgelegt werden darf oder nicht |
Ich kriege das nicht in meinen Kopf: Wie soll das Program wissen, ob ich den Stein an einer bestimmten Stelle ablegen darf? Ich meine, wie weiss es, welche Position im Array abgefragt werden muss?
Bergmann89 hat folgendes geschrieben : |
wenn ja legst du ihn so ab wie du das grad beschrieben hast und trägst einen neuen Stein ins Array ein. |
Wieder taucht die Frage auf: Wie weiss das Program, an welche Position im Array geschrieben werden mus? >>> :idea: Ach ja, mit dem Stein weiss es das! 15. Stein = 15. Position!
Ich glaube, ich begreife das langsam: Ist ja vollkommen wurscht, wie das grafisch aussieht und ob ein Stein Left 27, Top 88 liegt oder sonstwo! Jeder Stein repräsentiert einen Arrayplatz, und dort sind seine Werte gespeichert, und damit weiss ich als Spieler und das Programm weiss als Spieler, ob das Ablegen möglich ist oder nicht!
Bergmann89 - Fr 04.06.10 19:18
Rischtisch, und das Programm muss nich wissen, wo der Stein im Array liegt, den es prüfen muss. Das Programm prüft einfach jeden Stein^^ Wie heißt es doch so schön, der PC is SCHNELL, aber DUMM :)
so sieht das ganze dann aus:
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:
| type TDirection = (diVert, diHorz); TDomino = packed record X, Y, P1, P2: Integer; Dir: TDirection; end; TDominoArray = array of TDomino;
var DominoList: TDominoArray;
function GetDist(P1, P2: TPoint): Integer; begin result := Abs(P1.X-P2.X) + Abs(P1.Y-P2.Y); end;
function TForm1.CheckDomino(d: TDomino): Boolean; var d2: TDomino; P1, P2, P3, P4: TPoint; i: Integer; begin result := false;
P1 := Point(d.X, d.Y); if d.Dir = diVert then begin P2 := Point(d.X + 1, d.Y); end else begin P2 := Point(d.X, d.Y + 1); end;
for i := 0 to High(DominoList) do begin d2 := DominoList[i]; P3 := Point(d.X, d.Y); if d.Dir = diVert then begin P4 := Point(d.X + 1, d.Y); end else begin P4 := Point(d.X, d.Y + 1); end;
if (GetDist(P1, P3) = 0) then exit; if (GetDist(P1, P3) = 1) and (d.P1 <> d2.P1) then exit; if (GetDist(P1, P4) = 0) then exit; if (GetDist(P1, P4) = 1) and (d.P1 <> d2.P2) then exit; if (GetDist(P2, P3) = 0) then exit; if (GetDist(P2, P3) = 1) and (d.P1 <> d2.P1) then exit; if (GetDist(P2, P4) = 0) then exit; if (GetDist(P2, P4) = 1) and (d.P1 <> d2.P2) then exit; end; SetLength(DominoList, Length(DominoList) + 1); DominoList[High(DominoList)] := d; result := true end; |
ich habs nich getestet, aber eig sollte es so hin haun, wenn nich hast du n Ansatz an dem du weiter arbeiten kannst
MfG Bergmann
galagher - Fr 04.06.10 19:44
Zuerst: Vielen Dank, das hätte ich nicht hinbekommen!
Nun ja, der 1. Stein klappt ja, aber jeder weitere nicht: :(
Delphi-Quelltext
1:
| if not CheckDomino(aValue) then Caption := Caption+'NO!'; |
Die ganze Prozedur sieht so aus:
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:
| procedure TForm1.imgSteinClick(Sender: TObject); var aValue: TDomino; begin if isClick then begin aValue.X := Left; aValue.X := Top; aValue.P1 := 4; aValue.P2 := 2; aValue.Dir := diVert;
if not CheckDomino(aValue) then caption := caption+'NO!' else with (Sender as TImage) do begin Board.Canvas.Draw(Left, Top, Picture.Graphic); Picture.Bitmap := nil; end; end;
isClick := True; end; |
Bergmann89 - Fr 04.06.10 20:09
Hey,
du hast die Position des Steins ja fest im Code, da musst du Mausabhängige Koordinaten berechnen. Angenommen jder Stein is 32*64, also muss jedes Feld 32*32 sein, dann wären die FeldKoordinaten so:
Delphi-Quelltext
1: 2:
| aValue.X := Left div 32; aValue.Y := Top div 32 |
Außerdem hast du zwei mal aValue.X ;)
MfG Bergmann
galagher - Fr 04.06.10 20:40
Das Programm macht noch nicht viel, daher weise ich jetzt erstmal einfach iP1 und iP2 die Punktewerte zu. Es macht selbst noch gar nichts.
Also: Ich habe zur Zeit nur 1 Stein (3:6) im Spiel, also:
Das erste Setzen ist ok.
Dann weise ich zu:
Aber ab da klappt es schon nicht mehr.
Das BoardImage befindet sich an Left := 0, Top := 0. Die Steine sind 38x74 Pixel gross.
Das klappt auch nicht:
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:
| procedure TForm1.imgSteinClick(Sender: TObject); var aValue: TDomino; begin if isClick then begin
aValue.X := (Sender as TImage).Left div 38; aValue.Y := (Sender as TImage).Top div 38; aValue.P1 := iP1; aValue.P2 := iP2; aValue.Dir := diVert;
if not CheckDomino(aValue) then caption := caption+'NO!' else with (Sender as TImage) do begin Board.Canvas.Draw(Left, Top, Picture.Graphic); end; end;
isClick := True; end; |
Ausserdem verstehe ich immer noch nicht, wie das Programm das Array mit den Mauskooedinaten vergleichen soll, man kann doch nicht pixelgenau einen bestimmten Punkt treffen!
Bergmann89 - Sa 05.06.10 00:18
Hey,
das Programm prüft die Steine ja auch nicht pixelgenau, sondern die Variable X bzw. Y von TDomino gibt die Feldposition an. Ich bin grad bisl durcheinander, was deine Images angeht. Kannst du das Projekt mal hochladen, da guck ich mir das ma an...
€: Ich hab mir ma schnell was zusammen gebastelt. Ich denke es sollte ausreichend kommentiert sein, das du es verstehst. Wenn du trotzdem noch fragen hast, dann kannst du ja nochma schreiben.
MfG Bergmann.
galagher - Sa 05.06.10 09:28
Bergmann89 hat folgendes geschrieben : |
€: Ich hab mir ma schnell was zusammen gebastelt. |
Alle Achtung!
Ich habe es so, dass ich die Steine beliebig verschieben kann. Das klappt aber dann mit dem Array zusammen nicht.
Bergmann89 - Sa 05.06.10 17:31
Hey,
in meiner Check-Funktion war ein kleiner Fehler drin. Jetz funktioniert es soweit, das du den 6-3-Stein drehen un platzieren kannst. Überall wo ich im Code was geändert hab hab ich n Kommentar drüber geschrieben. Dann is mir noch aufgefallen, das du globale Variablen benutzt:
Delphi-Quelltext
1: 2: 3: 4: 5:
| var Form1: TForm1; isClick: Boolean; iP1, iP2: Integer; DominoList: TDominoArray; |
Die sollte man wenn möglich umgehen, die kannst du bei der private Deklaration von Form1 mit rein schreiben (wie ich es mit dem Domino gemacht hab). Und noch ein kleiner Tipp: guck dir ma den Debugger an, da kann man Schritt für Schritt den Code ausführen ( F7 bzw. F8 ), so merkt man wenn was nich stimmt. Wenn du ne Variable markierst un dann STRG+F5 drückst kannst du dir den Wert der Variable angucken. So findet man schnell und sicher Fehler ;)
MfG Bergmann
galagher - Sa 05.06.10 18:08
Hallo Bergmann89!
Bergmann89 hat folgendes geschrieben : |
Dann is mir noch aufgefallen, das du globale Variablen benutzt: Delphi-Quelltext 1: 2: 3: 4: 5:
| var Form1: TForm1; isClick: Boolean; iP1, iP2: Integer; DominoList: TDominoArray; |
Die sollte man wenn möglich umgehen, die kannst du bei der private Deklaration von Form1 mit rein schreiben (wie ich es mit dem Domino gemacht hab). |
Das wusste ich nicht! Dass man globale Variablen vermeiden sollte, weiss ich, aber warum, weiss ich nicht! Was ist der Unterschied?
Bergmann89 hat folgendes geschrieben : |
Wenn du ne Variable markierst un dann STRG+F5 drückst kannst du dir den Wert der Variable angucken. So findet man schnell und sicher Fehler ;) |
STRG+F5 wusste ich auch nicht!
Ich werd's mir anschauen! Danke für deine Geduld und Hilfe!
Grafische Programme - also Spiele - liegen mir offenbar nicht so. Ich hab's mir einfacher vorgestellt. War nahe daran, das Projekt aufzugeben, ich habe z.B. noch keine Ahnung, wie ich das Programm spielen lasse; da gibt es noch so viel... :nixweiss: :?
Dein Code hat einen entscheidenden Vorteil: Er funktioniert! Aber leider verstehe ich ihn nicht. Also, das Prinzip schon, aber nicht so wirklich...
galagher - Sa 05.06.10 18:30
Glück auf, Bergmann!
Habe es erst jetzt getestet! Das ist ja mein Programm! Danke für die Korrektur meines Programms! So stelle ich mir das vor! (Habe zuerst die .exe ausgeführt und dann nur kurz den Sourcecode angeschaut).
Muss erst mal durch den Code durchsteigen, wird sicher etwas dauern! Aber - ja, genau so! :D
Wenn das was wird, wird sicher "bergmann89" im Info aufscheinen!
Ok, andere Steine kommen noch, aber es funktioniert!
Bergmann89 - Sa 05.06.10 18:38
Hey,
warum man globale Variablen nur ur Nt verwenden sollte weiß ich eig auch nich geanz genau^^ Warscheinlich der Übersicht halber, bzw um Ressourcen zu sparen, denn globale Variablen belegen immer Speicher, Objekt-Variablen nur dann, wenn das Objekt daszu exestiert.
Für einen Anfänger sind Spiele mit grafischen Elementen immer die nächste Herausvorderung. Aber ich weiß ja nich was du bis jetzt so alles schon gemacht hast. Dir wird es jetzt vlt schwer fallen, aber wenn du das jetzt durchziehst sollte es dich einen ganzen Schritt weiter bringen.
Oder du legst das Projekt erstmal auf Eis und probierst dich an was einfachen, um das Verständniss fürs Programmieren zu bekommen. Sowas wie Taschenrechner, Notepad-Klone, ... sind relativ einfache Programme. Danch kann man sich dann mit Hex-Editoren, kleinen Spielen oder ähnlichen beschäftigen. Und was du dir auch auf alle Fälle angucken solltest ist
DAS [
http://www.christian-stelzmann.de/artikel/crashkurs.htm] da steht das Wichtigste drin, was man über Delphi und das Porgrammieren wissen sollte. Und man kann auch immer mal nachgucken wenn man nicht weiter weiß.
So viel hab ich am Code gar nicht geändert, vlt 20 Zeilen oder so. Wenn du Fragen hast schreib einfach, dann helfen wir weiter.
MfG Bergmann.
galagher - So 06.06.10 09:17
Hallo!
Habe bis jetzt kaum Programme mit Grafik gemacht, ansonsten schon auch grössere Sachen als "nur" einen Taschenrechner (ist auch interessant gewesen)!
Bergmann89 hat folgendes geschrieben : |
Wenn du Fragen hast schreib einfach, dann helfen wir weiter. |
Naja, ist nach der ganzen Hilfe ja unverschämt - aber ich frage mal: Wie könnte das Programm als Spieler selbst einen Stein setzen? Ich möchte jetzt keinen Code, aber vielleicht ein paar Tipps oder eine Beschreibung!
Mein Gedanke: Merken, wo jeder Stein liegt, angrenzende Koordinaten errechnen und durchprobieren, ob dort ein Stein passt. Theoretisch...
F34r0fTh3D4rk - So 06.06.10 11:40
Ich sag immer:
Logik,
Daten und
Darstellung trennen. Denn was du zunächst versucht hast, war die Logik über die Darstellung zu implementieren. Das geht zwar, macht in diesem Fall aber nicht viel Sinn. Man kann Domino komplett funktionierend ohne, bzw. unabhängig von der Darstellung entwickeln und dann die Darstellung über eine Schnittstelle einbauen. So muss man, wenn man sich für eine andere Darstellungsform entscheiden sollte (3D statt 2D, text-basiert statt grafisch), nur noch den Code für die Darstellung, aber nicht die eigentliche Logik des Spiels umschreiben.
Dazu vielleicht ganz hilfreich:
Model View Controller [
http://de.wikipedia.org/wiki/Model_View_Controller] (Für Domino vielleicht etwas übertrieben, aber hier wird das Prinzip deutlich)
und:
Beobachter [
http://de.wikipedia.org/wiki/Beobachter_%28Entwurfsmuster%29]
Bergmann89 - So 06.06.10 19:03
Hey,
@F34r0fTh3D4rk: in gewisserweiße sind die Daten, Logik un Darstellung getrennt. Die Daten liegen alle in dem Array. Wenn der User eine Eingabe macht, bzw. wenn die KI einen Steni legen soll, werden die Daten im Array geändert (Logik) und zum Schulss greift die OnPaint-Methode des PaintBox auf das Array zu und zeichnet alles (Darstellung). Wozu würdest du den Observer einsetzten? Bsp.: Das der Datenbereich dem Observer sagt das sich die Daten geändert haben un der dann der Darstellung sagt, das neu gezeichnet werden muss?!
@galagher: für die KI (wenn man es so nennen kann) würd ich sowas wie nen
BruteForce [
http://de.wikipedia.org/wiki/Bruteforce] machen:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| Punkt auf 0,0 setzen (oben links) while not CheckDomino do drehe stein wenn 4 mal gedreht wurde, dan... verschiebe Position um ein Feld nach rechts wenn Position auserhalb des spielfeldes, dann... setze X-Position auf 0 setze Y-Position in die nächste Zeile |
so würde die KI die Steine immer erst versuchen oben links anzulegen. Man könnte das ganze auch auf Random umbauen, da muss man dann aber noch paar Tests einbauen, dass das auch wirklich zum Ende kommt.
MfG Bergmann
galagher - So 06.06.10 20:18
F34r0fTh3D4rk hat folgendes geschrieben : |
Ich sag immer: Logik, Daten und Darstellung trennen. |
Das versuche ich bei jedem Programm, schaffe es aber nicht immer wirklich konsequent!
@Bergmann89:
Nochmals Dank! Einen Code nach diesem Beispiel werde ich einbauen und sehen, wie weit ich komme! Die Anzahl der Möglichkeiten ist ja nicht unbegrenzt, und daher werden Anweisungen nach deinem Vorschlag sicher auch in akzeptabler Zeit ausgeführt.
jaenicke - So 06.06.10 20:29
Bergmann89 hat folgendes geschrieben : |
warum man globale Variablen nur ur Nt verwenden sollte weiß ich eig auch nich geanz genau^^ Warscheinlich der Übersicht halber, bzw um Ressourcen zu sparen, denn globale Variablen belegen immer Speicher, Objekt-Variablen nur dann, wenn das Objekt daszu exestiert. |
Damit hat das weniger zu tun, ist aber natürlich auch richtig.
Aber stell dir einmal z.B. ein dynamisch erstelltes Formular in einem Editor vor. Du erstellst davon jetzt zwei, weil zwei Dateien parallel geöffnet werden. So, jetzt schreibst du den Dateinamen aber in eine globale Variable. Davon gibt es aber nur eine. Wie willst du dadrin also zwei Dateinamen unterbringen?
Globale Variablen gehören eben nicht zu einem bestimmten Objekt, sondern zu der Unit, in der die Klasse, also der Konstruktionsplan der Objekte, steht. Dementsprechend darf man auch nicht versuchen objektbezogene Dinge darin abzulegen. Was zu einem Objekt, also einer von ggf. mehreren Instanzen der Klasse, gehört, gehört auch in die Klasse.
Das ist auch der Grund weshalb man nicht
Form1.Caption oder so schreiben sollte sondern
Self.Caption oder nur
Caption. Denn sonst greift man ggf. plötzlich auf eine falsche oder nicht existierende Instanz eines Formulars zu. Und noch öfter passiert das bei eigenen Klassen, denn bei denen gibt es natürlich sehr oft mehrere Instanzen.
Zusätzlich sind globale Variablen nicht gerade übersichtlich, sagtest du ja schon, und objektorientiert schon gar nicht.
galagher - So 06.06.10 20:53
jaenicke hat folgendes geschrieben : |
Aber stell dir einmal z.B. ein dynamisch erstelltes Formular in einem Editor vor. |
Das war einmal einer meiner Anfangsfehler - plötzlich hat dar Editor glatt unter einem falschen Dateinamen gespeichert! Hier ist es mir seitdem klar. Ansonsten ist es wohl einfach Gewohnheit oder Bequemlichkeit. :oops:
Werde künftig versuchen, ohne globale Variablen auszukommen, gleich mal im Domino-Projekt!
galagher - Mo 07.06.10 17:38
Im Moment suche noch ich den Stein für das Programm aus. Wenn er irgendwo passt, funktioniert es, wenn nicht, rechnet sich das Programm den Speicher wund:
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:
| var i, tmp: Integer; begin
Domino.X := 0; Domino.Y := 0; while not CheckDomino(Domino) do begin for i := 0 to 3 do begin if Domino.Dir = diVert then begin tmp := Domino.P1; Domino.P1 := Domino.P2; Domino.P2 := tmp; Domino.Dir := diHorz; end else Domino.Dir := diVert; end;
Inc(Domino.X);
if Domino.X > Board.Width then begin Domino.X := 0; Inc(Domino.Y); end; end;
Board.Canvas.Draw(Domino.X * iStoneWidth, Domino.Y * iStoneWidth, imgStein.Picture.Graphic); end; iStoneWidth, imgStein.Picture.Graphic); end; |
Wo ist / sind meine Fehler? Kann man aus mehreren möglichen Plätzen per Random einen auswählen? Das würde das Spiel interessanter machen.
//Edit: Es funktioniert auch dann nicht immer, wenn der Stein passt!
Bergmann89 - Di 08.06.10 00:35
Hey,
geh mal Schritt für Schritt mit dem Debuger durch. Der Sinn der Sache war ja, das abwechselnd geprüft und dann was geändert wird. Also müsste er nach jedem Drehen, einmal in den While-Kopf spingen, wo das CheckDomino steht.
Damit er die Schleife auch verlässt, wenn kein Stein passt, musst du gucken wann die Y Position außerhalb des Feldes ist und dann setzt du einfach ein break;, das beendet die Schleife.
Das mit dem random-Wert geht auch, dazu musst du nur alle Positionen des Feldes abschreiten (3 for-Schleifen: X, Y, Drehen) und gucken ob der Stein passt. wenn ja schreibst du ihn - ähnlich wie beim CheckDomino - in ein Array. Dazu musst du die CheckDomino-Funktion aber ändern, bzw. ne 2. machen, da die jetzige den Stein ja gleich hinlegt, und die neue soll ja nur gucken ob er passt. Dann hast du alle möglichen Stellen in dem Array un kannst dir eine raussuchen.
MfG Bergmann.
galagher - Di 08.06.10 17:42
Bergmann89 hat folgendes geschrieben : |
Der Sinn der Sache war ja, das abwechselnd geprüft und dann was geändert wird. Also müsste er nach jedem Drehen, einmal in den While-Kopf spingen, wo das CheckDomino steht. |
Macht der Code ja, es klappt aber nicht richtig. ZB. legt wird der Stein immer dann horizontal hingelegt, wenn
ich ihn zuvor drehe. Ist er vertikal, wird er vertikal gelegt. Passen zB. 5 Punkte, wenn diese unten sind, dann legt er den Stein nur dann ab, wenn ich ihm vorher die Punkte nach unten drehe. Irgendwie wirkt sich das Drehen nicht aus...
Bergmann89 hat folgendes geschrieben : |
Damit er die Schleife auch verlässt, wenn kein Stein passt, musst du gucken wann die Y Position außerhalb des Feldes ist und dann setzt du einfach ein break;, das beendet die Schleife. |
Ok, klar:
if Domino.Y > Board.Height then break;
Bergmann89 hat folgendes geschrieben : |
Das mit dem random-Wert geht auch |
Solange es nicht mal so klappt, ist das vorläufig egal!
Ich habe also 2 Versionen gebastelt, beide funktionieren, aber eben nur wie oben beschrieben:
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:
| Domino.X := 0; Domino.Y := 0;
repeat for i := 0 to 3 do begin if Domino.Dir = diVert then begin tmp := Domino.P1; Domino.P1 := Domino.P2; Domino.P2 := tmp; Domino.Dir := diHorz; end else Domino.Dir := diVert; end;
Inc(Domino.X);
if Domino.X > Board.Width then begin Domino.X := 0; Inc(Domino.Y); end;
until (CheckDomino(Domino)) or (Domino.Y > Board.Height);
Domino.X := 0; Domino.Y := 0;
while not CheckDomino(Domino) do begin for i := 0 to 3 do begin if Domino.Dir = diVert then begin tmp := Domino.P1; Domino.P1 := Domino.P2; Domino.P2 := tmp; Domino.Dir := diHorz; end else Domino.Dir := diVert; end;
Inc(Domino.X);
if Domino.X > Board.Width then begin Domino.X := 0; Inc(Domino.Y); end; if Domino.Y > Board.Height then break; end; |
galagher - Di 08.06.10 20:26
Jetzt funktioniert es, aber es ist langsam, weil ich das Image mitdrehen muss. Habe versucht, einen Integer t zu verwenden und den Stein vor dem Zeichnen t-Mal zu drehen, das klappt aber nicht. Also muss ich etwas finden, das den gelichen Effekt hat wie die Prozedur Drehen90Grad.
Das Programm spielt jetzt und dreht und legt die Steine richtig! :lol: :D
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:
| var i, n, t, tmp: Integer; begin
Domino.X := 0; Domino.Y := 0; n := 0; while not CheckDomino(Domino) do begin begin Drehen90Grad(imgStein.Picture.Bitmap); if Domino.Dir = diVert then begin tmp := Domino.P1; Domino.P1 := Domino.P2; Domino.P2 := tmp; Domino.Dir := diHorz; end else Domino.Dir := diVert; end;
Inc(n);
if n = 3 then begin Inc(Domino.X); n := 0; end;
if Domino.X > Board.Width then begin Domino.X := 0; Inc(Domino.Y); end; if Domino.Y > Board.Height then break; end;
Board.Canvas.Draw(Domino.X * iStoneWidth, Domino.Y * iStoneWidth, imgStein.Picture.Graphic); end; |
Das kann man aber sicher noch optimieren.
Narses - Di 08.06.10 20:49
Moin!
galagher hat folgendes geschrieben : |
Jetzt funktioniert es, aber es ist langsam, weil ich das Image mitdrehen muss. Habe versucht, einen Integer t zu verwenden und den Stein vor dem Zeichnen t-Mal zu drehen, das klappt aber nicht. Also muss ich etwas finden, das den gelichen Effekt hat wie die Prozedur Drehen90Grad. |
Naja, die Images werden ja nicht jeweils mehrere MB haben, oder? :? Einfach 4 ImageListen nehmen, für jede Himmelsrichtung eine. :nixweiss:
cu
Narses
galagher - Di 08.06.10 20:58
Narses hat folgendes geschrieben : |
Naja, die Images werden ja nicht jeweils mehrere MB haben, oder? :? Einfach 4 ImageListen nehmen, für jede Himmelsrichtung eine. :nixweiss:Narses |
Ich will nicht auch noch jeden Stein 4x im Programm haben, 1x genügt!
Elegant hat es ja
Bergmann89 in seinem Programm gelöst, da wird jeder Stein aus wenigen Bildteilen sozusagen zusammengesetzt.
Narses - Di 08.06.10 21:00
Moin!
galagher hat folgendes geschrieben : |
Ich will nicht auch noch jeden Stein 4x im Programm haben, 1x genügt! |
Du kannst ja beim Programmstart die 3 berechenbaren aus einer gespeicherten ableiten. :idea: Klar, muss man nicht 4x statisch ablegen. :nixweiss:
cu
Narses
Bergmann89 - Mi 09.06.10 13:24
Hey,
es würde auch helfen, wenn man das Zeichnen, während der Suche der passenden Stelle einfach weg lässt ;) Also nur die Daten manipulieren und am Ende zeichnen, so sollte es schnell genug sein, das der User es kaum mitbekommt. Kleinen Schönheitsfehler hab ich noch gefunden: if Domino.Y > Board.Height then break; ist nich ganz richtig, da du ja bei 0 anfängst zu Zählen muss die Schleife beendet werden, wenn die Position größer oder gleich der Feldhöhe ist...
MfG Bergmann.
galagher - Mi 09.06.10 17:52
Bergmann89 hat folgendes geschrieben : |
es würde auch helfen, wenn man das Zeichnen, während der Suche der passenden Stelle einfach weg lässt ;) Also nur die Daten manipulieren und am Ende zeichnen |
Wenn ich das Drehen während der Suche weglasse, wird der Stein falsch hingelegt! Habe schon versucht, je einen Integer für diVert und diHorz mitzählen zu lassen und danach, vor dem Zeichnen, den Stein entsprechend oft zu Drehen - klappt alles nicht. Die meisten Steine liegen dann falsch.
Bergmann89 hat folgendes geschrieben : |
if Domino.Y > Board.Height then break; ist nich ganz richtig, da du ja bei 0 anfängst zu Zählen muss die Schleife beendet werden, wenn die Position größer oder gleich der Feldhöhe ist... |
Also muss es heissen:
if Domino.Y >= Board.Height then break; und auch
if Domino.X >= Board.Width then?
Bergmann89 - Mi 09.06.10 19:07
Hey,
wieso sollte das mit dem nicht Zeichnen nicht gehen? Du hast doch, wenn die while-Schleife verlassen wird noch dein n, und das gibt an wie oft du die Image drehen musst, also einfach ne For-Schleife von 0 bis n-1 un da das Drehen90Grad rein. Danach bloß noch zeichnen. Fertig ;)
galagher hat folgendes geschrieben : |
Also muss es heissen: if Domino.Y >= Board.Height then break; und auch if Domino.X >= Board.Width then? |
rischtisch :)
MfG Bergmann.
galagher - Mi 09.06.10 19:18
Hallo!
Bergmann89 hat folgendes geschrieben : |
wieso sollte das mit dem nicht Zeichnen nicht gehen? Du hast doch, wenn die while-Schleife verlassen wird noch dein n, |
Das n wird aber nach je 4x Drehen wieder auf 0 gesetzt!
Nun möchte ich noch, dass das Programm aus mehreren Möglichkeiten eine auswählt.
Hab's jetzt so gelöst, läuft scnhell und korrekt:
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:
| while not CheckDomino(Domino) do begin if Domino.Dir = diVert then begin tmp := Domino.P1; Domino.P1 := Domino.P2; Domino.P2 := tmp; Domino.Dir := diHorz; end else begin Domino.Dir := diVert; Inc(h); end;
Inc(n);
if n = 3 then begin Inc(Domino.X); n := 0; end;
if Domino.X >= Board.Width then begin Domino.X := 0; Inc(Domino.Y); end; if Domino.Y >= Board.Height then break; end;
if Domino.Dir = diHorz then Drehen90Grad(imgStein.Picture.Bitmap); if Odd(h) then begin Drehen90Grad(imgStein.Picture.Bitmap); Drehen90Grad(imgStein.Picture.Bitmap); end;
Board.Canvas.Draw(Domino.X * iStoneWidth, Domino.Y * iStoneWidth, imgStein.Picture.Graphic);
if Domino.Dir = diHorz then Drehen90Grad(imgStein.Picture.Bitmap); |
Bergmann89 - Mi 09.06.10 19:23
Hey,
so geht das natürlich auch, aber im endeffekt is es das gleiche was ich grad gesagt hab^^ Wenn das Proggi dann eine random-Stelle auswählen soll, musst du den n eben mit speichern, wenn du dir das Array mit den möglichen Stellen zusammen bastelst. Musst du ja jetzt mit deinem h auch bloß machen.
MfG Bergmann.
galagher - Do 10.06.10 17:37
Hallo!
Bergmann89 hat folgendes geschrieben : |
Wenn das Proggi dann eine random-Stelle auswählen soll, musst du den n eben mit speichern, wenn du dir das Array mit den möglichen Stellen zusammen bastelst. |
:nixweiss: Ok, ich habe vor, die Funktion CheckDomino um einen bool'schen Parameter zu erweitern: False bedeutet, es wird der erste Platz genommen, an dem der Stein passt, True bedeutet, es werden zuerst alle Möglichkeiten gesammelt und dann mit Random eine ausgewählt.
Also soll der Aufruf so aussehen, wenn zB. der Spieler einen Stein setzt:
CheckDomino(Domino, False)
und so, wenn das Programm einen setzen soll:
CheckDomino(Domino, True)
Kannst du mir Tipps geben, was ich an CheckDomino abändern muss? Ich denke, die Prüfung der angrenzenden Steine bleibt gleich, aber ich will ja nicht sofort etwas ins Array eintragen und
True zurückgeben und damit den Stein schon ablegen, sondern erst alle Möglichkleiten erfassen, und erst dann ablegen.
Delphi-Quelltext
1: 2:
| SetLength(DominoList, Length(DominoList) + 1); DominoList[High(DominoList)] := d; |
Was muss ich hier ändern?
Bergmann89 - Do 10.06.10 17:41
Hey,
das ist eine schlechte Idee, ich würd's so machen: Das eintragen der Steine von CheckDomino in eine Extra Prozedur auslagern (z.B. PlaceDomino). dann Würd ich ne Prozedur machen, die alle Möglichkeiten durchprobiert, und wenn CheckDomino TRUE ist, dann wird ne Proezur aufgerufen, die die mögliche Position in das Array einträgt (z.B. AddPosiblePos). Am Ende kannst du dann mit random die Position bestimmten, mit PlaceDomino den Stein ablegen und mit Paint neu zeichnen...
MfG Bergmann
galagher - Do 10.06.10 19:05
Bergmann89 hat folgendes geschrieben : |
das ist eine schlechte Idee, ich würd's so machen: Das eintragen der Steine von CheckDomino in eine Extra Prozedur auslagern (z.B. PlaceDomino). |
Das war einfach! :mrgreen:
Der ganze Rest nicht.
Ja, ich verstehe, was du meinst, ist ja auch verständlich, aber wie giesse ich das in Quellcode?
Bergmann89 hat folgendes geschrieben : |
dann Würd ich ne Prozedur machen, die alle Möglichkeiten durchprobiert, und wenn CheckDomino TRUE ist, dann wird ne Proezur aufgerufen, die die mögliche Position in das Array einträgt (z.B. AddPosiblePos). |
Jedesmal, wennn CheckDomino TRUE ist, soll genau
was in
welches Array eingetragen werden?
Also: Die Prozedur, die das tut, heisst AddPosiblePos, und sie trägt wo was ein? Dieses Array kann ja nicht DominoList sein?
Bergmann89 hat folgendes geschrieben : |
Am Ende kannst du dann mit random die Position bestimmten, mit PlaceDomino den Stein ablegen und mit Paint neu zeichnen... |
So in etwa:
Delphi-Quelltext
1: 2: 3:
| i := -1; while i = -1 do i := Random(High(DominoPossiblePos)); |
Nie wieder ein Programm, bei dem auch das Programm etwas tun soll! :motz:
//Edit:
Das zB. tut gar nichts:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TForm1.CheckDominos(d: TDomino); var x, y: Integer; begin for x := 0 to Board.Width do for y := 0 to Board.Height do if CheckDomino(d) then memo1.Lines.Add('A'); end; |
Bergmann89 - Do 10.06.10 19:37
Hey,
da musst du dir ein neues Array anlegen. Die Prozedur CheckDominos würd ich umbenennen, weil man so schnell durcheinander kommt (CheckDomino <> CheckDomino
s) nenn sie doch GetAllPosiblePos, BruteFocePosition oder sowas in der Art. Am anfang leerst du das Array (Bsp.: PosiblePositionList) mit SetLength(0). Dann kommen 3 Schleifen (2 hast du ja schon richtig). Schleife für X, Schleife für Y un Schleife für Drehen. Dann probierst du alle Schleifen durch, und wenn CheckDomino = TRUE, dann wird AddPosiblePos aufgerufen. Da übergibst du einfach das Domino-Record un schreibst das wie bei dem DominoList-Array in das Array rein.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| var Domino: TDomino; für alle X-Positionen mache... X-Position von Domino ändern für alle Y-Positionen mache... Y-Position von Domino ändern für alle drehungen mache... wenn CheckDomino(Domin) dann... AddPosiblePos(Domino) drehe Domino |
dann brauchst du nur noch ein beliebiges raus suchen und zu platzieren un das ganze neu zeichnen:
Quelltext
1: 2: 3:
| Domino = suche zufälliges Domino aus der Liste der möglichen Positionen PlaceDomino(Domino) Zeichne das Feld neu |
So in etwas sollte das Funktionieren...
€:
galagher hat folgendes geschrieben : |
Nie wieder ein Programm, bei dem auch das Programm etwas tun soll! :motz: |
Das is doch aber grad der Reiz am Programmieren ;) Man brauch da nur bisl Erfahrung, und wenn du das Domino dann fertsch un auch verstanden hast, dann sollte dir das bei andern KIs, die du evtl mal programmierst leichter fallen...
MfG Bergmann
galagher - Do 10.06.10 19:54
Bergmann89 hat folgendes geschrieben : |
Das is doch aber grad der Reiz am Programmieren ;) Man brauch da nur bisl Erfahrung, und wenn du das Domino dann fertsch un auch verstanden hast, dann sollte dir das bei andern KIs, die du evtl mal programmierst leichter fallen... |
Leider fange ich immer wieder mit derartigen - grafischen - Programmen an, zulezt mit einem Mensch ärgere dich nicht, bei dem ich die Grafik, die Kegel, den Würfel, dessen Punkte, die Züge am Brett, Teile der Logik und Teile des Arrays hatte, und scheiterte an der Umsetzung im Array, weil ja jeder der 4 Spieler woanders anfängt... Alles lief mir auseinander, wurde immer komplexer und alle Ideen, die ich hatte, konnte ich letztlich nicht zusammenführen.
Ebenso hier:
http://www.delphi-forum.de/viewtopic.php?t=59658&highlight=bauernspiel
Diverse Zusatzfunktionen, die Oberfläche und Interaktion mit dem Benutzer habe ich selbst entwickelt, aber die eigentliche Logik,
das Spiel, stammt von
alzaimar.
Dennoch gebe ich hier, bei Domino, nicht auf!
@Bergmann89:
Kann aber sein, dass ich noch oft nachfrage!
galagher - Fr 11.06.10 17:26
Hallo!
Ich habe eine Prozedur geschrieben (besser: Copy & Paste), die genau dasselbe macht wie CheckDomino, nur trägt es die möglichen "Plätze" nicht in das Array DominoList, sondern in AllPlacesList ein. Dann dachte ich, braucht man doch nur einen "Platz" per Random auswählen und schon spielt das Programm flexibel.
Ok, hier meine Ergebnisse - kurz dazu: Es funktioniert nur leider nicht.
Zuerst die Prozedur, die alle Möglichkeiten finden soll:
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:
| procedure TForm1.FindAllPlaces(d: TDomino); var
d2: TDomino; P1, P2, P3, P4: TPoint; i: Integer;
contact: Boolean;
function GetDist(P1, P2: TPoint): Integer; begin result := Abs(P1.X-P2.X) + Abs(P1.Y-P2.Y); end;
begin contact := false;
P1 := Point(d.X, d.Y); if d.Dir = diHorz then begin P2 := Point(d.X + 1, d.Y); end else begin P2 := Point(d.X, d.Y + 1); end;
for i := 0 to High(AllPlacesList) do begin d2 := AllPlacesList[i]; P3 := Point(d2.X, d2.Y); if d2.Dir = diHorz then begin P4 := Point(d2.X + 1, d2.Y); end else begin P4 := Point(d2.X, d2.Y + 1); end;
if (GetDist(P1, P3) = 0) then exit; if (GetDist(P1, P3) = 1) then begin Contact := true; if (d.P1 <> d2.P1) then exit; end; if (GetDist(P1, P4) = 0) then exit; if (GetDist(P1, P4) = 1) then begin Contact := true; if (d.P1 <> d2.P2) then exit; end; if (GetDist(P2, P3) = 0) then exit; if (GetDist(P2, P3) = 1) then begin Contact := true; if (d.P2 <> d2.P1) then exit; end; if (GetDist(P2, P4) = 0) then exit; if (GetDist(P2, P4) = 1) then begin Contact := true; if (d.P2 <> d2.P2) then exit; end; end; if not contact and (Length(AllPlacesList) > 0) then exit;
SetLength(AllPlacesList, Length(AllPlacesList) + 1); AllPlacesList[High(AllPlacesList)] := d; end; |
Und das ist die Prozedur, die obiges verwendet:
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:
| procedure TForm1.Button1Click(Sender: TObject); var x, y, n, h, tmp: Integer; aBitmap: TBitmap; begin iTalon := 0;
aBitmap := TBitmap.Create;
try aBitmap.Assign(imgStein.Picture.Bitmap);
Domino.X := 0; Domino.Y := 0; n := 0; h := 0;
for x := 0 to Board.Width do for y := 0 to Board.Height do begin FindAllPlaces(Domino); if Domino.Dir = diVert then begin tmp := Domino.P1; Domino.P1 := Domino.P2; Domino.P2 := tmp; Domino.Dir := diHorz; end else begin Domino.Dir := diVert; Inc(h); end;
Inc(n);
if n = 3 then begin Inc(Domino.X); n := 0; end;
end;
if Domino.Dir = diHorz then Drehen90Grad(aBitmap); if Odd(h) then begin Drehen90Grad(aBitmap); Drehen90Grad(aBitmap); end;
Domino := AllPlacesList[Random(High(AllPlacesList))]; Board.Canvas.Draw(Domino.X * iStoneWidth, Domino.Y * iStoneWidth, aBitmap);
finally aBitmap.Free; end; end; |
Dabei hängt das Programm, oder es rechnet eben solange. Es klappt einfach nicht, aber es sollte doch? 1. Finde alle Möglichkeiten, 2. wähle eine aus. Was ist da falsch?
//Edit:
Mir ist klar, dass in dem Programm diverser Coder mehrfach vorkommt, ich sollte dies natürlich alles vereinfachen, aber im Moment ist mir das egal, solange es nur läuft!
---
Moderiert von
Narses: Beiträge zusammengefasst---
Beim Prüfen der umgebenden Steine muss ich DominoList verwenden, nicht AllPlacesList. Jetzt hängt das Programm zwar nicht mehr, setzt aber die meisten Steine irgendwo, teilweise auf einen bereits abgelegten Stein drauf.
Wenn ich statt Random den 1. Array-Eintrag verwende -
Domino := AllPlacesList[0] - legt er jeden Stein immer an der selben Position ab - übereinander.
Ich blicke da nicht durch. :(
Bergmann89 - Sa 12.06.10 02:35
Hey,
mach es mal so wie ich gesagt hab un teil den Code mal in die Prozeduren und Funktionen auf, dann kann man auch den Überblick behalten. Was du da ganz unten in dem Button machst, da blick ich nämlich auch nich mehr durch :?
Also:
Funktion, die prüft, ob ein Stein da abgelegt werden kann oder nicht (Bsp.: CheckDomino)
Prozedur, die das Array mit den möglichen Positionen neu füllt (Bsp.: FindAllPosiblePlaces)
Prozedur, die das Domino in der Liste der Möglichen Positionen ablegt (Bsp.: AddToPosiblePlaces)
Prozedur, die einen Domino ablegt (Bsp.: PlaceDomino)
Prozedur, die das Domino (ohne Image) dreht (Bsp.: RotateDomino)
So is der Überblick besser un du hast aussagekräftige Namen für die Prodezuren/Funktionen. Dein FindAllPlaces müsste eig. CheckDomino heißen, weil es ja gar keine Plätze sucht, sondern nur überprüft!
Bei der Suche sind die Schleifen X und Y dazu gedacht die Position vom Domino durchzuzählen, also musst du der Position vom Domino auch die Werte der Schleife zuweisen, sonst passiert gar nix. Guck dir nochma den PseudoCode aus meinem Letzten Beitrag an.
Das Drehen passiert mithilfe einer 3. Schleife in den 2 ersten Schleifen, die von 0 bis 3 geht. Damit du weißt, wie oft du die Image drehen musst, musst du dein TDomino noch um einen Wert erweitern, meinetwegen ImgRotate oder so. Das ImgRotate musst du natürlich auch den aktuekllen Wert der Schleife geben.
Wenn CheckDomino mit den aktuellen Werten dann TRUE ist, legst du mit AddToPosiblePlaces den Stein im Array ab, in dem du später die Position per Zufall raus suchst.
Wenn du dann dein Domino per Zufall aus dem Array raus gesucht hast, drehst du die Image mit ner Schleife so oft, wie ImgRotate es dir vorgibt und dann legst du das Domino ab (PlaceDomino).
MfG Bergmann.
galagher - Sa 12.06.10 09:00
Hallo!
Ich verstehe nicht, warum mein Ansatz nicht funktioniert.
Bergmann89 hat folgendes geschrieben : |
Funktion, die prüft, ob ein Stein da abgelegt werden kann oder nicht (Bsp.: CheckDomino) |
Also wie CheckDomino, aber mit einem anderen Array und ohne den Aufruf PlaceDomino?
Bergmann89 hat folgendes geschrieben : |
Prozedur, die das Array mit den möglichen Positionen neu füllt (Bsp.: FindAllPosiblePlaces) |
Das macht CheckDomino doch schon mit PlaceDomino: :gruebel:
Delphi-Quelltext
1: 2: 3: 4: 5:
| procedure TForm1.PlaceDomino(d: TDomino); begin SetLength(DominoList, Length(DominoList) + 1); DominoList[High(DominoList)] := d; end; |
Bergmann89 hat folgendes geschrieben : |
Prozedur, die das Domino in der Liste der Möglichen Positionen ablegt (Bsp.: AddToPosiblePlaces) |
Das verstehe ich leider absolut gar nicht... In ein Array? Das tut doch PlaceDomino auch?
Bergmann89 hat folgendes geschrieben : |
Prozedur, die einen Domino ablegt (Bsp.: PlaceDomino) |
Das verstehe ich wieder! Wie PlaceDomino, aber in ein anderes Array.
Bergmann89 hat folgendes geschrieben : |
Prozedur, die das Domino (ohne Image) dreht (Bsp.: RotateDomino) |
Also einfach dieses als eingene Prozedur schreiben und dann einfach nur die Prozedur aufrufen?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| if Domino.Dir = diVert then begin tmp := Domino.P1; Domino.P1 := Domino.P2; Domino.P2 := tmp; Domino.Dir := diHorz; end else Domino.Dir := diVert; |
Bergmann89 hat folgendes geschrieben : |
Dein FindAllPlaces müsste eig. CheckDomino heißen, weil es ja gar keine Plätze sucht, sondern nur überprüft! |
Das füllt doch aber ein Array, und zwar immer dann, wenn ein Stein passt?
--- Ok, ich werde sehen, wie weit ich komme.
---
Moderiert von
Narses: Beiträge zusammengefasst---
Hallo!
Ok, ich war nicht faul und habe folgendes gebastelt:
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:
| var DominoList, DominoPossibleList: TDominoArray;
function TForm1.Check_if_DominoPossible(d: TDomino): Boolean; var
d2: TDomino; P1, P2, P3, P4: TPoint; i: Integer;
contact: Boolean;
function GetDist(P1, P2: TPoint): Integer; begin result := Abs(P1.X-P2.X) + Abs(P1.Y-P2.Y); end;
begin result := false; contact := false;
P1 := Point(d.X, d.Y); if d.Dir = diHorz then begin P2 := Point(d.X + 1, d.Y); end else begin P2 := Point(d.X, d.Y + 1); end;
for i := 0 to High(DominoList) do begin d2 := DominoList[i]; P3 := Point(d2.X, d2.Y); if d2.Dir = diHorz then begin P4 := Point(d2.X + 1, d2.Y); end else begin P4 := Point(d2.X, d2.Y + 1); end;
if (GetDist(P1, P3) = 0) then exit; if (GetDist(P1, P3) = 1) then begin Contact := true; if (d.P1 <> d2.P1) then exit; end; if (GetDist(P1, P4) = 0) then exit; if (GetDist(P1, P4) = 1) then begin Contact := true; if (d.P1 <> d2.P2) then exit; end; if (GetDist(P2, P3) = 0) then exit; if (GetDist(P2, P3) = 1) then begin Contact := true; if (d.P2 <> d2.P1) then exit; end; if (GetDist(P2, P4) = 0) then exit; if (GetDist(P2, P4) = 1) then begin Contact := true; if (d.P2 <> d2.P2) then exit; end; end; if not contact and (Length(DominoList) > 0) then exit;
result := True; end;
procedure TForm1.FindAllPosiblePlaces; begin end;
procedure TForm1.PlacePossibleDomino(d: TDomino); begin SetLength(DominoPossibleList, Length(DominoPossibleList) + 1); DominoPossibleList[High(DominoPossibleList)] := d; end;
procedure TForm1.RotateDomino(var d: TDomino); var tmp: Integer; begin with d do if Dir = diVert then begin tmp := P1; P1 := P2; P2 := tmp; Dir := diHorz; end else Dir := diVert; end; |
Das ist alles. Ich habe keine Ahnung, was ich sonst noch tun soll...
@
Bergmann89
Ich stecke hier fest, habe aber Verständnis, dass du mir (oder sonst jemand) den Code nicht als Fertiggericht servierst. Ich möchte ja auch selber kochen, aber hier bin ich echt überfordert!
Bergmann89 - Sa 12.06.10 15:50
Hey,
langsam wirds, aber bisl was hast du noch verdreht. Dein PlacePossibleDomino ist die Prozedur, die ein Domino in der Liste der möglichen Positionen ablegt, die hieß bei mir AddToPosibilePlaces. PlaceDomino war dazu gedacht das Domino auf dem Feld, also im DominoList-Array abzulegen. Bei FindAllPosiblePlaces soll das Proggi alle Stellen des Feldes durchgehen, dazu 3 Schleifen (siehe letzer und vorletzter Beitrag von mir). Du musst auch drauf achten was wir schreiben, kahm schon vieles doppelt. Da hilft es immer, wenn man sich sowas wie ne To-Do-Liste anlegt, wo man alles rein schreibt was hier genannt wurde. Un dann kann man das systematisch abarbeiten ;)
Ma noch ne Frage nebenbei: Wie gut bist du in Englisch? Ich hab so das Gefühl, das du mit den englischen Prozedurnamen bisl durcheinander kommst. (Vlt sollt ich die in Zukunft deutsch machen) :)
MfG Bergmann.
galagher - Sa 12.06.10 16:28
Hallo!
Bergmann89 hat folgendes geschrieben : |
Dein PlacePossibleDomino ist die Prozedur, die ein Domino in der Liste der möglichen Positionen ablegt, |
Naja - das soll es ja auch, oder? PlacePossibleDomino = "platziere mögliches Domino" - es platziert alle Möglichkeiten im Array, je einen pro Aufruf!? Genau wie PlaceDomino, nur in ein anderes Array.
Also der Reihe nach, das soll mein Programm tun:
1. Check_if_DominoPossible - Funktion, die prüft, ob ein Stein da abgelegt werden kann oder nicht (Bsp.: CheckDomino)
2. Prozedur, die das Array mit den möglichen Positionen neu füllt (Bsp.: FindAllPosiblePlaces - hier weiss ich nicht, wie diese Prozedur aussehen soll. Was ist hier zu tun?
3. Prozedur, die das Domino in der Liste der Möglichen Positionen ablegt (Bsp.: AddToPossiblePlaces) - Was ist hier zu tun? Was, wo und wie? (Ich weiss, dass das "füge zu möglichen Plätzen hinzu" bedeutet. :mrgreen: )
4. PlaceDomino - Prozedur, die einen Domino ablegt - Habe ich. Funktioniert.
5. RotateDomino - Prozedur, die das Domino (ohne Image) dreht - Habe ich auch und funktioniert auch.
Bergmann89 hat folgendes geschrieben : |
Ich hab so das Gefühl, das du mit den englischen Prozedurnamen bisl durcheinander kommst. |
Eher mit dem Inhalt der Prozeduren! Soweit reicht mein Englisch schon! Aber mittlerweile habe ich keinen Plan, keinen Ansatz, wie ich das zum Laufen bringe. Ich meine, es steht da als Code, aber es wird nie genutzt. Das Programm kompiliert und spielt, aber eben nur "ich lege am erstmöglichen Platz ab".
Das habe ich bereits:
Ich habe ein Array, das prüft, welcher Stein schon entnommen wurde - klappt. Daher erkennt das Programm auch, dass der letze Stein weg ist - klappt. Wechsel Spieler/Proggi - klappt. Und dass das Programm etwas Sinnvolles tut, wenn keine Steine mehr da sind, kriege ich auch hin. Und dass es das Spiel beginnt, auch - nur ist das zur Zeit eben eher langweilig, wenn es den 1. Stein
immer links oben ablegt. Klar, kann ja nicht anders - das ist der erste mögliche Platz.
Ich weiss einfach nicht, wie ich was wo mache! Nein, theoretisch schon, hast du ja beschrieben, aber ich kann's nicht umsetzen. :nixweiss: :cry:
Bergmann89 - Sa 12.06.10 19:14
Hey,
guck ma
HIER [
http://www.delphi-forum.de/viewtopic.php?p=608346#608346]. Da is sogar schon schöner PseudoCode, den man umsetzen kann. Das is jetzt das 3. ma das ich dir sag, das du das angucken sollst. Das is nämlich genau das, was die FindAllPlaces-Methodem machen soll. Wenn ich's jetzt noch ausführlicher hin schreib hast du Code da stehen. Und einfach 1 zu 1 kopieren bringt ja nix (haste ja auch schon festgestellt). Eig hast du alles was du zum lösen brauchst auf dieser Seite des Themas. Noch ein Kleiner Tipp, da das Ganze ja grad ziemlich durcheinander is. Kopier dir dein Projekt in einen Seperaten Ordner, lösch alles was mit dem Ablegen der Dominos, oder iwie mit der KI zu tun hat un schreib es neu. Zur Hilfe kannst du in den Alten Code, oder hier ins Forum gucken. Les dir nochma alle Beiträge genau durch, es steht eig. ausführlich genug da, was du machen musst ;)
MfG Bergmann.
galagher - So 13.06.10 08:24
Guten Morgen!
Jetzt endlich habe ich es, aber es ist wieder langsamer geworden. Ich habe ein Array DominoPossibleList zur Aufnahme der möglichen Plätze hinzugefügt und TDomino um den Integer Rotate erweitert, der die Anzahl der Drehungen enthält. :dance2:
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:
| var DominoList, DominoPossibleList: TDominoArray;
procedure TForm1.FindAllPossiblePlaces(d: TDomino); var
d2: TDomino; P1, P2, P3, P4: TPoint; i: Integer;
contact: Boolean;
function GetDist(P1, P2: TPoint): Integer; begin result := Abs(P1.X-P2.X) + Abs(P1.Y-P2.Y); end;
begin contact := false;
P1 := Point(d.X, d.Y); if d.Dir = diHorz then begin P2 := Point(d.X + 1, d.Y); end else begin P2 := Point(d.X, d.Y + 1); end;
for i := 0 to High(DominoList) do begin d2 := DominoList[i]; P3 := Point(d2.X, d2.Y); if d2.Dir = diHorz then begin P4 := Point(d2.X + 1, d2.Y); end else begin P4 := Point(d2.X, d2.Y + 1); end;
if (GetDist(P1, P3) = 0) then exit; if (GetDist(P1, P3) = 1) then begin Contact := true; if (d.P1 <> d2.P1) then exit; end; if (GetDist(P1, P4) = 0) then exit; if (GetDist(P1, P4) = 1) then begin Contact := true; if (d.P1 <> d2.P2) then exit; end; if (GetDist(P2, P3) = 0) then exit; if (GetDist(P2, P3) = 1) then begin Contact := true; if (d.P2 <> d2.P1) then exit; end; if (GetDist(P2, P4) = 0) then exit; if (GetDist(P2, P4) = 1) then begin Contact := true; if (d.P2 <> d2.P2) then exit; end; end; if not contact and (Length(DominoList) > 0) then exit;
SetLength(DominoPossibleList, Length(DominoPossibleList) + 1); DominoPossibleList[High(DominoPossibleList)] := d; end;
procedure TForm1.Button1Click(Sender: TObject); var x, y, n, h: Integer; aBitmap: TBitmap; begin aBitmap := TBitmap.Create;
try aBitmap.Assign(imgStein.Picture.Bitmap);
Domino.X := 0; Domino.Y := 0; Domino.Rotate := 0; n := 0; h := 0;
SetLength(DominoPossibleList, 0);
for x := 0 to Board.Width do for y := 0 to Board.Height do begin FindAllPossiblePlaces(Domino);
RotateDomino(Domino);
Inc(h); Domino.Rotate := h;
Inc(n);
if n = 3 then begin Inc(Domino.X); n := 0; end;
if Domino.X >= Board.Width then begin Domino.X := 0; Inc(Domino.Y); end;
if Domino.Y >= Board.Height then break; end;
caption:=inttostr(High(DominoPossibleList)); if High(DominoPossibleList) < 0 then exit;
Domino := DominoPossibleList[Random(High(DominoPossibleList))];
if (Domino.Rotate <> 4) then for n := 0 to Domino.Rotate-1 do Drehen90Grad(aBitmap);
CheckDomino(Domino);
DrawStone(aBitmap);
finally aBitmap.Free; end; end; |
@
Bergmann89
Ist zwar nicht so, wie du es gemeint hast, da blicke ich wirklich nicht durch! So funktioniert es jedenfalls, ich weiss nur nicht, warum es wieder langsamer ist. Kann man vielleicht noch optimieren.
//Edit: @
Bergmann89 - Danke dir für deine vielen Tipps!
//Edit:
Jetzt verstehe ich auch "AddToPossiblePlaces" und "FindAllPossiblePlaces"! - Und genau so oder zumindest sehr ähnlich habe ich es eingebaut - der Rest ist Oberfläche und Drumherum!
galagher - Mi 16.06.10 22:17
Hallo!
Jetzt habe ich ein neues Problem: Wie verhindere ich, dass Steine "abgeschnitten" abgelegt werden können? Keiner meiner Ansätze waren wirklich erfolgreich, zB. klappt dieses nur sehr bedingt - das Programm hält sich nicht dran:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| function TForm1.CheckDomino(d: TDomino): Boolean; begin
if d.Dir = diVert then begin if d.X*iStoneWidth+iStoneHeight > Board.Width then exit; if d.Y*iStoneWidth+iStoneHeight+iStoneWidth > Board.Height then exit; end else begin if d.X*iStoneWidth+iStoneHeight+iStoneWidth > Board.Width then exit; if d.Y*iStoneWidth+iStoneHeight > Board.Height then exit; end;
SetLength(DominoList, Length(DominoList) + 1); DominoList[High(DominoList)] := d;
result := True; |
Das Bild im Anhang zeigt, was ich meine! Kann mir bei der Lösung dieses Problems jemand helfen?
Bergmann89 - Mi 16.06.10 22:23
Hey,
setz einfach deine Spielfeldgröße auf ein Vielfaches von 32 (bzw. auf ein Vielfaches der DominoBreite), das sollte das Problem lösen...
MfG Bergmann
galagher - Mi 16.06.10 22:57
Bergmann89 hat folgendes geschrieben : |
setz einfach deine Spielfeldgröße auf ein Vielfaches von 32 (bzw. auf ein Vielfaches der DominoBreite), das sollte das Problem lösen... |
Meinst du die Breite und Höhe des Spielfeld-Images? Das habe ich derzeit so:
Board.SetBounds(0, 0, 600, 600); Genau, wie ich es brauche. Wenn ich nun statt 600 wesentlich höhere Werte nehme, wird das an sich transparente Image weiss (?), wenn das Programm seinen Stein berechnet!
Ausserdem brauche ich rechts neben dem Spielfeld einen freien Platz, weil ich dort noch ein paar Buttons unterbringen möchte.
//Edit: Verstehe - multiplizieren! Denke, jetzt hab ich's! Danke! :wink:
galagher - Do 17.06.10 21:36
galagher hat folgendes geschrieben : |
//Edit: Verstehe - multiplizieren! Denke, jetzt hab ich's! Danke! :wink: |
Das löst das Problem leider nicht oder ich habe die Lösung nicht verstanden. Ich dachte, wenn ich eine Spielfeldhöhe und -breite wähle, die zB. 15x die Breite der Steine hat, klappt es.
Jeder Stein hat 38 Pixel Breite, also mit zB. 15 multiplizieren, dann hat das Spielfeld 570x570 Pixel und die Steine passen so hinein, dass rechts und unten nichts abgeschnitten wird. Wenn das Programm aber nun einen Stein passend ablegt, dann manchmal auch so, dass entweder eine Hälfte sichtbar ist und die andere nicht mehr auf das Board gezeichnet wird, weil sie ausserhalb ist, oder der ganze Stein nicht im Board ist (im Array schon, nur eben grafisch nicht!).
Ich weiss nicht, wie ich das lösen kann. Die angehängte Grafik zeigt, was ich meine. Der rote Rahmen ist ein Shape.
Bergmann89 - Do 17.06.10 22:11
Hey,
guck dir ma die Prozedur an, die die möglichen Positionen durchzäht. Da hast du doch ne Abfrage drin, wann er nen "Zeilenumbruch" machen soll, und wann er letztendlich komplett aufhören soll. Oder du hast es mittlerweile über die for-Schleifen gemacht, weiß ich nich mehr. Und da änderst du die Werte einfach, das er nich mehr so weit nach außen und unten läuft...
MfG Bergmann.
galagher - Fr 18.06.10 17:12
Hallo!
Die Prozedur FindAllPossiblePlaces durchläuft eine for-Schleife, und das hier sollte sein, was du meinst:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| if d.X >= Board.Width then begin d.X := 0; Inc(d.Y); end;
if d.Y >= Board.Height then break; |
...funktioniert aber nicht, und auch Konstrukte, die die Breite der Steine (38 Pixel) addieren, wie zB.
if d.X+38 >= Board.Width then funktionieren nicht.
Hier die ganze Prozedur:
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:
| function TForm1.FindAllPossiblePlaces(d: TDomino): Integer; var x, y, n, h: Integer; begin d.X := 0; d.Y := 0; d.Rotate := 0; n := 0; h := 0; SetLength(DominoPossibleList, 0);
for x := 0 to Board.Width do for y := 0 to Board.Height do begin AddToPossiblePlaces(d);
RotateDomino(d);
Inc(h); d.Rotate := h;
Inc(n);
if n = 3 then begin Inc(d.X); n := 0; end;
if d.X >= Board.Width then begin d.X := 0; Inc(d.Y); end;
if d.Y >= Board.Height then break; end;
Result := High(DominoPossibleList); end; |
//Edit:
Schlimmer noch: Offenbar ist das Spielfeld rechts (und wahrscheinlich auch unten) unbegrenzt! Siehe Grafik!
Bergmann89 - Fr 18.06.10 19:16
Hey,
die Psoition des Dominos (d.X bzw. d.Y) ist in RasterKoordinaten, also in Abhängikeit der Breite ( 38 ). Um auf die FeldKoordinaten umzurechnen musst du mit 38 Multiplizieren, dann stimmt auich die IF-Abfrage. Das ganze kannst du die aber sparen, den du hast ja die Schleifen, die die Position weiter zählen, also einfach am Anfang der beiden Schleifen die Position des Dominos festlegen. Und danach dann eine Schlefe (0-3) die die Drehungen zählt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| for x := 0 to (Board.Width div 38)-1 do begin for y := 0 to (Board.Height div 38)-1 do begin d.X := 38 * x; d.Y := 38 * y; for n := 0 to 3 do begin d.Rotate := n; AddToPossiblePlaces(d); RotateDomino(d); end; end; end; |
MfG Bergmann
galagher - Sa 19.06.10 08:55
Hallo!
Vielen Dank, aber leider funktioniert das nicht. Es werden nun überhaupt keine Steine mehr abgelegt. Habe erst versucht, deinen Code in mein Programm einzubauen - klappt nicht. Dann ihn 1:1 zu übernehmen - klappt nicht. :(
//Edit:
Das scheint zu funktionieren, aber ehrlich gesagt, weiss ich nicht, warum! Ich habe es einfach ausprobiert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| for x := 0 to Board.Width do for y := 0 to Board.Height do begin if (d.X*38 < Board.Width-38) and (d.Y*38 < Board.Height-38) then AddToPossiblePlaces(d);
if d.X >= Board.Width-1 then begin d.X := 0; Inc(d.Y); end;
if d.Y >= Board.Height-1 then break; |
galagher - Mo 21.06.10 20:05
Hallo!
Ok, nächstes Problem:
Zuerst: Es gibt einen gemeinsamen Talon, aus dem beide Spieler (Mensch und Programm) Steine entnehmen (Random).
Ich habe das Spiel jetzt auf 66 Steine erweitert; klappt soweit alles. Ich habe zur Gewinner-Ermittlung einfach für den Spieler und das Programm je einen Integer als Zähler, der pro abgelegtem Stein um 1 erhöht wird. Wer am Ende des Spiels (=wenn alle Steine abgelegt sind), die höhere Zahl hat, ist Sieger. So weit, so klar.
Nur - wie ermittle ich den Gewinner, wenn eine verbleibende Anzahl an Steinen nirgendwo mehr passt? Ich hatte bei 66 Steinen, 608x608 Pixel Spielfeldgrösse und 38x74 Pixle pro Stein schon mehr als 3 "Rest"steine, die nirgendwo mehr passten.
Das Programm ist dzt. so, dass es erkennt, wenn ein Stein nirgendwo passt, und entsprechende Meldungen ausgibt: "Ich kann nicht ablegen, Sie sind dran" bzw. "Sie können nicht ablegen, ich bin dran".
Wohin das am Spielende führt, ist absehbar: Zu einem endlosen Hin und Her:
Das Programm entnimmt einen der verbliebenen Steine aus dem Talon (hier ist bereits gewiss, dass keiner der verbliebenen Steine mehr passt, nur weiss das Programm das eben nicht!) und sagt: "Ich kann nicht - daher du" - dann nimmt der Spieler einen neuen Stein. Das Programm erkennt, dass der nirgends passt, und sagt: "Du kannst nicht, daher ich", nimmt seinerseits einen Stein, der nirgends passt, und sagt: "Ich kann nicht - daher du" -
"Du kannst nicht, daher ich" - "Ich kann nicht - daher du" - "Du kannst nicht, daher ich" - usw. Das würde ewig so weitergehen.
Kurz: An welcher Stelle prüfe ich - und wie prüfe ich - alle verbliebenen Steine auf "Passen"? So in der Art:
if KeinSteinPasstIrgendwo then ?
Den Rest habe ich: Der Gewinner steht dann anhand seines Zählers fest!
F34r0fTh3D4rk - Mo 21.06.10 23:16
Wie prüfst du denn jetzt, ob ein Spieler nicht mehr setzen kann? Das sollte sich doch problemlos auf "prüfen, ob kein Spieler mehr setzen kann" erweitern lassen.
Bergmann89 - Di 22.06.10 10:41
Hey,
Quelltext
1: 2: 3: 4: 5: 6: 7:
| für alle verbleibenden Steine, mache... wenn Stein abgelegt werden kann (CheckDomino, ohne ablegen!), dann... erhöhe Zähler um 1
wenn Zähler gleich null, dann... Textausgabe: "Kein Stein kann mehr abgelegt werden" Spielende |
Das solltest du mit den Funktionen die du bereits hast kein Problem sein ;)
MfG Bergmannn
galagher - Mi 23.06.10 17:34
F34r0fTh3D4rk hat folgendes geschrieben : |
Wie prüfst du denn jetzt, ob ein Spieler nicht mehr setzen kann? |
Bergmann89 hat folgendes geschrieben : |
Quelltext 1: 2: 3: 4: 5: 6: 7:
| für alle verbleibenden Steine, mache... wenn Stein abgelegt werden kann (CheckDomino, ohne ablegen!), dann... erhöhe Zähler um 1
wenn Zähler gleich null, dann... Textausgabe: "Kein Stein kann mehr abgelegt werden" Spielende | |
Genau so!
Eigentlich logisch, man braucht keinen eigenen, extra geschriebenen Code dafür! Was ich mit
einem Stein mache, muss ich doch bloss in einer Schleife mit allen Steinen machen! :dance2:
Danke euch!
galagher - Mo 28.06.10 17:24
jaenicke hat folgendes geschrieben : |
Globale Variablen gehören eben nicht zu einem bestimmten Objekt, sondern zu der Unit, in der die Klasse, also der Konstruktionsplan der Objekte, steht. |
jaenicke hat folgendes geschrieben : |
Zusätzlich sind globale Variablen nicht gerade übersichtlich, sagtest du ja schon, und objektorientiert schon gar nicht. |
Stimmt ja alles, nur jetzt möchte ich in einer anderen Unit (Unit2) den Spieler ermitteln, der den 1. Stein legen darf: Wer (Programm oder Mensch) den Stein mit insgesamt mehr Punkten hat, beginnt. Und schon muss zumindest TDomino eine globale Variable sein, denn wenn das im private-Teil von Unit1 steht, kann ich es ja on einer anderen Unit nicht nutzen!
Wie macht man es also?
galagher - Di 29.06.10 19:40
Hallo!
@
Bergmann89:
Würdest du eher
a) jedem Spieler (Mensch/Programm) am Spielbeginn per Random bestimmte Steine, d. h. ein eigenes Array zuweisen, oder
b) mit einem gemeinsamen Array arbeiten, aus dem jeder Spieler jeweils einen Stein entnimmt?
Diese Frage ist mir enorm wichtig, denn momentan arbeitet das Programm mit nur einem Steine-Array!
Bergmann89 - Mi 30.06.10 15:51
Hey,
eig is das doch egal, oder? Kann man so oder so machen. Wenn du es jetzt schon mit einem Array für alle hast dann lass es so, kannst ja später noch als Option einbauen, das jeder sein eigenes hat...
MfG Bergmann
galagher - Mi 30.06.10 18:13
Bergmann89 hat folgendes geschrieben : |
eig is das doch egal, oder? |
Ich weiss nicht, ob es egal ist, denn jetzt stehen beiden Spieler alle Steine zur Verfügung, dann aber hat jeder Spieler nur seine Steine. Ich weiss nicht, was besser ist!
galagher - So 04.07.10 14:15
Hallo!
Es muss doch möglich sein, mit dem Array DominoList alle bisher abgelegten Steine neu zu zeichnen. Man soll während des Spiels eine andere Farbe einstellen können, dies übermalt aber alle abgelegten Steine. Also muss ich sie neu zeichnen. Dazu muss ich zwar noch einen Integer einbauen, der das Bitmap angibt, das gezeichnet werden muss, aber daran scheitert es nicht.
Das funktioniert nicht:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| var i, n: Integer; bmp: TBitmap; begin bmp := TBitmap.Create;
for i := 0 to High(DominoList) do begin Domino := DominoList[i];
ImageList1.GetBitmap(0, bmp); for n := 0 to Domino.Rotate do Drehen90Grad(bmp);
DrawStone(bmp); end;
bmp.Free; end; |
Was mache ich falsch?
//Edit:
Im Prinzip nichts, habe nur vergessen, den Zähler für's Drehen nach 4x auf 0 zurückzusetzen und kam dabei auf mehrere tausend Mal Drehen, was das Programm natürlich einige Zeit beschäftigte und es dadurch auf nichts mehr reagierte!
galagher - Mo 05.07.10 17:47
Hallo!
Es gibt doch noch ein Problem: Ich kriege die Berechnung des rechten bzw. unteren Randes nicht hin. Entweder setzt das Programm Steine auch ausserhalb des Spielfeldes, oder es erkennt weder für sich noch für mich einen Stein als passend, wenn dieser zB. ganz rechts angefügt werden muss.
Mit folgendem Code passiert das:
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:
| function TForm1.FindAllPossiblePlaces(d: TDomino): Integer; var x, y, n, h: Integer; begin d.X := 0; d.Y := 0; d.Rotate := 0; n := 0; h := 0; SetLength(DominoPossibleList, 0);
for x := 0 to iBoardWidth do for y := 0 to iBoardHeight do begin
if (d.X*iStoneWidth < iBoardWidth-iStoneWidth) and (d.Y*iStoneWidth < iBoardHeight-iStoneWidth) then AddToPossiblePlaces(d);
RotateDomino(d);
if h >= 4 then h := 0;
Inc(h); d.Rotate := h;
Inc(n);
if n = 3 then begin Inc(d.X); n := 0; end;
if d.X >= iBoardWidth-1 then begin d.X := 0; Inc(d.Y); end;
if d.Y >= iBoardHeight-1 then break; end;
Result := High(DominoPossibleList); end; |
Die Grafik verdeutlicht nochmal, was ich meine!
galagher - Mi 07.07.10 19:36
Hallo!
Das Programm ist mittlerweile so komplex geworden, dass eine einfache Antwort nicht so schnell möglich ist,
aber ich war ja nicht faul und habe *gedacht* und auch probiert und siehe da: :dance2:
Ich denke, das ist es jetzt:
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:
| function TForm1.FindAllPossiblePlaces(d: TDomino): Integer; var x, y, n, h: Integer; b: Boolean; begin d.X := 0; d.Y := 0; d.Rotate := 0; n := 0; h := 0; SetLength(DominoPossibleList, 0);
for x := 0 to iBoardWidth do for y := 0 to iBoardHeight do begin if (d.X*iStoneWidth < iBoardWidth) and (d.Y*iStoneWidth < iBoardHeight) then begin b := True;
if (d.X*iStoneWidth+iStoneWidth = iBoardWidth) and (d.Dir = diHorz) then b := False;
if (d.Y*iStoneWidth+iStoneWidth = iBoardHeight) and (d.Dir = diVert) then b := False;
if b then AddToPossiblePlaces(d); end;
RotateDomino(d);
|
galagher - Sa 17.07.10 19:25
Hallo!
Sorry, dass ich mich ein weiteres Mal in Serie melde, aber der Code FindAllPossiblePlaces stimmt immer noch nicht. Entweder bekomme ich es hin, dass er Steine nicht unten bzw. rechts ausserhalb des Spielfeldes anlegt, also korrekt arbeitet, aber dafür nicht alle möglichen Plätze innerhalb des Spielfeldes findet.
Oder er findet alle Plätze, legt dafür aber unten bzw. rechts ausserhalb des Spielfeldes an.
Ich möchte aber, dass er
alle möglichen Plätze innerhalb des Spielfeldes findet! Ich kriege das einfach nicht hin.
So findet er nicht alle möglichen Plätze im Spielfeld, legt aber stets korrekt an:
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:
| function TForm1.FindAllPossiblePlaces(d: TDomino): Integer; var x, y, n, h: Integer; b: Boolean; begin d.X := 0; d.Y := 0; d.Rotate := 0; n := 0; h := 0; SetLength(DominoPossibleList, 0);
for x := 0 to iBoardWidth do for y := 0 to iBoardHeight do begin if (d.X*iStoneWidth <= iBoardWidth-iStoneWidth) and (d.Y*iStoneWidth <= iBoardHeight-iStoneWidth) then begin b := False;
if (d.Dir = diHorz) then if (d.X < 16) and (d.Y < 14) then b := True; if (d.Dir = diVert) then if (d.X < 17) and (d.Y < 13) then b := True;
if b then AddToPossiblePlaces(d); end;
RotateDomino(d);
if h >= 4 then h := 0;
Inc(h); d.Rotate := h;
Inc(n);
if n = 3 then begin Inc(d.X); n := 0; end;
if d.X >= iBoardWidth-1 then begin d.X := 0; Inc(d.Y); end;
if d.Y >= iBoardHeight-1 then break; end;
Result := High(DominoPossibleList); end; |
//Edit: Code ist jetzt etwas vereinfacht, das löst das Problem aber nicht!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!