(* QuevedoRoutinen.mod Version 2.0 / 5-8-93, Kern von Quevedo *)

MODULE QuevedoRoutinen;

TYPE stellung* = RECORD
                   wtx*,wty*,wkx*,wky*,skx*,sky* : INTEGER;
                   schach*,matt*,turmzug* : BOOLEAN;
                   bewertung : LONGINT
                 END;

PROCEDURE Mini(a,b : INTEGER) : INTEGER;
BEGIN
  IF (a < b) THEN
    RETURN a
  ELSE
    RETURN b
  END
END Mini;

PROCEDURE Maxi(a,b : INTEGER) : INTEGER;
BEGIN
  IF (a > b) THEN
    RETURN a
  ELSE
    RETURN b
  END
END Maxi;

PROCEDURE Zahl(ausdruck : BOOLEAN) : INTEGER;
(* FALSE -> 0, TRUE -> 1 *)
BEGIN
  IF (ausdruck) THEN
    RETURN 1
  ELSE
    RETURN 0
  END
END Zahl;

PROCEDURE Bedroht(s : stellung; x,y : INTEGER) : BOOLEAN;
(* Bedroht der weiße Turm oder König in Stellung s das Feld (x,y) ? *)
BEGIN
  RETURN (Maxi(ABS(s.wkx - x),ABS(s.wky - y)) = 1) OR
         (s.wtx = x) & ((s.wkx # x) OR ((s.wky < s.wty) = (s.wky < y))) OR
         (s.wty = y) & ((s.wky # y) OR ((s.wkx < s.wtx) = (s.wkx < x)))
END Bedroht;

PROCEDURE LegaleStellung*(s : stellung) : BOOLEAN;
(* Ist die Stellung s legal, wenn weiß am Zug ist ? *)
BEGIN
  RETURN (s.wtx >= 1) & (s.wtx <= 8) & (s.wty >= 1) & (s.wty <= 8) &
         (s.wkx >= 1) & (s.wkx <= 8) & (s.wky >= 1) & (s.wky <= 8) &
         (s.skx >= 1) & (s.skx <= 8) & (s.sky >= 1) & (s.sky <= 8) &
         ((s.wtx # s.wkx) OR (s.wty # s.wky)) &
         ((s.wkx # s.skx) OR (s.wky # s.sky)) &
         ((s.skx # s.wtx) OR (s.sky # s.wty)) &
         ~Bedroht(s,s.skx,s.sky)
END LegaleStellung;

PROCEDURE BewerteStellung(VAR s : stellung);
(* Stellung s bewerten und ggf. die Variablen schach und matt setzen *)
VAR zeilen,spalten,reihen,deltawksk,deltawksk2,deltawtwk,deltawtsk,
    distanzx,distanzy,distanz,turmgefahr1,turmgefahr2,x,y : INTEGER;
    baldmatt,fastmatt,patt,turmbedroht : BOOLEAN;
BEGIN
  s.schach := Bedroht(s,s.skx,s.sky);
  s.matt := FALSE;
  patt := TRUE;
  FOR x := Maxi(s.skx - 1,1) TO Mini(s.skx + 1,8) DO
    FOR y := Maxi(s.sky - 1,1) TO Mini(s.sky + 1,8) DO
      patt := patt & (Bedroht(s,x,y) OR (x = s.skx) & (y = s.sky))
    END
  END;
  IF patt & s.schach THEN
    patt := FALSE;
    s.matt := TRUE
  END;
  deltawtwk := Maxi(ABS(s.wkx - s.wtx),ABS(s.wky - s.wty));
  deltawtsk := Maxi(ABS(s.skx - s.wtx),ABS(s.sky - s.wty));
  deltawksk := Maxi(ABS(s.skx - s.wkx),ABS(s.sky - s.wky));
  deltawksk2:= ABS(s.skx - s.wkx) + ABS(s.sky - s.wky);
  turmgefahr1 := deltawtwk - deltawtsk + 8;
  turmgefahr2 := 8 - deltawtsk;
  turmbedroht := (deltawtsk = 1) & (deltawtwk > 1);
  IF (s.wtx < s.skx) & (s.wtx < s.wkx) THEN
    spalten := 8 - s.wtx
  ELSIF (s.wtx > s.skx) & (s.wtx > s.wkx) THEN
    spalten := s.wtx - 1
  ELSE
    spalten := 9
  END;
  IF (s.wty < s.sky) & (s.wty < s.wky) THEN
    zeilen := 8 - s.wty
  ELSIF (s.wty > s.sky) & (s.wty > s.wky) THEN
    zeilen := s.wty - 1
  ELSE
    zeilen := 9
  END;
  distanzx := ABS(s.wkx - s.skx +
                  (s.wtx - s.skx) * Zahl(ABS(s.wtx - s.skx) <= 1));
  distanzy := ABS(s.wky - s.sky +
                  (s.wty - s.sky) * Zahl(ABS(s.wty - s.sky) <= 1));
  IF (spalten < zeilen) OR (spalten = zeilen) & (distanzx < distanzy) THEN
    reihen := spalten;
    distanz := distanzx
  ELSE
    reihen := zeilen;
    distanz := distanzy
  END;
  baldmatt := (Mini(s.skx,9 - s.skx) = 1) & (Mini(s.sky,9 - s.sky) = 1) &
              (deltawksk = 2) & (deltawksk2 = 3);
  fastmatt := (deltawksk = 2) &
              ((Mini(s.skx,9 - s.skx) = 1) &
               ((Mini(s.sky,9 - s.sky) = 2) & (zeilen = 2) OR
                (ABS(s.wty - s.sky) = 1) & (ABS(s.wty - s.wky) = 2)) OR
               (Mini(s.sky,9 - s.sky) = 1) &
               ((Mini(s.skx,9 - s.skx) = 2) & (spalten = 2) OR
                (ABS(s.wtx - s.skx) = 1) & (ABS(s.wtx - s.wkx) = 2)));
  s.bewertung := 0;
  s.bewertung := s.bewertung * 2 + Zahl(patt);
  s.bewertung := s.bewertung * 2 + Zahl(turmbedroht);
  s.bewertung := s.bewertung * 2 + Zahl(~s.matt);
  s.bewertung := s.bewertung * 2 + Zahl(~fastmatt);
  s.bewertung := s.bewertung * 2 + Zahl(~baldmatt);
  s.bewertung := s.bewertung * 8 + reihen;
  s.bewertung := s.bewertung * 8 + distanz;
  s.bewertung := s.bewertung * 8 + deltawksk;
  s.bewertung := s.bewertung * 8 + deltawksk2;
  s.bewertung := s.bewertung * 8 + turmgefahr1;
  s.bewertung := s.bewertung * 8 + turmgefahr2
END BewerteStellung;

PROCEDURE WeisserZug*(VAR s : stellung);
(* Alle für Weiß möglichen Züge ausprobieren, den besten ausführen *)
VAR i,x,y,xmin,xmax,ymin,ymax,anzahl,optimum : INTEGER;
    minimum : LONGINT;
    pos : ARRAY 25 OF stellung;
BEGIN
  anzahl := 0;
  xmin := 1;
  xmax := 8;
  ymin := 1;
  ymax := 8;
  IF s.wtx = s.wkx THEN
    IF s.wty < s.wky THEN
      ymax := s.wky - 1
    ELSE
      ymin := s.wky + 1
    END
  ELSIF s.wty = s.wky THEN
    IF s.wtx < s.wkx THEN
      xmax := s.wkx - 1
    ELSE
      xmin := s.wkx + 1
    END
  END;
  FOR x := xmin TO xmax DO
    IF (x # s.wtx) THEN
      pos[anzahl] := s;
      pos[anzahl].wtx := x;
      pos[anzahl].turmzug := TRUE;
      BewerteStellung(pos[anzahl]);
      INC(anzahl)
    END
  END;
  FOR y := ymin TO ymax DO
    IF (y # s.wty) THEN
      pos[anzahl] := s;
      pos[anzahl].wty := y;
      pos[anzahl].turmzug := TRUE;
      BewerteStellung(pos[anzahl]);
      INC(anzahl)
    END
  END;
  FOR x := Maxi(s.wkx - 1,1) TO Mini(s.wkx + 1,8) DO
    FOR y := Maxi(s.wky - 1,1) TO Mini(s.wky + 1,8) DO
      IF ((x # s.wkx) OR (y # s.wky)) &
         ((x # s.wtx) OR (y # s.wty)) &
         (Maxi(ABS(x - s.skx),ABS(y - s.sky)) > 1) THEN
        pos[anzahl] := s;
        pos[anzahl].wkx := x;
        pos[anzahl].wky := y;
        pos[anzahl].turmzug := FALSE;
        BewerteStellung(pos[anzahl]);
        INC(anzahl)
      END
    END
  END;
  optimum := 0;
  minimum := pos[0].bewertung;
  FOR i := 1 TO anzahl - 1 DO
    IF (pos[i].bewertung < minimum) THEN
      optimum := i;
      minimum := pos[i].bewertung
    END
  END;
  s := pos[optimum]
END WeisserZug;

END QuevedoRoutinen.

