Einzelnen Beitrag anzeigen

w3seek
(Gast)

n/a Beiträge
 
#17

Re: Sieger-Prüfung "Vier gewinnt"

  Alt 29. Jun 2004, 00:57
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]
  Mit Zitat antworten Zitat