home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / TURBOPAS / QUBIC32.LBR / QUBIC.PZS / QUBIC.PAS
Pascal/Delphi Source File  |  2000-06-30  |  21KB  |  769 lines

  1. {               QUBIC.PAS  Vers 3.2  10Nov85
  2.  
  3.           (C) 1985  by  W. Brimhall
  4.                         Phoenix, Az.  602-996-3201
  5.  
  6.    This program may be distributed free for non-commerical use.
  7.  
  8.          Qubic is a game of Tic Tac Toe in a 4x4x4 cube.
  9.             This version is written in Turbo Pascal.
  10. }
  11.  
  12. PROGRAM Qubic;
  13.  
  14. { Patch in different values here to configure the game for different
  15.   keyboard arrow codes. }
  16.  
  17. CONST
  18.   left=^S;  { WordStar keyboard arrow codes }
  19.   right=^D;
  20.   up=^E;
  21.   down=^X;
  22.   abort=^C;  { ^C aborts game }
  23.   empty=0;
  24.   flagged=1;
  25.   player=10;
  26.   machine=100;
  27.  
  28. { This table is used to convert from square # to screen
  29.   position. It is organized as a 64x2 array. The square
  30.   # is used as the index to look up the screen row &
  31.   column positions. }
  32.  
  33.   scrn_pos : ARRAY[1..64,1..2] OF BYTE =
  34.     ((3,36),(3,43),(3,50),(3,57),
  35.      (4,31),(4,38),(4,45),(4,52),
  36.      (5,26),(5,33),(5,40),(5,47),
  37.      (6,21),(6,28),(6,35),(6,42),
  38.  
  39.      (8,36),(8,43),(8,50),(8,57),
  40.      (9,31),(9,38),(9,45),(9,52),
  41.      (10,26),(10,33),(10,40),(10,47),
  42.      (11,21),(11,28),(11,35),(11,42),
  43.  
  44.      (13,36),(13,43),(13,50),(13,57),
  45.      (14,31),(14,38),(14,45),(14,52),
  46.      (15,26),(15,33),(15,40),(15,47),
  47.      (16,21),(16,28),(16,35),(16,42),
  48.  
  49.      (18,36),(18,43),(18,50),(18,57),
  50.      (19,31),(19,38),(19,45),(19,52),
  51.      (20,26),(20,33),(20,40),(20,47),
  52.      (21,21),(21,28),(21,35),(21,42));
  53.  
  54. { Table of next non-winning, non-blocking machine moves.
  55.   This is organized as a 16x1 array of square numbers.}
  56.  
  57.   mach_move : ARRAY[1..16] OF BYTE =
  58.     (1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43);
  59.  
  60. { Table of winning lines. This is organized as a
  61.   76x4 array of square numbers.}
  62.  
  63.   win_line : ARRAY[1..76,1..4] OF BYTE =
  64.       { left & right }
  65.     (( 1,2,3,4   ),( 5,6,7,8   ),(9,10,11,12 ),(13,14,15,16),
  66.      (17,18,19,20),(21,22,23,24),(25,26,27,28),(29,30,31,32),
  67.      (33,34,35,36),(37,38,39,40),(41,42,43,44),(45,46,47,48),
  68.      (49,50,51,52),(53,54,55,56),(57,58,59,60),(61,62,63,64),
  69.        { up & down }
  70.      (1,17,33,49 ),(5,21,37,53 ),(9,25,41,57 ),(13,29,45,61),
  71.      (2,18,34,50 ),(6,22,38,54 ),(10,26,42,58),(14,30,46,62),
  72.      (3,19,35,51 ),(7,23,39,55 ),(11,27,43,59),(15,31,47,63),
  73.      (4,20,36,52 ),(8,24,40,56 ),(12,28,44,60),(16,32,48,64),
  74.        { front & back }
  75.      (1,5,9,13   ),(17,21,25,29),(33,37,41,45),(49,53,57,61),
  76.      (2,6,10,14  ),(18,22,26,30),(34,38,42,46),(50,54,58,62),
  77.      (3,7,11,15  ),(19,23,27,31),(35,39,43,47),(51,55,59,63),
  78.      (4,8,12,16  ),(20,24,28,32),(36,40,44,48),(52,56,60,64),
  79.        { left & right diagnals }
  80.      (1,6,11,16  ),(17,22,27,32),(33,38,43,48),(49,54,59,64),
  81.      (13,10,7,4  ),(29,26,23,20),(45,42,39,36),(61,58,55,52),
  82.        { up & down diagnals }
  83.      (1,21,41,61 ),(2,22,42,62 ),(3,23,43,63 ),(4,24,44,64 ),
  84.      (49,37,25,13),(50,38,26,14),(51,39,27,15),(52,40,28,16),
  85.        { front & back diagnals }
  86.      (1,18,35,52 ),(5,22,39,56 ),(9,26,43,60 ),(13,30,47,64),
  87.      (49,34,19,4 ),(53,38,23,8 ),(57,42,27,12),(61,46,31,16),
  88.        { cross diagnals }
  89.      (1,22,43,64 ),(16,27,38,49),(4,23,42,61 ),(13,26,39,52));
  90.  
  91. { Table of one of many possible sets of winning moves. To prove
  92.   that winning is possible the program will supply these moves if
  93.   the player logs on with the name 'WINNER'.}
  94.  
  95.   win_move : ARRAY[1..8] OF BYTE =
  96.     (10,11,41,27,26,25,9,57);
  97.  
  98. TYPE  square_status = empty..machine;
  99.   position = 0..64;
  100.   setofchar = SET OF CHAR;
  101.   str80 = STRING[80]; {Turbo doesn't like STRING parameters}
  102.  
  103. VAR  cube : ARRAY[position] OF square_status;
  104.   line_sum : ARRAY[1..76] OF INTEGER;
  105.   row,column,i,j,square,move : INTEGER;
  106.   name,reply : str80;
  107.   response : CHAR;
  108.   moved,game_over,hard_game,aborted : BOOLEAN;
  109.  
  110. (*********)
  111. (* Space *)
  112. (*********)
  113.  
  114. (* Output spaces to the CRT *)
  115. PROCEDURE Space(count:INTEGER);
  116. BEGIN
  117.     WHILE count > 0 DO
  118.   BEGIN
  119.       WRITE(' ');
  120.       count := count-1
  121.   END;    (* WHILE count *)
  122. END;    (* Space *)
  123.  
  124. (**********)
  125. (* Center *)
  126. (**********)
  127.  
  128. (* Center a String on the CRT *)
  129. PROCEDURE Center(sentence:str80);
  130. CONST    scrnwidth = 80;  (* screen width *)
  131.    offset = 2;  (* offset to make screen look centered *)
  132. VAR    len : INTEGER;
  133. BEGIN
  134.     len := LENGTH(Sentence);
  135.     WRITELN(sentence:len-offset+(scrnwidth-len) DIV 2)
  136. END;    (* Center *)
  137.  
  138. (*********)
  139. (* Erase *)
  140. (*********)
  141.  
  142. (* Erase a line on the CRT and place cursor at column 1 *)
  143. PROCEDURE Erase(line:INTEGER);
  144. BEGIN
  145.     Gotoxy(1,line);
  146.     ClrEol;
  147. END;    (* Erase *)
  148.  
  149. (**************)
  150. (* initialize *)
  151. (**************)
  152.  
  153. (* Display instructions & initialize *)
  154. PROCEDURE initialize;
  155. VAR  i : INTEGER;
  156. BEGIN
  157.     move := 1;
  158.     ClrScr;
  159.     Gotoxy(1,22);
  160.     Center('(C) 1985 by W. Brimhall Phoenix, Az.  602-996-3201');
  161.     Center('This program may be distributed free for non-commerical use.');
  162.     Gotoxy(1,1);
  163.     Center('Welcome  to');
  164.     Gotoxy(1,3);
  165.     Center('+ +  Q  U  B  I  C  + +');
  166.     Center('Vers  3.2');
  167.     Gotoxy(1,6);
  168.     Delay(2000);
  169.     Center('The game is Tic Tac Toe in a 4x4x4 cube. To make your');
  170.     Center('move use the arrows on the keyboard to position the cursor');
  171.     Center('to your selected position in the cube, then press RETURN.');
  172.     FOR i := 1  TO 64 DO
  173.       cube[i] := 0;
  174.     aborted := FALSE;
  175.     Gotoxy(1,16);
  176.     WRITE('Your name please? ');
  177.     READLN(name);
  178.     Gotoxy(1,18);
  179.     Write('Do you want a hard game ',name,'? ');
  180.     READLN(reply);
  181.     IF reply[1] IN ['Y','y'] THEN
  182.       hard_game := TRUE
  183.     ELSE
  184.       hard_game := FALSE;
  185. END;    (* Initialize *)
  186.  
  187. (*************)
  188. (* disp_cube *)
  189. (*************)
  190.  
  191. (* Display the cube on the CRT screen *)
  192. PROCEDURE disp_cube;
  193. VAR  cube_line : str80;
  194.   spaces, level : integer;
  195. BEGIN
  196.     cube_line := ':      :      :      :';
  197.     ClrScr;
  198.     LowVideo;
  199.     WRITELN;
  200.     FOR level := 1 TO 4 DO
  201.   BEGIN
  202.       WRITELN;
  203.       spaces := 35;
  204.  
  205.     REPEAT
  206.         Space(spaces);
  207.         WRITELN(cube_line);
  208.         spaces := spaces-5;
  209.     UNTIL spaces = 15;
  210.  
  211.   END     (* FOR level *);
  212.   NormVideo;
  213. END;    (* Disp_cube *)
  214.  
  215. (***************)
  216. (* Goto_square *)
  217. (***************)
  218.  
  219. (* Position cursor to the current square on the crt screen *)
  220.  
  221. PROCEDURE Goto_square;
  222. BEGIN
  223.   Erase(12); Gotoxy(70,12);
  224.   WRITE('Square ',square);
  225.   row := scrn_pos[square,1];
  226.   column := scrn_pos[square,2];
  227.   Gotoxy(column,row);
  228. END;  (* Goto_square *)
  229.  
  230. (*****************)
  231. (* Select_square *)
  232. (*****************)
  233.  
  234. { Use the Keyboard arrows to select the players next
  235.   move. When the cursor is positioned to the selected
  236.   square press return. The current square will be
  237.   returned in the global variable 'square'. If the
  238.   position is undefined square will be equal to 0 }
  239.  
  240. PROCEDURE Select_square;
  241. BEGIN
  242.   Goto_square;
  243.   WRITE(CHR(7));  { bel }
  244.  
  245.   IF name = 'WINNER' THEN  {get move from win_move array}
  246.     BEGIN
  247.       DELAY(1500);
  248.       Erase(1);
  249.       square := win_move[move];
  250.       move := move + 1;
  251.       Goto_square;
  252.       DELAY(1500);
  253.       WRITE('x');
  254.       Goto_square;
  255.       DELAY(1500);
  256.     END
  257.   ELSE
  258.     REPEAT  {get move from player}
  259.       READ(KBD,response);
  260.       CASE response OF
  261.         left  : square := square-1;
  262.         right : square := square+1;
  263.         down  : square := square+4;
  264.         up    : square := square-4;
  265.         abort : aborted := TRUE
  266.       END;  { CASE }
  267.       IF square < 1 THEN square := square+64;
  268.       IF square > 64 THEN square := square-64;
  269.       Erase(1);
  270.       Goto_square;
  271.     UNTIL (response=^M) OR aborted
  272.  
  273. END;  { Select_square }
  274.  
  275. (***************)
  276. (* Player_move *)
  277. (***************)
  278.  
  279. { Make players move, if it is to an undefined or already
  280.   taken square then tell him so and make him do it again.
  281.   Store the player flag in the selected square of the
  282.   cube array }
  283.  
  284. PROCEDURE Player_move;
  285. VAR  first_try : BOOLEAN;
  286. BEGIN
  287.   first_try := TRUE;
  288.   moved := FALSE;
  289.  
  290.   WHILE (moved=FALSE) AND (aborted=FALSE) DO
  291.     BEGIN
  292.  
  293.     IF first_try THEN  { IF #1 }
  294.       BEGIN
  295.       Erase(24); Erase(23);
  296.       Write('Your move ',name,': ');
  297.       select_square;
  298.       first_try := FALSE
  299.       END;
  300.  
  301.     IF (cube[square]=machine) AND (aborted=FALSE) THEN  { IF #2 }
  302.       BEGIN
  303.       Erase(1); Erase(23);
  304.       WRITE('Come on ',name,', can''t you see ');
  305.       WRITE('that square is mine!');
  306.       Erase(24);
  307.       WRITE('It''s still your move: ');
  308.       select_square
  309.       END
  310.  
  311.     ELSE  { ELSE #2 }
  312.  
  313.       IF (cube[square]=player) AND (aborted=FALSE) THEN  { IF #3 }
  314.         BEGIN
  315.         Erase(1); Erase(23);
  316.         WRITE('That''s already your square ',name,',');
  317.         Erase(24);
  318.         WRITE('move again: ');
  319.         select_square
  320.         END
  321.  
  322.       ELSE  { ELSE #3 }
  323.  
  324.         BEGIN  { Square must be empty, give it to player }
  325.         cube[square] := player;
  326.         Write('x');
  327.         moved := TRUE
  328.         END;
  329.  
  330.   END;    { WHILE }
  331. END;    { Player_move }
  332.  
  333. (*************)
  334. (* Show_move *)
  335. (*************)
  336.  
  337. (* Position the cursor to the current square
  338.    and write a 'o' for the machine *)
  339.  
  340. PROCEDURE Show_move;
  341. BEGIN
  342.   Goto_square;
  343.   WRITE('o',#8)
  344. END;  (* Show_move *)
  345.  
  346. (************)
  347. (* Evaluate *)
  348. (************)
  349.  
  350. (* This function evaluates a selected winning line by
  351.    summing the value in each square *)
  352.  
  353. FUNCTION Evaluate(line:INTEGER):INTEGER;
  354. VAR  sum,i : INTEGER;
  355. BEGIN
  356.   sum := 0;
  357.   FOR i := 1 TO 4 DO
  358.     sum := sum + cube[win_line[line,i]];
  359.   Evaluate := sum
  360. END;  (* Eval_pos *)
  361.  
  362. (***********)
  363. (* Move_to *)
  364. (***********)
  365.  
  366. (* Move to a square on selected line that contains sq_val *)
  367.  
  368. PROCEDURE Move_to(line,sq_val:INTEGER);
  369. VAR  sqr : INTEGER;
  370. BEGIN
  371.   IF line MOD 4 < 2 THEN
  372.     BEGIN  (* try moving to outside squares on exterior lines *)
  373.       sqr := 1;
  374.       REPEAT
  375.         IF cube[win_line[line,sqr]]=sq_val THEN
  376.           BEGIN
  377.             square := win_line[line,sqr];
  378.             cube[square] := machine;
  379.             moved := TRUE
  380.           END;
  381.         sqr := sqr+3;
  382.       UNTIL moved OR (sqr > 4);
  383.     END  (* IF line *)
  384.   ELSE
  385.     BEGIN  (* try moving to inside squares on interior lines *)
  386.       sqr := 2;
  387.       REPEAT
  388.         IF cube[win_line[line,sqr]]=sq_val THEN
  389.           BEGIN
  390.             square := win_line[line,sqr];
  391.             cube[square] := machine;
  392.             moved := TRUE
  393.           END;
  394.         sqr := sqr+1;
  395.       UNTIL moved OR (sqr > 3)
  396.     END;  (* ELSE line *)
  397. END;  (* Move_to *)
  398.  
  399. (***************)
  400. (* Pick_square *)
  401. (***************)
  402.  
  403. (* Pick a square on winning line that could
  404.    result in a future multi win *)
  405.  
  406. PROCEDURE Pick_square(line:INTEGER);
  407. BEGIN  (* Pick_square *)
  408.   Move_to(line,flagged);
  409.   IF moved=FALSE THEN
  410.     Move_to(line,empty);
  411.   IF moved THEN
  412.     BEGIN
  413.       Erase(1);
  414.       Write('Machine takes:');
  415.       Show_move
  416.    END
  417. END;  (* Pick_square *)
  418.  
  419. (**********)
  420. (* Unflag *)
  421. (**********)
  422.  
  423. (* Restore all flagged squares to empty *)
  424.  
  425. PROCEDURE Unflag;
  426. VAR  square : INTEGER;
  427. BEGIN
  428.   FOR square := 1 TO 64 DO
  429.     IF cube[square]=flagged THEN
  430.       cube[square]:=empty
  431. END;  (* Unflag *)
  432.  
  433. (**************)
  434. (* Multi_move *)
  435. (**************)
  436.  
  437. (* Move to flagged square to take or block a multi win *)
  438.  
  439. PROCEDURE Multi_move(line:INTEGER);
  440. VAR  sqr : INTEGER;
  441. BEGIN
  442.   sqr := 1;
  443.   REPEAT
  444.     IF cube[win_line[line,sqr]]=flagged THEN
  445.       BEGIN
  446.         square := win_line[line,sqr];
  447.         cube[square]:=machine;
  448.         moved := TRUE
  449.       END;
  450.     sqr := sqr+1
  451.   UNTIL moved OR (sqr > 4);
  452.  
  453.   Erase(1);
  454.   IF line_sum[line] < machine THEN
  455.     BEGIN
  456.       WRITE('Just in the nick of time! ');
  457.       WRITE('Machine moves to:')
  458.     END
  459.   ELSE
  460.     BEGIN
  461.       WRITE('Let''s see you get out of this one! ');
  462.       WRITE('Machine moves to:')
  463.     END;
  464.   Show_move
  465. END;  (* Multi_move *)
  466.  
  467. (*************)
  468. (* Multi_win *)
  469. (*************)
  470.  
  471. (* Check for a move that could result in a win
  472.    on more than one line *)
  473.  
  474. PROCEDURE Multi_win;
  475. VAR  line,square : INTEGER;
  476. BEGIN
  477.   line := 1;
  478.   REPEAT  (* Flag any possible machine multi win squares *)
  479.     line_sum[line]:=Evaluate(line);
  480.     IF line_sum[line] = machine + machine THEN
  481.       FOR square := 1 TO 4 DO
  482.         IF cube[win_line[line,square]]=empty THEN
  483.           cube[win_line[line,square]]:=flagged;
  484.   IF (line_sum[line] > machine + machine) AND
  485.           (line_sum[line] < machine + machine + player) THEN
  486.       Multi_move(line);  (* Move to multi win square *)
  487.     line := line+1;
  488.   UNTIL moved OR (line > 76);
  489.  
  490.   IF moved=FALSE THEN
  491.     BEGIN
  492.       FOR line := 1 to 76 DO  (* Evaluate new linesums *)
  493.         line_sum[line] := Evaluate(line);
  494.       line := 1;
  495.       REPEAT  (* Check for possible future machine multi win *)
  496.         IF (line_sum[line] = machine + flagged + flagged) OR
  497.           (line_sum[line] = machine + flagged + flagged + flagged) THEN
  498.             Pick_square(line);  (* Pick a square that could be a multi win *)
  499.         line := line+1;
  500.       UNTIL moved OR (line > 76);
  501.     END;  (* IF moved *)
  502.  
  503.   Unflag;  (* restore flagged squares to empty *)
  504.  
  505.   IF moved=FALSE THEN
  506.     BEGIN
  507.       line := 1;
  508.       REPEAT  (* Flag any possible player multi win squares *)
  509.         line_sum[line]:=Evaluate(line);
  510.         IF line_sum[line] = player + player THEN
  511.           FOR square := 1 TO 4 DO
  512.             IF cube[win_line[line,square]]=empty THEN
  513.               cube[win_line[line,square]]:=flagged;
  514.         IF (line_sum[line] > player + player) AND
  515.             (line_sum[line] < player + player + player) THEN
  516.               Multi_move(line);  (* Move to multi win square *)
  517.         line := line+1;
  518.       UNTIL moved OR (line > 76)
  519.     END;  (* FOR line *)
  520.  
  521.   IF moved=FALSE THEN
  522.     BEGIN
  523.       FOR line := 1 to 76 DO  (* Evaluate new linesums *)
  524.         line_sum[line] := Evaluate(line);
  525.       line := 1;
  526.       REPEAT  (* Check for possible future player multi win *)
  527.         IF (line_sum[line] = player + flagged + flagged) OR
  528.           (line_sum[line] = player + flagged + flagged + flagged) THEN
  529.             Pick_square(line);  (* Pick a square that could be a multi win *)
  530.         line := line+1;
  531.       UNTIL moved OR (line > 76)
  532.     END;  (* IF moved *)
  533.  
  534. END;  (* Multi_win *)
  535.  
  536. (**************)
  537. (* Plane_move *)
  538. (**************)
  539.  
  540. (* Move to flagged or empty square on selected plane *)
  541.  
  542. PROCEDURE Plane_move(plane:INTEGER);
  543. VAR   line : INTEGER;
  544. BEGIN
  545.   line := 4*plane-3;
  546.   REPEAT
  547.     Move_to(line,flagged); (* try to move to flagged square *)
  548.     IF moved=FALSE THEN
  549.       Move_to(line,empty); (* try to move to an empty square *)
  550.     line := line+1;
  551.   UNTIL moved or (line=4*plane);
  552.  
  553.   IF moved THEN
  554.     BEGIN
  555.       Erase(1);
  556.       Write('Machine will move to:');
  557.       Show_move
  558.     END
  559. END;  (* Plane_move *)
  560.  
  561. (****************)
  562. (* Check_planes *)
  563. (****************)
  564.  
  565. (* Check for 4 player squares on a plane *)
  566.  
  567. PROCEDURE Check_planes;
  568. VAR  line,sqr,plane,plane_sum : INTEGER;
  569. BEGIN
  570.   FOR plane := 1 to 18 DO  (* cube contains 18 planes *)
  571.     BEGIN
  572.       plane_sum:=0;
  573.       FOR line := 4*plane-3 TO 4*plane DO
  574.         FOR sqr := 1 TO 4 DO
  575.           BEGIN
  576.       plane_sum := plane_sum + cube[win_line[line,sqr]];
  577.             IF moved=FALSE THEN
  578.               IF (plane_sum > 4 * player) AND
  579.                 (plane_sum < 5 * player) THEN
  580.                   Plane_move(plane)  (* move to square on plane *)
  581.               ELSE
  582.                 IF (plane_sum > machine + 4 * player ) AND
  583.                   (plane_sum < machine + 5 * player ) THEN
  584.                     Plane_move(plane)  (* move to square on plane *)
  585.           END  (* FOR sqr *)
  586.     END  (* FOR plane *)
  587. END;  (* Check_planes *)
  588.  
  589. (***************)
  590. (* Take_square *)
  591. (***************)
  592.  
  593. (* Locate the empty square on selected line and give
  594.    it to the machine. Place square number in the
  595.    global variable square *)
  596.  
  597. PROCEDURE Take_square(line:INTEGER);
  598. VAR  sqr:INTEGER;
  599. BEGIN
  600.   FOR sqr := 1 to 4 DO
  601.       IF cube[win_line[line,sqr]] = empty THEN
  602.         square := win_line[line,sqr];
  603.   cube[square] := machine;
  604. END;  (* Take_square *)
  605.  
  606. (************)
  607. (* Show_win *)
  608. (************)
  609.  
  610. (* Move the cursor to each square on the selected winning line *)
  611.  
  612. PROCEDURE Show_win(line:INTEGER; winner:CHAR);
  613. VAR  i,sqr:INTEGER;
  614. BEGIN
  615.   FOR i := 1 TO 4 DO
  616.     BEGIN
  617.       sqr := win_line[line,i];
  618.       row := scrn_pos[sqr,1];
  619.       column := scrn_pos[sqr,2];
  620.       Gotoxy(column,row);
  621.       WRITE(CHR(7));    (* bel *)
  622.       Delay(1500);
  623.       WRITE(winner)
  624.     END
  625. END;  (* Show_win *)
  626.  
  627. (****************)
  628. (* Machine_move *)
  629. (****************)
  630.  
  631. (* Process next machine move *)
  632.  
  633. PROCEDURE Machine_move;
  634. VAR  line,move,sqr : INTEGER;
  635. BEGIN
  636.   moved := FALSE;  game_over := FALSE;
  637.   line := 1;
  638.   REPEAT  (* Check for player 4 in line *)
  639.     line_sum[line] := Evaluate(line);
  640.     IF line_sum[line] = 4 * player THEN
  641.       BEGIN
  642.         Gotoxy(1,1);
  643.         WRITE('Congratulations! You win as follows:');
  644.         Show_win(line,'X');
  645.         game_over := TRUE
  646.       END;
  647.     line := line+1;
  648.   UNTIL game_over OR (line > 76);
  649.  
  650.   IF game_over=FALSE THEN
  651.     BEGIN
  652.       line := 1;
  653.       REPEAT  (* Check for machine 3 in line *)
  654.         IF line_sum[line] = 3 * machine THEN
  655.           BEGIN
  656.             Take_square(line);
  657.             Gotoxy(1,1);
  658.             WRITE('Machine moves and Wins as follows:');
  659.             Show_move;
  660.             Delay(2000);
  661.             Show_win(line,'O');
  662.             game_over := TRUE
  663.           END;
  664.         line := line+1;
  665.       UNTIL game_over OR (line > 76)
  666.     END;
  667.  
  668.   IF game_over=FALSE THEN
  669.     BEGIN
  670.       line := 1;
  671.       REPEAT  (* Check for player 3 in line *)
  672.         IF line_sum[line] = 3 * player THEN
  673.           BEGIN
  674.             Take_square(line);
  675.             Gotoxy(1,1);
  676.             WRITE('Nice try. Machine moves to:');
  677.             Show_move;
  678.             moved := TRUE
  679.           END;
  680.         line := line+1;
  681.       UNTIL moved OR (line > 76 )
  682.     END;
  683.  
  684.   IF hard_game AND (moved = FALSE) AND (game_over = FALSE) THEN
  685.     BEGIN
  686.       Multi_win;  (* Check for multi line win *)
  687.       IF moved=FALSE THEN
  688.         Check_planes;  (* Check for 4 player squares on a plane *)
  689.       Unflag  (* Restore flagged squares to empty *)
  690.     END;  (* IF hard_game *)
  691.  
  692.   IF (moved = FALSE) AND (game_over = FALSE) THEN
  693.     BEGIN  (* No priority moves are necessary, so pick the
  694.         next empty square from mach_move table *)
  695.       move := 1;
  696.       REPEAT
  697.         IF cube[mach_move[move]]=empty THEN
  698.           BEGIN
  699.             cube[mach_move[move]]:=machine;
  700.             square := mach_move[move];
  701.             gotoxy(1,1);
  702.             WRITE('Machine moves to:');
  703.             Show_move;
  704.             moved := TRUE
  705.           END;
  706.  
  707.         move := move+1
  708.       UNTIL (move=17) OR (moved=TRUE);
  709.     END;
  710.  
  711.   IF (moved = FALSE) AND (game_over = FALSE) THEN
  712.         BEGIN  (* All the squares in the mach_move table are
  713.                   full, so Pick any open square for machine *)
  714.           sqr := 1;
  715.           REPEAT
  716.             IF cube[sqr]=empty THEN
  717.               BEGIN
  718.                 cube[sqr]:=machine;
  719.                 square := sqr;
  720.                 Gotoxy(1,1);
  721.                 WRITE('Machine likes:');
  722.                 Show_move;
  723.                 moved:=TRUE
  724.               END;
  725.  
  726.            sqr := sqr+1;
  727.          UNTIL (sqr=65) OR (moved=TRUE);
  728.        END;
  729.  
  730.   IF (moved = FALSE) AND (game_over = FALSE) THEN
  731.     BEGIN  (* All squares are full, must be a tie game *)
  732.     Gotoxy(1,1);
  733.     WRITE('Tie game.')
  734.     END
  735.  
  736. END;  (* Machine_move *)
  737.  
  738. (****************)
  739. (* Main program *)
  740. (****************)
  741.  
  742. LABEL End_of_game;
  743. BEGIN    (* Main Program *)
  744.   REPEAT
  745.     Initialize;
  746.     Disp_cube;
  747.     square := 13;
  748.     REPEAT
  749.       Delay(1500);
  750.       Player_move;
  751.       Erase(23);
  752.       Erase(24);
  753.       Erase(1);
  754.       IF aborted THEN GOTO End_of_game;
  755.       Goto_square;
  756.       Delay(1500);
  757.       Machine_move;
  758.     UNTIL game_over;
  759.  
  760. End_of_game:
  761.     Erase(24); Erase(23);
  762.     WRITE('Would you like to play again? ');
  763.     READLN(reply);
  764.   UNTIL reply[1] IN ['N','n'];
  765.  
  766.   Erase(24);
  767.   Center('Good bye...')
  768. END.    (* Qubic *)
  769.