Delphi-PRAXiS
Seite 2 von 7     12 34     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Sieger-Prüfung "Vier gewinnt" (https://www.delphipraxis.net/24941-sieger-pruefung-vier-gewinnt.html)

w3seek 29. Jun 2004 00:13

Re: Sieger-Prüfung "Vier gewinnt"
 
Code:
result := cnt = 4;
das sollte >= 4 sein, hab das wort mindestens vergessen. Ich glaub nicht dass man das in eine funktion ohne es total unuebersichtlich zu machen, zusammenfassen kann. Ich wuerde jede zeile und jede spalte checken, und dann noch die diagonalen bei denen mind 4 felder sind. das sollte eigentlich genuegen.

Allerdings find ich auch den Ansatz von StefanDP ganz gut, setzt allerdings voraus dass man dies beim aendern eines Feldes immer prueft, wenn ein fertiges spielfeld vor liegt, wird man das nicht erkennen.

Luckie 29. Jun 2004 00:16

Re: Sieger-Prüfung "Vier gewinnt"
 
Äh, ja. Aber wenn in der zweiten Reihe von unten dann 3 sind hat Spieler eins auch gewonnen. Probier es mal aus.

w3seek 29. Jun 2004 00:23

Re: Sieger-Prüfung "Vier gewinnt"
 
Code:
    for i := 0 to COLUMNS-1 do
    begin
      if Field[i, r] = 1 then
        Inc(cnt)
      else
        cnt := 0;
    end;
wie gesagt musst du den counter auf null setzen wenn das feld nicht vom gesuchten spieler ist
[edit]
und natuerlich auch fuer jede zeile und spalte wieder auf null setzen
[/edit]

dizzy 29. Jun 2004 00:23

Re: Sieger-Prüfung "Vier gewinnt"
 
Ein Problem sehe ich: Eine Zeile/Spalte der Form: 0 1 1 0 0 1 1 würde zu cnt=4 = true führen, obwohl das ja kein Sieg wäre. Es müssen ja nicht nur 4 Steine in einer Zeile/Spalte/Diag. sein, sondern die müssen auch noch lückenlos sein.

Delphi-Quellcode:
function CheckRows: Boolean;
  var
    c, r: Integer;
  begin
    cnt := 0;
    for c := 0 to COLUMNS-1 do
    begin
      for r := 0 to ROWS-1 do
      begin
        if (Field[c, r] = 0) and (cnt > 0) then // bei Unterbrechung durch '0' zurück setzen!
          cnt := 0
        else if Field[c, r] = 1 then
          Inc(cnt);
      end;
    end;
    result := cnt = 4;
  end;

\\edit: *gnarf* 1.: zu langsam; 2.: nicht so elegant wie w3seek... naja ;)

Luckie 29. Jun 2004 00:27

Re: Sieger-Prüfung "Vier gewinnt"
 
@dizzy: jetzt funktioniert gar nichts mehr. Ich habe ja das Projekt angehangen, ihr könnte da ja eure Idee ausprobieren. Ich lass das erstmal liegen für heute und gehe ins Bett, glaube ich.

dizzy 29. Jun 2004 00:49

Re: Sieger-Prüfung "Vier gewinnt"
 
SO! Jetzt aber. Das Problem war, dass die Schleife immer bis zum Ende durchlief. Daher fand sie auch NUR Siegbedingungen im letzten Durchgang. Lösung: Ein nicht so schönes, aber wirkungsvoll angebrachtes "exit".

Delphi-Quellcode:
  function CheckRows: Boolean;
  var
    c, r: Integer;
  begin
    for r := 0 to ROWS-1 do
    begin
      cnt := 0;
      for c := 0 to COLUMNS-1 do
      begin
        if Field[c, r] <> 1 then cnt := 0
        else inc(cnt);
        if cnt = 4 then
        begin
          result := true;
          exit;
        end; // if cnt=4
      end; // for c...
    end; // for r...
    result := false;
  end; // CheckRows
(Getestet!)

Für CheckColumns einfach die beiden Schleifenköpfe gegeneinander austauschen, und für Diagonal reicht mein Hirnschmalz heute auch net mehr :)
btw: für ein CheckRows waren die Schleifen ohnehin schon falsch herum verschachtelt! Eigentlich war's schon die CheckColumns :zwinker:.
btw2: das "exit" könnte man jetzt noch umgehen, in dem man das ganze in repeat-until-Schleifen packt, und bei cnt=4 nen Flag setzt. Ist aber imho in diesem Fall nicht viel leichter lesbar, und zu dem weniger performant.

n8i,
dizzy

w3seek 29. Jun 2004 00:57

Re: Sieger-Prüfung "Vier gewinnt"
 
Ok, hier mein Algorithmus:

Delphi-Quellcode:
function Gewonnen(Spieler: Byte): Boolean;
const
  N_ZEILEN = 6;
  N_SPALTEN = 7;
  N_GEWINNT = 4;
  Spielfeld: array[0..N_ZEILEN-1] of array[0..N_SPALTEN-1] of Cardinal =
  (
    (0, 0, 0, 0, 0, 0, 0),
    (0, 0, 0, 0, 0, 0, 0),
    (0, 0, 0, 0, 0, 0, 0),
    (0, 0, 0, 0, 0, 0, 0),
    (0, 0, 0, 0, 0, 0, 0),
    (0, 0, 0, 0, 0, 0, 0)
  );

  function GewinntZeile(Zeile: Integer): Boolean;
  var
    c, i: Integer;
  begin
    Result := false;
    c := 0;
    // wir pruefen alle punkte in dieser zeile
    for i := 0 to N_SPALTEN - 1 do
    begin
      // hat der spieler hier einen punkt?
      if Spielfeld[Zeile][i] = Spieler then
      begin
        // wir zaehlen unseren counter hoch
        Inc(c);
        if c = N_GEWINNT then
        begin
          // wir haben N_GEWINNT aufeinanderfolgendende punkte des spielers, er hat somit gewonnen!
          Result := true;
          Exit;
        end;
      end
      else
      begin
        // dieser punkt ist nicht gesetzt oder gehoert nicht dem spieler! Wir setzen den counter auf 0
        // da die reihe unterbrochen wurde
        c := 0;
      end;
    end;
  end;


  function GewinntSpalte(Spalte: Integer): Boolean;
  var
    c, i: Integer;
  begin
    Result := false;
    c := 0;
    // wir pruefen alle punkte in dieser spalte
    for i := 0 to N_ZEILEN - 1 do
    begin
      // hat der spieler hier einen punkt?
      if Spielfeld[i][Spalte] = Spieler then
      begin
        Inc(c);
        if c = N_GEWINNT then
        begin
          // wir haben N_GEWINNT aufeinanderfolgendende punkte des spielers, er hat somit gewonnen!
          Result := true;
          Exit;
        end;
      end
      else
      begin
        // dieser punkt ist nicht gesetzt oder gehoert nicht dem spieler! Wir setzen den counter auf 0
        // da die reihe unterbrochen wurde
        c := 0;
      end;
    end;
  end;

  function GewinntDiagonal(Zeile, Spalte, Delta: Integer): Boolean;
  var
    Anfang, Pos, Ende: PCardinal;
    c: Integer;
  begin
    Result := false;
    // wir holen uns die adresse des punktes von dem aus wir das spielfeld betrachten, das ist der linke bzw obere spielrand
    Pos := @Spielfeld[Zeile, Spalte];
    // wir holen uns die adressen der punkte ueber bzw unter die wir nicht gehen duerfen
    Anfang := @Spielfeld[0, 0];
    Ende := @Spielfeld[N_ZEILEN - 1][N_SPALTEN - 1];
    c := 0;
   
    // diese schleife so lange ausfuehren bis die aktuelle position ausserhalb des spielfelds gesetzt wurde
    while (Cardinal(Pos) <= Cardinal(Ende)) and (Cardinal(Pos) >= Cardinal(Anfang)) do
    begin
      // ist der gesuchte spieler an der aktuellen stelle?
      if Pos^ = Spieler then
      begin
        // wir zaehlen hoch, wie viele punkte hintereinander schon ohne unterbrechnung waren
        Inc(c);
        if c = N_GEWINNT then
        begin
          // ok, wir haben genau N_GEWINNT punkte in folge, der spieler hat gewonnen!
          Result := true;
          Exit;
        end;
      end
      else
      begin
        // ok, der punkt ist nicht gesetzt oder gehoert nicht zu dem gesuchten spieler, wir setzen den counter zurueck
        c := 0;
      end;
      // wir springen zum naechsten punkt der getestet wird. je nachdem in welche richtung wir gehen und wie weit, gibt delta an.
      Inc(Pos, Delta);
    end;
  end;

var
  i: Integer;
begin
  Result := false;

  // wir laufen von der linken oberen spielecke zur linken unteren spielecke
  for i := 0 to N_ZEILEN - 1 do
  begin
       // sind in dieser zeile 4 aufeinanderfolgende punkte des spielers?
    if GewinntZeile(i) or
       // -(N_SPALTEN - 1) ist der abstand zum naechsten punkt der rechts oben (diagonal) liegt, der abstand ist
       // also negativ und um 1 geringer als das spielfeld spalten hat
       GewinntDiagonal(i, 0, -(N_SPALTEN - 1)) or
       // N_SPALTEN + 1 ist der abstand zum naechsten punkt rechts unten (diagonal), der abstand ist also positiv
       // und um 1 groesser als das spielfeld spalten hat
       GewinntDiagonal(i, 0, N_SPALTEN + 1) then
    begin
      Result := true;
      Exit;
    end;
  end;

  // wir laufen von der linken oberen zur rechten oberen spielecke
  for i := 0 to N_SPALTEN - 1 do
  begin
       // sind in dieser spalte 4 aufeinanderfolgende punkte des spielers?
    if GewinntSpalte(i) or
       // N_SPALTEN + 1 ist der abstand zum naechsten punkt unterhalb und rechts von diesem punkt, also um 1 groesser
       // als das spielfeld spalten hat
       GewinntDiagonal(0, i, N_SPALTEN + 1) or
       // N_SPALTEN - 1 ist der abstand zum naechsten punkt unterhalb und links von diesem punkt, also um genau 1 kleiner
       // als das spielfeld spalten hat
       GewinntDiagonal(0, i, N_SPALTEN - 1) then
    begin
      Result := true;
      Exit;
    end;
  end;
end;
Ich habs nicht ausgiebig getestet, aber sollte funktionieren

[edit]
kleiner fix, es sollte glaub ich "while (Cardinal(Pos) <= Cardinal(Ende)) and (Cardinal(Pos) >= Cardinal(Anfang)) do" statt "while (Cardinal(Pos) < Cardinal(Ende)) and (Cardinal(Pos) >= Cardinal(Anfang)) do" sein
[/edit]

Luckie 29. Jun 2004 01:00

Re: Sieger-Prüfung "Vier gewinnt"
 
Oh Gott, wie kommt das den bei mir da jetzt rein? Ich glaube, das muss ich mir noch mal richtig zu Gemühte führen.

dizzy 29. Jun 2004 01:04

Re: Sieger-Prüfung "Vier gewinnt"
 
Zitat:

Zitat von Luckie
Oh Gott, wie kommt das den bei mir da jetzt rein? Ich glaube, das muss ich mir noch mal richtig zu Gemühte führen.

Nimm meins - das hab ich in deinem Projekt gebaut und getestet :zwinker:

Luckie 29. Jun 2004 01:06

Re: Sieger-Prüfung "Vier gewinnt"
 
Hm, w3seeks Code kompiliert, tut nur nicht das, was ich will. :gruebel:


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:44 Uhr.
Seite 2 von 7     12 34     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz