|
Antwort |
Registriert seit: 18. Mai 2007 5 Beiträge |
#1
Ich weiß, ein Noob sollte kein Schach programmieren. Aber ich hab mich nunmal für dieses Projekt für die Schule entschieden und möchte es nun durchziehen. Ich möchte simpel anfangen und dann eins nach dem anderen einbauen. Nun habe ich aber ein Problem. Bei einer Abfrage, ob der schwarze Bauer1 auf ein Feld springen darf, wollte ich kontrollieren, dass er nicht auf Felder geht, auf denen schon schwarze Figuren stehen.
Und bei diser Kontrolle läuft was falsch. Er liefert nur eine Message (Ungültiger Zug) für x=A-H und y=7, obwohl die schwarzen Figuren auf x=A-H und y=1-2 stehen. Ich habe mal mein Programm hochgeladen, dass ihr euch einen Überblick verschaffen könnt. Wäre sehr erfreut über schnelle Hilfe, da ich nicht mehr so viel Zeit habe *g* Mfg Steffen |
Zitat |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#3
Hi und erstmal Herzlich Willkommen in der DP
Zitat von SteffDaChef:
Ich weiß, ein Noob sollte kein Schach programmieren.
Zitat von SteffDaChef:
Bei einer Abfrage, ob der schwarze Bauer1 auf ein Feld springen darf, wollte ich kontrollieren, dass er nicht auf Felder geht, auf denen schon schwarze Figuren stehen. Und bei diser Kontrolle läuft was falsch. Er liefert nur eine Message (Ungültiger Zug) für x=A-H und y=7, obwohl die schwarzen Figuren auf x=A-H und y=1-2 stehen. Ich habe mal mein Programm hochgeladen, dass ihr euch einen Überblick verschaffen könnt.
Jedenfalls ist es selten gern gesehen, das man nur Code postet und sagt "schaut mal". Schöner ist es wenn
Wie gesagt, Dein Code ist leider gar nicht kommentiert. An sich führt man übrigens Konstanten ein, damit Du eben nicht irgendwelche Zahlen verwenden musst. Wenn Du 112 schreibst, wird keiner Wissen, dass Du hier einen weißen Bauern meinst! Schreibst Du aber BAUER_WEIß (was eine Konstante mit dem Wert 112 ist), wird man doch eher wissen was Du machen möchtest. An sich kannst Du auch gänzlich auf Zahlen verzichten, sowas macht Delphi für Dich automatisch, wenn Du Aufzählungstypen verwendest. Diese werden einfach mit dem Schlüsselwort type erstellt und haben die Form:
Delphi-Quellcode:
Jetzt kannst Du diesen Datentyp wie andere Variablentypen verwenden. Delphi speichert die intern dann zwar auch als Zahlen ab, aber für Dich bleibt das Transparent, Du kannst also schreiben:
type
TSchachfigur = (sfBauer, sfSpringer, sfLaeufer, sfTurm, sfDame, sfKoenig);
Delphi-Quellcode:
Ist viel leichter lesbar als das mit den Zahlen. Jetzt hast Du natürlich das Problem, dass es 8 Bauern, je 2 Türme, Springer, Läufer, 1 Koenig und 1 Dame pro Farbe gibt. Mit einer Variable ist es also nicht getan. Das was Du als erstes als Zusatzinformation brauchst ist die Farbe. Auch hier kannst Du einfach einen Aufzählungstypen erstellen:
var figur: TSchachfigur;
begin figur := sfDame; TFarbe = (weiss, schwarz); Jetzt brauchst Du noch einen Datentypen, der diese Information (Schachfigur und Farbe) in einem Typen zusammenfässt. Hier verwendet man Verbundtypen, die über das Schlüsselwort record eingeleitet werden. Diese setzen sich aus mehreren Datentypen zusammen und werden mit einem end; beendet. In diesem Fall hätte der Typ die Form
Delphi-Quellcode:
Ich gehe einfach mal davon aus, dass ihr die schon verwendet habt und gehe nicht näher auf den Typen ein. Wie bereits gesagt, gibt es jetzt mehr als eine Figur. Du kannst jetzt also 16 Variablen pro Farbe anlegen und für jede Figur Speichern auf welchem Feld sie sich befindet. Oder Du überlegst, ob es eine gute Alternative gibt. Da Du ohnehin ein Spielfeld hast, kannst Du natürlich auch einfach das machen, was Du schon mit Deinen Zahlen gemacht hast, Du speicherst im Spielfeld, was für eine Figur sich auf welcher Position befindet. Statt einem Array[1..8, 1..8] of Byte hast Du dann ein Array[1..8, 1..8] of TSpielfigur. Das belegst Du entsprechend wie gehabt (nur besser lesbar).
TSpielfigur = record
figur: TSchachfigur; farbe: TFarbe; end; Möchtest Du nun eine Figur von einem Feld (x,y) auf ein anderes (x', y') bewegen, so besteht die Gültigkeitsprüfung aus zwei Dingen. Das erste ist, dass Du schauen musst, ob dieser Zug für die Figur überhaupt erlaubt ist. So kann ein Turm natürlich nicht über eine Figur springen, die zwischen ihm und der Zielposition ist oder sich gar diagonal bewegen. Auch kann ein Bauer sich nur im ersten Zug über zwei Felder nach vorne bewegen, danach jedoch nur noch um ein Feld vor oder eben diagonal schlagen. Hast Du also geprüft, ob das Zielfeld überhaupt für die Figur erreichbar ist, musst Du dann noch schauen, ob wenn das Feld belegt ist, die Figur die das Feld belegt schlagbar ist (Dein eigentliches Problem). Dazu musst Du natürlich nur schauen, ob es sich um die andere Farbe handelt, kurz also:
Delphi-Quellcode:
Gruß Der Unwissende
function istSchlagbar(StartX, StartY, ZielX, ZielY: Integer): Boolean;
begin result := Spielfeld[StartX, StartY].farbe <> Spielfeld[ZielX, ZielY].farbe; end; |
Zitat |
Registriert seit: 18. Mai 2007 5 Beiträge |
#4
Vielen Dank für die ausführliche und kompetente Antwort. Ich werde es mal versuchen umzusetzen. Haben leider in der Schule, dass nie mit dem type und so gemacht, aber scheint ja nicht schwer zu sein. Also nochmal vielen Dank!
Eine Frage hab ich noch. Können bei case-Verzweigungen nur variablen auf zahlen überprüft werden? Und kann man auch die Positionen in type einbinden? Außerdem, was ist das result am ende bzw boolean? mfg Steffen |
Zitat |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#5
Zitat von SteffDaChef:
Können bei case-Verzweigungen nur variablen auf zahlen überprüft werden?
Delphi-Quellcode:
Solche Aufzählungstypen sind also kein Problem, bei einem String hingegen würde ein Case nicht funktionieren (entsprechend erst recht nicht bei Objekten oder anderen komplexen Datentypen).
type
TFarbe = (schwarz = 0, weiss = 118); // ord(schwarz) = 0 // ord(weiss) = 118
Zitat von SteffDaChef:
Und kann man auch die Positionen in type einbinden?
Zitat von SteffDaChef:
Außerdem, was ist das result am ende bzw boolean?
Das, was Du zurückgeben willst weißt Du einfach der speziellen Variable result zu. Result ist dann das, was die wörtliche Übersetzung schon vermuten lässt, das Ergebnis der Funktion. Statt result kannst Du auch den Namen der Funktion verwenden. Da die von mir gepostete Funktion prüft, ob eine Figur schlagbar ist, gibt sie also einen Wahrheitswert zurück. Boolean ist dabei der Delphityp, der dem entspricht. Ein Boolean kann zwei Werte annehmen: True und False (Groß-/Kleinschreibung ist hier wie immer egal). Solch ein Wahrheitswert kann immer mit if überprüft werden. Du kannst also so etwas schreiben wie:
Delphi-Quellcode:
Wobei der Zug hier rein fiktiv ist, hab es nicht mit Schachbretter im Kopf überlegen, müsste aber einem gültigen Zug für das Schlagen durch einen Bauern entsprechen?! Egal.
if not istSchlagbar(A, 10, B, 11) then
begin ShowMessage('Geht nicht!!! Bäh!'); end else begin ... end; Ja, Funktionen geben halt einen Wert zurück, was immer schöner/sauberer/einfacher ist als mit globalen Variablen zu arbeiten. Der Vorteil ist, dass halt jeder, der die Funktion aufruft sein eigenes Ergebnis bekommt. Eine globale Variable hingegen wird immer vom Letzten überschrieben, ohne dass man das sonst bemerkt. |
Zitat |
Registriert seit: 18. Mai 2007 5 Beiträge |
#6
Nochmals vielen Dank,
oben müsste dann folgednes stehen: type TSchachfigur=(sfBauer1,sfBauer2,sfBauer3,sfBauer4, sfBauer5,sfBauer6,sfBauer7, sfBauer8,sfSpringer1,sfSpringer2,sfLaeufer1,sfLaeu fer2,sfTurm1,sfTurm2,sfDame, sfKoenig,wfBauer1,wfBauer2,wfBauer3,wfBauer4,wfBau er5,wfBauer6,wfBauer7, wfBauer8,wfSpringer1,wfSpringer2,wfLaeufer1,wfLaeu fer2,wfTurm1,wfTurm2,wfDame, wfKoenig); TFarbe=(schwarz,weiss); TSpielfigur=record figur:TSchachfigur; farbe:TFarbe; end; Da wir das mit record/Verbundtypen nocht nicht genau hatten, habe ich mich mal im Internet schlau gemacht. Doch nun kann doch in TSpielfigur nur eine Figur und eine Farbe gespeichert werden?! Wie/Wo kann ich dann die Figur und die dazugehörige Farbe ( und vllt auch Koordinate )festlegen. Denn bei der istSchlagbar-Funktion werden ja Koordinate und Farbe zusammen überprüft. Dazu muss man ja erstmal jeder Figur eine feste Farbe geben. Schon mal Danke im vorraus! mfg Steffen Edit:Noch eine Frage. Wenn jetz der Zug funktioniert, wird ja eine Schachfigur auf eine andere verrückt. Die eine Schachfigur wurde dann ja geschalgen und ist weg. 1.Würde die folgende Funktion funktionieren? 2.Wie bekommt man dann noch die Figur aus dem Array? case sfBauer1 of ord(wfBauer1):ImSB1.visible:=false; ord(wfBauer2):ImSB2.visible:=false; |
Zitat |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#7
Zitat von SteffDaChef:
Nochmals vielen Dank
Zitat von SteffDaChef:
Doch nun kann doch in TSpielfigur nur eine Figur und eine Farbe gespeichert werden?! Wie/Wo kann ich dann die Figur und die dazugehörige Farbe ( und vllt auch Koordinate )festlegen.
Denn bei der istSchlagbar-Funktion werden ja Koordinate und Farbe zusammen überprüft. Dazu muss man ja erstmal jeder Figur eine feste Farbe geben. Was Du also immer im Speicher hast ist ein Array[1..8, 1..8] of TSpielfigur. Darin speicherst Du einfach ab, welche Figur sich gerade wo befindet. Am Anfang sind die Positionen klar (eben die Startaufstellung). Wird dann ein Zug gemacht, so bestimmt dieser Zug welche Figur wohin bewegt werden soll. Wenn ich Dein Programm richtig verstanden habe passiert eben das über Koordinaten auf dem Schachbrett (also z.B. A8 nach B9). Um zu prüfen ob der Zug gültig ist kannst Du dann einfach auf dieses interne Schachbrett zugreifen und lässt Dir erstmal die TSpielfigur an der Stelle [1,8] ausgeben. Hier kannst Du nun schauen, ob da überhaupt eine Figur steht (sonst ungültiger Zug), ob wenn da eine Figur steht sie die korrekte Farbe hat (sonst ungültiger Zug) und dann natürlich ob die Zielkoordinate erreicht werden kann (geht nur, wenn keine Figuren im Weg stehen und man nicht eine eigene Figur schlagen müsste). Den Fall, dass dort schon eine Figur steht brauchst Du nicht unbedingt berücksichtigen, Du überschreibst einfach die Figur und das entspricht dem entfernen vom Spielfeld. Natürlich musst Du auch die alte Position der gezogenen Figur wieder als frei markieren! Dann war es das auch schon.
Zitat von SteffDaChef:
2.Wie bekommt man dann noch die Figur aus dem Array?
Wenn also jmd. sagt, er möchte von A8 nach B9 ziehen, dann würdest Du etwas machen wie:
Delphi-Quellcode:
Das ganze ist natürlich nur Pseudocode (ok, sehr stark an Delphi angelehnt!). Es soll halt nur eine mögliche Idee zeigen, es wird auch andere Wege geben die funktionieren! An sich würde ich es halt so machen, dass ich mir in einer (globalen) Variable die Farbe merke, die gerade dran ist. Natürlich dürfen nur solche Figuren bewegt werden, die die korrekte Farbe haben und natürlich muss in jedem Zug auch eine Figur bewegt werden. Alle ungültigen Züge rufen hier nur die Funktion ungültierZug auf, wie eine solche Funktion aussieht muss sich jeder selbst überlegen. Wichtig ist, dass wenn ein ungültiger Zug auftritt, Du die restlichen Schritte nicht durchführst (würde hier einfach passieren!). Auch was das Empty angeht, so ist das hier wirklich nur Pseudocode, Du brauchst hier einfach eine bestimmte Markierung für leere Felder (z.B. eine spezielle Spielfigur).
begin
// prüfen ob das Feld belegt ist if isEmpty(Spielfeld[A, 8]) then begin ungültigerZug; end; // prüfen ob die Farbe ok ist! if not Spielfeld[A, 8].Farbe = aktuelleFarbe then begin ungültigerZug; end; // prüfen ob Spielfigur im Weg ist if not canMove(A, 8, B, 9) then begin ungültigerZug; end; // prüfen ob Spielfeld belegt ist if not isEmpty(Spielfeld[B,9]) then begin if Spielfeld[B,9].Farbe = aktuelleFarbe then begin ungültigerZug; end else begin // Schlagen anzeigen schlage(B,9); end; end; Spielfeld[B,9] := Spielfeld[A, 8]; Spielfeld[A, 8] := empty; end;
Zitat von SteffDaChef:
Edit:Noch eine Frage. Wenn jetz der Zug funktioniert, wird ja eine Schachfigur auf eine andere verrückt. Die eine Schachfigur wurde dann ja geschalgen und ist weg.
1.Würde die folgende Funktion funktionieren? case sfBauer1 of ord(wfBauer1):ImSB1.visible:=false; ord(wfBauer2):ImSB2.visible:=false;
Delphi-Quellcode:
Der erste Weg ist natürlich deutlich sinnvoller! Ord würde Dir nur die Zahl hinter so einem Wert zurückgeben, für Dein Schachprogramm wirst Du die aber nie brauchen! Eine Sache aber noch dazu, warum unterscheidest Du denn eigentlich die 8 Bauern als verschiedene Schachfiguren? Ich meine wenn Du die Schachfigur Bauer und seine Farbe hast, dann sollte das doch eigentlich reichen. Du weißt ob man ihn schlagen kann oder nicht, Du weißt wohin Du ihn bewegen kannst, mehr gibt es doch gar nicht, oder? Insbesondere brauchst Du unter TSchachfigur nicht die weißen und schwarzen zu unterscheiden, schließlich verwendest Du später TSpielfigur, dass eben gerade die Eigenschaft Farbe mit bringt. Eine TSpielfigur besteht immer aus sowohl der Farbe als auch der Schachfigur. Das sollte wie gesagt alle Information sein, die Du überhaupt brauchst.
case sfBauer1.Figur of
wfBauer1 : ... wfBauer2 : ... end; // oder halt case ord(sfBauer1.Figur) of ord(wfBauer1) : ... ord(wfBauer2) : ... end; Hier solltest Du Dich einfach stark am realen Spiel orientieren. Hier hat ein Spieler auch nur 8 Bauern, die er kaum einzeln unterscheiden wird. Ich kenne zumindestens keinen, der den gleichen Bauern bewußt immer auf die gleiche Startposition stellt... |
Zitat |
Registriert seit: 18. Mai 2007 5 Beiträge |
#8
Bei der case-Funktion kommt der Fehler:[Error] mSchach02a.pas(238): Record, object or class type required.
Also ich habe:
Delphi-Quellcode:
Habe ich da irgendwo was falsch gemacht? Er soll damit einfach überprüfen, ob er auf ein Feld geht, auf der keine weiße Figur ist.
type
TSchachfigur=(sfBauer1,sfBauer2,sfBauer3,sfBauer4,sfBauer5,sfBauer6,sfBauer7, sfBauer8,sfSpringer1,sfSpringer2,sfLaeufer1,sfLaeufer2,sfTurm1,sfTurm2,sfDame, sfKoenig,wfBauer1,wfBauer2,wfBauer3,wfBauer4,wfBauer5,wfBauer6,wfBauer7, wfBauer8,wfSpringer1,wfSpringer2,wfLaeufer1,wfLaeufer2,wfTurm1,wfTurm2,wfDame, wfKoenig); var figur:TSchachfigur; procedure check(ox,oy,p,y:integer); begin case sfBauer1.figur of sfBauer1:old(ox,oy,p,y); sfBauer2:old(ox,oy,p,y); ... |
Zitat |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#9
Zitat von SteffDaChef:
Bei der case-Funktion kommt der Fehler:[Error] mSchach02a.pas(238): Record, object or class type required.
Also ich habe:
Delphi-Quellcode:
type
TSchachfigur=(sfBauer1,sfBauer2,sfBauer3,sfBauer4,sfBauer5,sfBauer6,sfBauer7, sfBauer8,sfSpringer1,sfSpringer2,sfLaeufer1,sfLaeufer2,sfTurm1,sfTurm2,sfDame, sfKoenig,wfBauer1,wfBauer2,wfBauer3,wfBauer4,wfBauer5,wfBauer6,wfBauer7, wfBauer8,wfSpringer1,wfSpringer2,wfLaeufer1,wfLaeufer2,wfTurm1,wfTurm2,wfDame, wfKoenig); var figur:TSchachfigur; Schau Dir einfach TSpielfigur an und Du solltest sehen, was hier eigentlich gemeint war/ist. |
Zitat |
Registriert seit: 18. Mai 2007 5 Beiträge |
#10
Normal sollte in den Funktionen/Prozeduren der TForm1.BitBtOkClick-Prozedur, je nachdem, ob der Zug geht oder nicht, das ox(alte x-Koordinate) zu p (eingegebene x-Koordinate) oder andersrum umgewandeelt.
Also wenn der Zug geht: ox:=p und wenn nicht: p:=ox Das gleiche gilt für die oy(alte y-Koordinate) und y (eingegebene y-Koordinate).
Delphi-Quellcode:
Kann es sein, dass in den Prozeduren (Reihenfolge ist sinnvoll gewählt) die Varibalen ox und oy, durch die Funktionen/Prozeduren gar nicht verändert werden.
procedure TForm1.BitBtOkClick(Sender: TObject); {Procedure, die alle Funktionen und Prozeduren vereinigt und ausführt}
begin if CbSf.Text='Bauer1' then begin ox:=1; //alte x-Koordinate oy:=2; //alte y-Koordinate x:=Ed_X.Text; //Bestimmung von x aus einem Textfeld y:=StrToInt(Ed_Y.Text); //Bestimmung von y aus einem Textfeld xk(x); //wandelt x für Array um istFarbeSchlagbar(ox,oy,p,y); //überprüft farbe zum schlagen checkFarbe(ResultFarbe); //falls Farbe nicht in Ordnung, dann soll p auf ox und y auf oy zurückgesetzt werden, damit figur nicht berschoben wird PruefungZug(ox,oy,p,y); //eigentliche Prüfung über Felder xkoordinate(p); // folgende 4 Prozeduren verschieben nur Bild, abhängig von p und y ykoordinate(y); ImSB1.Left:=l; ImSB1.Top:=t; Normal wird ja von oben nach unten alles nacheinander abgearbeitet. Also werden auch in die Funktionen/Prozeduren die aktuellen Werte der Variablen gegeben, dann die Funktion/Prozedur durchlaufen, die Variablen mit ihren Werten wieder ausgegeben/verändert. Danach folgt die nächste Prozedur usw. Also müsste PruefungZug die endgültigen p, y, ox und oy Werte festlegen und auch ox und oy für den nächsten Durchlauf der Prozedur TForm1.BitBtOkClick. Nur bleibt ox und und oy glaub ich immer gleich. Normal läuft das aber doch wie oben beschrieben ab, oder? |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |