home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1991 / 09_10 / explode / exterm.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1991-08-08  |  27.0 KB  |  818 lines

  1. (* ======================================================================== *)
  2. (*                             EXTERM.PAS                                   *)
  3. (*          Strategiespiel "Explode", die "Exterminator"-Version            *)
  4. (*                    (c) 1991 Gerald Arend & toolbox                       *)
  5. (*    Turbo Pascal (ich denke, ab 5.0 müßte es sich compilieren lassen)     *)
  6. (*    funktioniert auf beliebigen Farbgrafikkarten, für Hercules sind       *)
  7. (*    einige Änderungen notwendig                                           *)
  8. (*                                                                          *)
  9. (*  Dieses Programm wurde aufgrund einer leichtfertigen Äußerung des        *)
  10. (*  Redakteurs Ulrich Schmitz ins Leben gerufen, der ernsthaft behauptete,  *)
  11. (*  er könne in C ein Strategiespiel nach Art von "Explode" programmieren,  *)
  12. (*  das so ziemlich unschlagbar sei. Der "Exterminator" ist die Turbo-      *)
  13. (*  Pascal-Antwort auf diese Herausforderung. Und eine erfolgreiche dazu:   *)
  14. (*  Sie zerschmetterte den "Bestrafer" in einem 14-ründigen Turnier mit      *)
  15. (*  13 : 1.                                                                 *)
  16. (*                                                                          *)
  17. (*  Die hier vorliegende Version wurde gegenüber der Turnierversion noch    *)
  18. (*  einmal leicht verbessert. Wenn Sie gegen die Originalversion spielen    *)
  19. (*  möchten, entfernen Sie bitte die Compiler-Option "{$DEFINE IMPROVED}"   *)
  20. (*  in einer der nächsten Zeilen.                                           *)
  21. (*                                                                          *)
  22. (*  Viel Spaß beim Spielen (und Verlieren?)!                                *)
  23. (*                                                                          *)
  24. (*  Gerald Arend                                                            *)
  25. (* ======================================================================== *)
  26.  
  27. {$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S-,V-,X+}
  28. {$M 65000,0,0}
  29. {$DEFINE IMPROVED}
  30.  
  31. PROGRAM Exterminator;
  32.  
  33. (* Compilerdirektiven:
  34.    {$DEFINE SPEED}    - keine Verzögerungsschleife beim Sprengen
  35.    {$DEFINE DEBUG}    - zeigt Feldbewertung auf dem Spielbrett an
  36.    {$DEFINE IMPROVED} - Verbesserung des Turnier-Algorithmus         *)
  37.  
  38. USES Crt, Dos;
  39. TYPE
  40.   BlockType = ARRAY[0..3] OF STRING[9];                    { einzelne Blöcke }
  41.   SpielerProc = PROCEDURE(Spieler : BYTE);
  42.       { prozedurale Parameter für die Spielprozeduren "Mensch" und Computer" }
  43.   AuswertRec  = RECORD                                      { für Rechnerzug }
  44.                   x, y : BYTE;
  45.                   Wert : INTEGER;
  46.                 END;
  47.   AuswertType = ARRAY[1..36] OF AuswertRec;
  48.  
  49. CONST
  50.   MaxX = 5;                               { Felder von 0 bis MaxX horizontal }
  51.   MaxY = 5;                               { Felder von 0 bis MaxY vertikal   }
  52.   MaxWert = 5;                              { max. Stapelhöhe auf einem Feld }
  53.  
  54.   Farbe : ARRAY[0..2] OF BYTE =                          { die Spielerfarben }
  55.           (DarkGray, LightRed, LightGreen);
  56.   InfoCol = Yellow OR Blue SHL 4;
  57.   Info2Col = White OR LightGray SHL 4;
  58.   LastZugCol = LightGray;
  59.   Feld2Col = LightGray;
  60.   CheckerCol : ARRAY[FALSE..TRUE] OF BYTE =
  61.                (Blue, Black);                          { "Schachbrettfarben" }
  62.  
  63.   xFeld2 = 56;                        { Koordinaten für das kleine Spielfeld }
  64.   yFeld2 = 12;
  65.  
  66.   Block : ARRAY [0..5] OF BlockType =
  67. ((                                                  { die einzelnen "Steine" }
  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. ' . ▒▒▒ o ',
  94. '  o ▒▒███',
  95. ' ┌─┐.▀▀▀ ',
  96. ' └─┘ ''    '));
  97.  
  98. TYPE
  99.   FeldRec   = RECORD
  100.                 Wert  : BYTE;
  101.                 Farbe : BYTE;
  102.               END;
  103.   FeldArray = ARRAY[0..MaxX, 0..MaxY] OF FeldRec;
  104.  
  105.   WertRec   = RECORD              { Record für Auswertung während Rechnerzug }
  106.                 DiffFelder : BYTE;        { Differenz eigene Felder nach Zug }
  107.                 DiffPoints : BYTE;        { Differenz eigene Punkte nach Zug }
  108.                 VerlFelder : BYTE;      { Max. Verlust Felder nach Gegnerzug }
  109.                 VerlPoints : BYTE;      { Max. Verlust Punkte nach Gegnerzug }
  110.                 Nachbarn   : INTEGER;             { Auswertung Nachbarfelder }
  111.                 ZugLegal   : BOOLEAN;                    { Eigenzug erlaubt? }
  112.                 ZugBad     : BOOLEAN; { TRUE, wenn tödlicher Gegnerzug mögl. }
  113.               END;
  114.   WertMatrix = ARRAY[0..MaxX, 0..MaxY] OF WertRec;
  115.   TotalRec   = ARRAY[0..2] OF BYTE;       { für Summierung Punkte und Felder }
  116.  
  117. VAR
  118.   Spieler : ARRAY[1..2] OF SpielerProc;
  119.   GameOver : BOOLEAN;
  120.   Feld : FeldArray;
  121.   xr, yr : BYTE;
  122.   x, y : ARRAY[0..2] OF BYTE;
  123.   Screen : ARRAY[0..24, 0..79] OF WORD ABSOLUTE $B800:$0;
  124.            { die vorliegende Version versteht sich nur mit Farbgrafikkarten! }
  125.   ZugZaehler : BYTE;
  126.   ch : CHAR;
  127.   n : BYTE;
  128.  
  129. CONST
  130.   BX = 9;                                           { Breite der Spielsteine }
  131.   BY = 4;                                             { Höhe der Spielsteine }
  132.   Kritisch : ARRAY[0..MaxX, 0..MaxY] OF BYTE =
  133.              ((2, 3, 3, 3, 3, 2),          { Werte, wann ein Feld explodiert }
  134.               (3, 4, 4, 4, 4, 3),
  135.               (3, 4, 4, 4, 4, 3),
  136.               (3, 4, 4, 4, 4, 3),
  137.               (3, 4, 4, 4, 4, 3),
  138.               (2, 3, 3, 3, 3, 2));
  139.  
  140. PROCEDURE SchalteCursor(An: BOOLEAN);
  141. VAR
  142.   Reg : REGISTERS;
  143. BEGIN
  144.   WITH Reg DO
  145.   BEGIN
  146.     IF An THEN
  147.       CX := $A0B
  148.     ELSE
  149.       CX := $FFFF;
  150.     BX := 0;
  151.     AX := $0100
  152.   END;
  153.   Intr($10, Reg)
  154. END;  { Cursor }
  155.  
  156. PROCEDURE ProgrammEnde;
  157. TYPE
  158.   Screen2Type = ARRAY[1..4000] OF WORD;
  159. VAR
  160.   n : WORD;
  161.   Screen2 : Screen2Type ABSOLUTE $B800:$0000;
  162. CONST
  163.   Step = 77;
  164. BEGIN
  165.   n := 1;
  166.   REPEAT
  167.     Inc(n, Step);
  168.     IF n > 4000 THEN BEGIN
  169.       Dec(n, 4000);
  170.       Delay(5);
  171.     END;
  172.     Screen2[n] := 0;
  173.   UNTIL n = 1;
  174.   TextMode(LastMode);
  175.   SchalteCursor(TRUE);
  176.   ClrScr;
  177.   LowVideo;
  178.   Write('Denke immer daran: Der  ');
  179.   HighVideo;
  180.   Write('E X T E R M I N A T O R  ');
  181.   LowVideo;
  182.   WriteLn('wartet auf Dich...');
  183.   Halt;
  184. END;  { ProgrammEnde }
  185.  
  186.  
  187. PROCEDURE Info(Message1, Message2 : STRING; Attr : BYTE);
  188. BEGIN
  189.   Window(xFeld2, 6, 80, 10);
  190.   TextAttr := Attr;
  191.   Write('╔═══════════════════════╗');
  192.   Write('║                       ║');
  193.   Write('║                       ║');
  194.   Write('╚═══════════════════════╝');
  195.   GotoXY((80 - xFeld2 - Length(Message1)) DIV 2 + 2, 2); Write(Message1);
  196.   GotoXY((80 - xFeld2 - Length(Message2)) DIV 2 + 2, 3); Write(Message2);
  197.   Window(1, 1, 80 ,25);
  198. END;  { Info }
  199.  
  200. PROCEDURE ShowLastZug(Nr, x, y, Attr : BYTE);
  201. BEGIN
  202.   GotoXY(xFeld2 + 16 + Nr * 3, 11);
  203.   TextAttr := Attr;
  204.   Write(Chr(BYTE('A') + x), y + 1);
  205. END;
  206.  
  207. PROCEDURE DrawBlock(x, y : BYTE);             { einzelnes Spielfeld zeichnen }
  208. VAR
  209.   n : BYTE;
  210. BEGIN
  211.   IF Feld[x, y].Farbe = 0 THEN
  212.     TextAttr := CheckerCol[Odd(x + y)] SHL 4
  213.   ELSE
  214.     TextAttr := CheckerCol[Odd(x + y)] SHL 4 OR
  215.                 Farbe[Feld[x, y].Farbe];
  216.   FOR n := 0 TO 3 DO BEGIN
  217.     GotoXY(Succ(x * BX), Succ(y * BY) + n);
  218.     Write(Block[Feld[x, y].Wert][n]);
  219.   END;
  220.   TextBackGround(Black);
  221.   GotoXY(xFeld2 + 2 + 4 * x, yFeld2 + 1 + 2 * y);
  222.   IF Feld[x, y].Wert > 0 THEN
  223.     Write(Feld[x, y].Wert:1)
  224.   ELSE
  225.     Write(#32);
  226. END;
  227.  
  228. PROCEDURE DrawFeld;                            { gesamtes Spielfeld zeichnen }
  229. VAR
  230.   x, y : BYTE;
  231. BEGIN
  232.   FOR x := 0 TO MaxX DO
  233.     FOR y := 0 TO MaxY DO BEGIN
  234.       DrawBlock(x, y);
  235.     END;
  236. END;
  237.  
  238. PROCEDURE DrawInfos;
  239. BEGIN
  240.   Window(xFeld2, 1, 80, 24);
  241.   TextAttr := InfoCol;
  242.   Write('█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█');
  243.   Write('▌  E  X  P  L  O  D  E  ▐');
  244.   Write('▌E x t e r m i n a t o r▐');
  245.   Write('█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█');
  246.   WriteLn;
  247.   WriteLn;
  248.   WriteLn;
  249.   WriteLn;
  250.   TextAttr := LastZugCol;
  251.   Writeln;
  252.   ClrEol;
  253.   WriteLn('    Züge gespielt');
  254.   Write(' Letzte Spielzüge:');
  255.   ClrEol;
  256.   Window(1, 1, 80, 25);
  257.   TextAttr := InfoCol;
  258.   GotoXY(1, 25);
  259.   Write('   (c) 1991 Gerald Arend und toolbox nach einer Spielidee von Patrick Filipaj');
  260.   ClrEol;
  261. END;
  262.  
  263. PROCEDURE DrawFeld2;
  264. BEGIN
  265.   Window(xFeld2, yFeld2, 80, 25);
  266.   TextAttr := Feld2Col;
  267.   Write('╔═A═╤═B═╤═C═╤═D═╤═E═╤═F═╗');
  268.   Write('1   │   │   │   │   │   1');
  269.   Write('╟───┼───┼───┼───┼───┼───╢');
  270.   Write('2   │   │   │   │   │   2');
  271.   Write('╟───┼───┼───┼───┼───┼───╢');
  272.   Write('3   │   │   │   │   │   3');
  273.   Write('╟───┼───┼───┼───┼───┼───╢');
  274.   Write('4   │   │   │   │   │   4');
  275.   Write('╟───┼───┼───┼───┼───┼───╢');
  276.   Write('5   │   │   │   │   │   5');
  277.   Write('╟───┼───┼───┼───┼───┼───╢');
  278.   Write('6   │   │   │   │   │   6');
  279.   Write('╚═A═╧═B═╧═C═╧═D═╧═E═╧═F═╝');
  280.   Window(1, 1, 80, 25);
  281. END;
  282.  
  283. PROCEDURE Cursor(x, y : BYTE);           { blinkender "Cursor" auf Spielfeld }
  284. VAR
  285.   xx, yy, cx, cy : BYTE;
  286. CONST
  287.   Maske = $F800;
  288. BEGIN
  289.   cx := x * BX;
  290.   cy := y * BY;
  291.   FOR xx := cx TO cx + 8 DO
  292.     FOR yy := cy TO cy + 3 DO
  293.       Screen[yy, xx] := Screen[yy, xx] XOR Maske;
  294.   Screen[yFeld2 + 2 * y, xFeld2 + 1 + 4 * x] :=
  295.     Screen[yFeld2 + 2 * y, xFeld2 + 1 + 4 * x] XOR Maske;
  296. END;
  297.  
  298. PROCEDURE Addiere(VAR Feld : FeldArray; x, y : SHORTINT; n : BYTE);
  299. BEGIN                                                         { Stein setzen }
  300.   IF (x >= 0) AND (x <= MaxX) AND
  301.      (y >= 0) AND (y <= MaxY) THEN
  302.     WITH Feld[x, y] DO BEGIN
  303.       Inc(Wert);
  304.       Farbe := n;
  305.     END;
  306. END;
  307.  
  308. PROCEDURE Summiere(VAR Feld : FeldArray; VAR TotFeld, TotPoints : TotalRec);
  309. VAR                     { Punkte und Felder des gesamten Spielfelds addieren }
  310.   x, y : BYTE;
  311. BEGIN
  312.   TotFeld[0] := 0;
  313.   TotFeld[1] := 0;
  314.   TotFeld[2] := 0;
  315.   TotPoints[0] := 0;
  316.   TotPoints[1] := 0;
  317.   TotPoints[2] := 0;
  318.   FOR x := 0 TO MaxX DO
  319.     FOR y := 0 TO MaxY DO BEGIN
  320.       Inc(TotFeld[Feld[x, y].Farbe]);
  321.       Inc(TotPoints[Feld[x, y].Farbe], Feld[x, y].Wert);
  322.     END;
  323. END;  { Summiere }
  324.  
  325. PROCEDURE Check(VAR Feld : FeldArray; Virtuell : BOOLEAN);
  326. VAR                                                       { Explosions-Check }
  327.   x, y, n : BYTE;
  328.   Stabil : BOOLEAN;
  329.   Total : ARRAY[0..2] OF BYTE;
  330. BEGIN
  331.   REPEAT
  332.     Stabil := TRUE;
  333.     Total[0] := 0;
  334.     Total[1] := 0;
  335.     Total[2] := 0;
  336.     FOR x := 0 TO MaxX DO
  337.       FOR y := 0 TO MaxY DO BEGIN
  338.         Inc(Total[Feld[x, y].Farbe]);
  339.         IF Feld[x, y].Wert >= Kritisch[x, y] THEN BEGIN
  340.           n := Feld[x, y].Farbe;                     { Nachbarfelder erhöhen }
  341.           Addiere(Feld, x-1, y, n);
  342.           Addiere(Feld, x+1, y, n);
  343.           Addiere(Feld, x, y-1, n);
  344.           Addiere(Feld, x, y+1, n);
  345.           Dec(Feld[x, y].Wert, Kritisch[x, y]);
  346.           IF Feld[x, y].Wert = 0 THEN                       { Feld ist leer: }
  347.             Feld[x, y].Farbe := 0;                          { neutrale Farbe }
  348.           IF NOT Virtuell THEN BEGIN
  349.             DrawFeld;                                     { Spielfeld zeigen }
  350. {$IFNDEF SPEED}
  351.             Sound(600);
  352.             Delay(3);
  353.             NoSound;
  354.             Delay(300);
  355. {$ENDIF}
  356.           END;
  357.         Stabil := FALSE;
  358.         END;
  359.       END;
  360.       IF (Total[1] = 0) OR (Total[2] = 0) AND
  361.          (ZugZaehler > 2) THEN
  362.       BEGIN
  363.         IF NOT Virtuell THEN
  364.           GameOver := TRUE;                                   { verlooooorn! }
  365.         Exit;
  366.       END;
  367.   UNTIL Stabil;
  368. END;
  369.  
  370. PROCEDURE Pause;
  371. BEGIN
  372.   REPEAT UNTIL ReadKey > '';
  373. END;
  374.  
  375. {$F+}
  376. PROCEDURE Mensch(n : BYTE);
  377. {$F-}
  378. VAR
  379.   ch : CHAR;
  380. BEGIN
  381.   Info('Mensch, Du ziehst!', 'Ich warte...', Farbe[n]);
  382.   REPEAT
  383.     Cursor(x[n], y[n]);
  384.     WHILE KeyPressed DO ReadKey;
  385.     ch := ReadKey;
  386.     Cursor(x[n], y[n]);
  387.     CASE UpCase(ch) OF
  388.       #0 :  { Cursorsteuerung }
  389.         CASE ReadKey OF
  390.           #75 : IF x[n] > 0 THEN Dec(x[n]);
  391.           #77 : IF x[n] < MaxX THEN Inc(x[n]);
  392.           #72 : IF y[n] > 0 THEN Dec(y[n]);
  393.           #80 : IF y[n] < MaxY THEN Inc(y[n]);
  394.         END;
  395.       #27 : { Abbruch }
  396.         ProgrammEnde;
  397.       'A'..'F' :
  398.         x[n] := Ord(UpCase(ch)) - Ord('A');
  399.       '1'..'6' :
  400.         y[n] := Ord(ch) - Ord('1');
  401.     END;
  402.   UNTIL (ch = #13) AND (Feld[x[n], y[n]].Farbe IN [0, n]);
  403.   ShowLastZug(n, x[n], y[n], Farbe[n]);
  404. END;
  405.  
  406. {$F+}
  407. PROCEDURE Computer(Selbst : BYTE);                     { der "Exterminator"! }
  408. {$F-}
  409. VAR
  410.   Matrix : WertMatrix;                            { Feld für Brettauswertung }
  411.   WertFeld : AuswertType;                             { Array für Zugauswahl }
  412.   FeldAlt : FeldArray;                                     { Spielfeldpuffer }
  413.   Gegner : BYTE;                                         { Farbe des Gegners }
  414.  
  415.   PROCEDURE Sort(VAR M : AuswertType);               { sortiert die Zugliste }
  416.   VAR
  417.     a, b : BYTE;
  418.     s : AuswertRec;
  419.   BEGIN
  420.     FOR a := 1 TO 35 DO
  421.       FOR b := a + 1 TO 36 DO
  422.         IF M[a].Wert < M[b].Wert THEN BEGIN
  423.           s := M[a];
  424.           M[a] := M[b];
  425.           M[b] := s;
  426.         END;
  427.   END;  { Sort }
  428.  
  429.   PROCEDURE Analyse(VAR Feld2 : FeldArray);           { analysiert alle Züge }
  430.  
  431.     FUNCTION CheckNachbarn(x, y : SHORTINT;
  432.                            Referenz : SHORTINT) : SHORTINT;
  433.                 { gibt den Wert zurück, um wieviel näher das Nachbarfeld am
  434.                     Explosionsstatus liegt als das eigene Feld, dessen Wert
  435.                                               als "Referenz" übergeben wird  }
  436.     VAR
  437.       Test : SHORTINT;
  438.     BEGIN
  439.       Test := 0;
  440.       IF (x >= 0) AND (x <= MaxX) AND (y >= 0) AND (y <= MaxY) THEN
  441. {$IFDEF IMPROVED}
  442. { Kleine Verbesserung, die erst nach dem Turnier dazukam: Nur Felder des
  443.   Gegners oder neutrale Felder werden in die Nachbarschaftsbewertung
  444.   mit einbezogen }
  445.         IF (Feld2[x, y].Farbe = 0) OR (Feld2[x, y].Farbe = Gegner) THEN
  446. {$ENDIF}
  447.           Test := Referenz - (Kritisch[x, y] - Feld2[x, y].Wert);
  448.       CheckNachbarn := Test;
  449.     END;  { CheckNachbarn }
  450.  
  451.     FUNCTION CountNachbarn : INTEGER; { Nachbarschaftswerte für ganzes Brett }
  452.     VAR
  453.       x, y : BYTE;
  454.       Ref : SHORTINT;                                    { Referenzwert Feld }
  455.       Test : INTEGER;
  456.     BEGIN
  457.       Test := 0;
  458.       FOR x := 0 TO MaxX DO
  459.         FOR y := 0 TO MaxY DO
  460.           IF Feld2[x, y].Farbe = Selbst THEN BEGIN
  461.         { Referenzwert: Wieviel Steine benötigt das Feld noch zur Explosion? }
  462.             Ref := Kritisch[x, y] - Feld2[x, y].Wert;
  463.             Inc(Test, CheckNachbarn(x - 1, y, Ref));
  464.             Inc(Test, CheckNachbarn(x + 1, y, Ref));
  465.             Inc(Test, CheckNachbarn(x, y - 1, Ref));
  466.             Inc(Test, CheckNachbarn(x, y + 1, Ref));
  467.           END;
  468.       CountNachbarn := Test;
  469.     END;  { CountNachbarn }
  470.  
  471.   VAR
  472.     x, y, n, xx, yy : BYTE;
  473.     Feld3, Feld2Alt : FeldArray;
  474.     TotPoints,
  475.     TotFeld,
  476.     TotPointsAlt,
  477.     TotFeldAlt : TotalRec;
  478.     MaxFeldGegner : BYTE;
  479.     MaxPointsGegner : BYTE;
  480.     NachbarnAlt : INTEGER;
  481.   CONST
  482.     BlubberLen = 22;
  483.     Blubber : STRING =
  484.     '                      ....denk.....                       ';
  485.  
  486.   BEGIN                                                            { Analyse }
  487.     TextColor(Farbe[Selbst]);
  488.     Feld2Alt := Feld2;
  489.     Summiere(Feld2Alt, TotFeldAlt, TotPointsAlt);
  490.     NachbarnAlt := CountNachbarn;
  491.     FOR x := 0 TO MaxX DO
  492.       FOR y := 0 TO MaxY DO BEGIN
  493.         Feld2 := Feld2Alt;                              { Feld2 restaurieren }
  494.         WITH Matrix[x, y] DO BEGIN                     { Defaultwerte setzen }
  495.           DiffFelder := 0;
  496.           DiffPoints := 0;
  497.           VerlFelder := 0;
  498.           VerlPoints := 0;
  499.           Nachbarn   := 0;
  500.           ZugLegal   := FALSE;
  501.           ZugBad     := FALSE;
  502.         END;
  503.  
  504.         IF Feld2[x, y].Farbe = Selbst THEN
  505.         BEGIN                                       { eigenes Feld besetzbar }
  506.           Matrix[x, y].ZugLegal := TRUE;
  507.           Inc(Feld2[x, y].Wert);                             { Feld besetzen }
  508.           Check(Feld2, TRUE);                                 { Explosionen? }
  509.           Summiere(Feld2, TotFeld, TotPoints);           { Feldsummen bilden }
  510.           Matrix[x, y].DiffFelder :=                      { gewonnene Felder }
  511.             TotFeld[Selbst] - TotFeldAlt[Selbst];
  512.           Matrix[x, y].DiffPoints :=                      { gewonnene Punkte }
  513.             TotPoints[Selbst] - TotPointsAlt[Selbst];
  514.         END;
  515.  
  516.         IF Feld2[x, y].Farbe = 0 THEN
  517.         BEGIN                                     { neutrales Feld besetzbar }
  518.           Matrix[x, y].ZugLegal := TRUE;
  519.           Matrix[x, y].DiffFelder := 1;
  520.           Matrix[x, y].DiffPoints := 1;
  521.           Inc(Feld2[x, y].Wert);                             { Feld besetzen }
  522.           Feld2[x, y].Farbe := Selbst;              { Farbe nicht vergessen! }
  523.         END;             { Explosions-Check entfällt, da Feld stabil bleibt! }
  524.  
  525.                        { Differenz kritische Felder für diesen Zug ermitteln }
  526.         IF Matrix[x, y].ZugLegal THEN
  527.           Matrix[x, y].Nachbarn := NachBarnAlt - CountNachbarn;
  528.  
  529. { Gegnerzug: Der nächste Programmteil führt  a l l e  möglichen
  530.   Züge des Gegners durch; ermittelt wird der Verlust an Feldern und
  531.   Punkten, die der beste Gegnerzug der Spielsituation des Rechners
  532.   zufügt }
  533.  
  534.         IF Matrix[x, y].ZugLegal THEN BEGIN
  535.          { dieser Check ist nur nötig, wenn auch ein Rechnerzug möglich ist! }
  536.           MaxFeldGegner := 0;
  537.           MaxPointsGegner := 0;
  538.  
  539.           FOR xx := 0 TO MaxX DO
  540.             FOR yy := 0 TO MaxY DO BEGIN
  541.               Feld3 := Feld2;           { Situation nach PC-Zug restaurieren }
  542.               IF (Feld3[xx, yy].Farbe IN [0, Gegner]) THEN
  543.               BEGIN                                     { Gegnerzug möglich! }
  544.                 Inc(Feld3[xx, yy].Wert);                         { Gegnerzug }
  545.                 Check(Feld3, TRUE);                            { Feldprüfung }
  546.                 Summiere(Feld3, TotFeld, TotPoints);     { Feldsummen bilden }
  547.                 IF TotFeld[Gegner] > MaxFeldGegner THEN
  548.                   MaxFeldGegner := TotFeld[Gegner];
  549.                 IF TotPoints[Gegner] > MaxPointsGegner THEN
  550.                   MaxPointsGegner := TotPoints[Gegner];
  551.                 IF (TotFeld[Selbst] = 0) AND (ZugZaehler > 2) THEN
  552.                   Matrix[x, y].ZugBad := TRUE;           { oha: PC is platt! }
  553.               END;
  554.             END;                                  { Hauptschleife Gegnerzüge }
  555.           Matrix[x, y].VerlFelder := MaxFeldGegner;
  556.           Matrix[x, y].VerlPoints := MaxPointsGegner;
  557.         END;                                             { Routine Gegnerzug }
  558.  
  559.       GotoXY(xFeld2 + 1, 8);
  560.       Write(Copy(Blubber, y + x * 6 + 1, BlubberLen));
  561.     END;                                                 { Schleife Eigenzug }
  562.   END;                                                             { Analyse }
  563.  
  564.   PROCEDURE Auswertung;
  565.   TYPE
  566.     ZugSetType = SET OF BYTE;
  567.   LABEL
  568.     CheckNext, KillHim;
  569.   VAR
  570.     xx, yy, n, i, i1, i2 : BYTE;
  571.   BEGIN
  572.     n := 1;
  573.     FOR xx := 0 TO MaxX DO                              { "Matrix" aufteilen }
  574.       FOR yy := 0 TO MaxY DO BEGIN
  575.         CASE Matrix[xx, yy].ZugLegal OF
  576.           TRUE :
  577.           BEGIN
  578.             WertFeld[n].x := xx;
  579.             WertFeld[n].y := yy;
  580.             IF NOT Matrix[xx, yy].ZugBad THEN
  581.             WITH Matrix[xx, yy] DO                           { Feldbewertung }
  582.               WertFeld[n].Wert := DiffFelder * 8
  583.                                 + DiffPoints * 2
  584.                                 - VerlFelder * 4
  585.                                 - VerlPoints * 2
  586.                                 + Nachbarn   * 4
  587.                                 - Kritisch[xx, yy]
  588.             ELSE
  589.               WertFeld[n].Wert := -32000;       { unglückliche Züge erhalten
  590.                                                         miserable Bewertung! }
  591.           END;
  592.  
  593.           FALSE :
  594.             WertFeld[n].Wert := -32500;           { illegale Züge erhalten
  595.                                                     hundsmiserable Bewertung }
  596.         END;                                                          { CASE }
  597.  
  598. {$IFDEF DEBUG}                                       { für Debugging-Zwecke: }
  599.         TextColor(White);              { die Auswertung für alle Felder wird }
  600.         GotoXY(xx * 9 + 1, yy * 4 + 1);        { auf dem Spielfeld angezeigt }
  601.         Window(WhereX, WhereY, WhereX + 8, WhereY + 3);
  602.         WITH Matrix[xx, yy] DO
  603.           IF ZugLegal THEN BEGIN
  604.             IF ZugBad THEN
  605.               TextColor(LightRed)
  606.             ELSE
  607.               IF Feld[xx, yy].Farbe = 0 THEN
  608.                 TextColor(White)
  609.               ELSE
  610.                 TextColor(Farbe[Feld[xx, yy].Farbe]);
  611.             TextBackGround(CheckerCol[Odd(xx + yy)]);
  612.             ClrScr;
  613.             Write('ΣF', DiffFelder:2, ' P', DiffPoints:3);
  614.             Write('±F', VerlFelder:2, ' P', VerlPoints:3);
  615.             WriteLn('±N', Nachbarn);
  616.             Write(WertFeld[n].Wert);
  617.           END;
  618.         Window(1, 1, 80, 25);
  619. {$ENDIF}
  620.  
  621.         Inc(n);
  622.       END;    { Hauptschleife }
  623.  
  624. {$IFDEF DEBUG}
  625.       Pause;
  626. {$ENDIF}
  627.  
  628.     Sort(WertFeld);           { Array sortieren; schlechte und illegale Züge }
  629.                             { gelangen dabei automatisch ans Ende der Liste! }
  630.     i1 := 1;                                     { Zug nach Zufall auswählen }
  631.     i2 := i1;
  632.     REPEAT                     { Ermittlung des Bereichs gleichwertiger Züge }
  633.       Inc(i2);
  634.     UNTIL WertFeld[i2].Wert < WertFeld[i1].Wert;
  635.     Dec(i2);
  636.     IF i1 = i2 THEN
  637.       i := i1                                        { nur ein optimaler Zug }
  638.     ELSE
  639.       REPEAT              { Zufallsgenerator wählt einen der besten Züge aus }
  640.         i := Random(36) + 1;
  641.       UNTIL i IN [i1..i2];
  642.  
  643.     x[Selbst] := WertFeld[i].x;                                 { Zugvorgabe }
  644.     y[Selbst] := WertFeld[i].y;
  645.   END;   { Auswertung }
  646.  
  647. BEGIN                                                             { Computer }
  648.   Info('Der Exterminator zieht!', '', Farbe[Selbst]);
  649.   Gegner := Selbst XOR 3;
  650.   FeldAlt := Feld;
  651.   Analyse(Feld);                                          { Spielfeldanalyse }
  652.   Auswertung;                                                   { Zugauswahl }
  653.   Feld := FeldAlt;                                       { Feld restaurieren }
  654.   DrawFeld;
  655.   ShowLastZug(Selbst, x[Selbst], y[Selbst], Farbe[Selbst]);
  656.   Cursor(x[Selbst], y[Selbst]);
  657.  
  658. {$IFNDEF SPEED}
  659.   Sound(400);
  660.   Delay(15);
  661.   NoSound;
  662.   Delay(900);
  663. {$ENDIF}
  664.  
  665.   Cursor(x[Selbst], y[Selbst]);
  666. END;                                                              { Computer }
  667.  
  668. PROCEDURE InitGame;
  669. BEGIN
  670.   x[1] := 2;
  671.   y[1] := 2;
  672.   x[2] := 3;
  673.   y[2] := 3;
  674.   GameOver := FALSE;
  675. END;                                                              { InitGame }
  676.  
  677. PROCEDURE SetupFeld;
  678. VAR
  679.   x, y : BYTE;
  680. BEGIN
  681.   FOR x := 0 TO MaxX DO
  682.     FOR y := 0 TO MaxY DO
  683.       WITH Feld[x, y] DO BEGIN
  684.         Wert := 0;
  685.         Farbe := 0;
  686.       END;
  687. END;                                                             { SetUpFeld }
  688.  
  689. PROCEDURE Taeterae(n : BYTE);
  690. VAR
  691.   i : BYTE;
  692.   s : WORD;
  693. BEGIN
  694.   IF @Spieler[n] = @Computer THEN BEGIN
  695.     Info('Glorreicher Sieger ist',
  696.          'der Exterminator (' + Chr(Ord('1') + n - 1) + ')', Farbe[n]);
  697.     s := 440;
  698.     FOR i := 1 TO 5 DO BEGIN
  699.       Sound(s * i);
  700.       Delay(150);
  701.     END;
  702.   END ELSE BEGIN
  703.     Info('Glorreicher Sieger ist',
  704.          'der Mensch (' + Chr(Ord('1') + n - 1) + ')', Farbe[n]);
  705.     s := 440;
  706.     FOR i := 5 DOWNTO 1 DO BEGIN
  707.       Sound(s * i);
  708.       Delay(150);
  709.     END;
  710.   END;
  711.   NoSound;
  712.   REPEAT
  713.   UNTIL ReadKey > '';
  714. END;                                                              { Taeterae }
  715.  
  716. PROCEDURE Titel;
  717. BEGIN
  718.   TextBackGround(Blue);
  719.   TextColor(Yellow);
  720.   ClrScr;
  721.   WriteLn;
  722.   WriteLn('        ████████ ██    ██ ████████ ██       ████████ ███████  ████████');
  723.   WriteLn('        ██        ██  ██  ██    ██ ██       ██    ██ ██    ██ ██');
  724.   WriteLn('        ██         ████   ██    ██ ██       ██    ██ ██     █ ██');
  725.   WriteLn('        █████       ██    ████████ ██       ██    ██ ██     █ █████');
  726.   WriteLn('        ██         ████   ██       ██       ██    ██ ██    ██ ██');
  727.   WriteLn('        ████████  ██  ██  ██       ████████ ████████ ████████ ████████');
  728.   WriteLn('        ████████ ██    ██ ██       ████████ ████████ ██████   ████████');
  729.   WriteLn;
  730.   WriteLn;
  731.   TextColor(LightRed);
  732.   WriteLn('     ▒▒▒▒▒ ▒▒ ▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒  ▒▒▒▒▒ ▒▒▒ ▒▒  ▒  ▒▒▒  ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒');
  733.   WriteLn('     ▒      ▒▒▒    ▒   ▒     ▒   ▒ ▒ ▒ ▒  ▒  ▒ ▒ ▒ ▒   ▒   ▒   ▒   ▒ ▒   ▒');
  734.   WriteLn('     ▒▒▒▒    ▒     ▒   ▒▒▒   ▒▒▒▒  ▒ ▒ ▒  ▒  ▒ ▒ ▒ ▒▒▒▒▒   ▒   ▒   ▒ ▒▒▒▒');
  735.   WriteLn('     ▒      ▒▒▒    ▒   ▒     ▒ ▒   ▒   ▒  ▒  ▒ ▒ ▒ ▒   ▒   ▒   ▒   ▒ ▒ ▒');
  736.   WriteLn('     ▒▒▒▒▒ ▒▒ ▒▒   ▒   ▒▒▒▒▒ ▒  ▒▒ ▒   ▒ ▒▒▒ ▒  ▒▒ ▒   ▒   ▒   ▒▒▒▒▒ ▒  ▒▒');
  737.   WriteLn;
  738.   WriteLn;
  739.   TextColor(LightGreen);
  740.   WriteLn('                 O F F I Z I E L L E R   G E W I N N E R   D E S');
  741.   WriteLn;
  742.   WriteLn('              t o o l b o x - E X P L O D E - W E T T B E W E R B S');
  743.   WriteLn;
  744.   WriteLn;
  745.   TextColor(LightCyan);
  746.   WriteLn('        Programmiert von Gerald Arend nach einer Idee von Patrick Filipaj');
  747.   WriteLn('                         (c) 1991 Gerald Arend & toolbox');
  748.   Pause;
  749. END;
  750.  
  751. BEGIN                                                        { Hauptprogramm }
  752.   Randomize;
  753.   CheckBreak := FALSE;
  754.   SchalteCursor(FALSE);
  755.  
  756.   Titel;
  757.   REPEAT
  758.     TextBackGround(Black);
  759.     ClrScr;
  760.     InitGame;
  761.     SetUpFeld;
  762.     DrawInfos;
  763.     DrawFeld2;
  764.  
  765.     Info('Spieler 1:', '<P>C oder <M>ensch?', Farbe[1]);
  766.     REPEAT
  767.       ch := UpCase(ReadKey);
  768.     UNTIL ch IN ['P', 'M'];
  769.     IF ch = 'P' THEN
  770.       Spieler[1] := Computer
  771.     ELSE
  772.       Spieler[1] := Mensch;
  773.     Info('Spieler 2:', '<P>C oder <M>ensch?', Farbe[2]);
  774.     REPEAT
  775.       ch := UpCase(ReadKey);
  776.     UNTIL ch IN ['P', 'M'];
  777.     IF ch = 'P' THEN
  778.       Spieler[2] := Computer
  779.     ELSE
  780.       Spieler[2] := Mensch;
  781.  
  782.     ZugZaehler := 0;
  783.     REPEAT
  784.       DrawFeld;
  785.       n := 1;
  786.       REPEAT
  787.         IF KeyPressed THEN
  788.           IF ReadKey = #27 THEN
  789.             ProgrammEnde;
  790.         TextAttr := White;
  791.         GotoXY(xFeld2 + 1, 10);
  792.         Write(ZugZaehler : 2);
  793.         Spieler[n](n);
  794.         Feld[x[n], y[n]].Farbe := n;
  795.         Inc(Feld[x[n], y[n]].Wert);
  796.         Inc(ZugZaehler);
  797.         DrawFeld;
  798. {$IFNDEF SPEED}
  799.         Delay(300);
  800. {$ENDIF}
  801.         Check(Feld, FALSE);
  802.         n := n XOR 3;
  803.       UNTIL GameOver;
  804.     UNTIL GameOver;
  805.  
  806.     Taeterae(n XOR 3);
  807.  
  808.     Info('Noch ein Spiel?', '<J>/<N>', Info2Col);
  809.     REPEAT
  810.       ch := UpCase(ReadKey);
  811.     UNTIL ch IN ['J', 'N', #27];
  812.   UNTIL ch <> 'J';
  813.   ProgrammEnde;
  814. END.
  815. (* ======================================================================== *)
  816. (*                         Ende von EXTERM.PAS                              *)
  817.  
  818.