home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MADTRB28.ZIP / MAZE1LVL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1986-03-23  |  14.3 KB  |  554 lines

  1. PROGRAM Maze;
  2.     {adapted from "Advanced Pascal Programming Techniques"
  3.     by  Paul A. Sand
  4.     }
  5.  
  6.   CONST
  7.     MAXMAZECOLS = 79;
  8.     MaxMazeRows = 22;
  9.     MaxCRTCol = 80;
  10.     MaxCRTRow = 25;
  11.     (* =====  MONO attributes A ==== *)
  12. (*    NewPath = LightGray;     { Maze is "LowVideo" color.  Path out }
  13.     BadPath = black;         {  is "HighVideo".  Reject paths are  }
  14.     OutPath = white;         {  simply erased from the screen.     }
  15.     BakGrnd = black;*)
  16.     (* =====  MONO attributes B ==== *)
  17. (*    NewPath = White;         { Maze is "HighVideo" color.  Path out  }
  18.     BadPath = lightGray;     {  is reverse video -- kind of ugly.    }
  19.     OutPath = black;         {  Rejected paths are set to "LowVideo".}
  20.     BakGrnd = lightGray;*)
  21.     (* =====  COLOR attributes  ==== *)
  22.     NewPath = Brown;      { In color, it works fine.}
  23.     OutPath = LightRed;
  24.     BadPath = DarkGray;
  25.     BakGrnd = Black;
  26.   TYPE
  27.     direction = (North, South, West, East, Out);
  28.     dirset    = set of direction;
  29.     MazeArray = ARRAY[0..MaxMazeRows, 0..MaxMazeCols] OF DirSet;
  30.     register = record
  31.       ax, bx, cx, dx, bp, si, ds, es, flags: Integer;
  32.       end;
  33.  
  34.   VAR
  35.     Maze : mazeArray;
  36.     Got_Out : Boolean;
  37.     CH : Char;
  38.     MazeRows,
  39.     MazeCols : Integer;
  40.     DisplayPaths : Boolean;
  41.  
  42.  
  43. {.cp 32}
  44. PROCEDURE GetParameters(Var MazeRows : Integer;
  45.                         Var MazeCols : Integer;
  46.                     Var DisplayPaths : Boolean);
  47. {
  48.      Obtains the parameters for the dimensions of the current maze and
  49.      whether or not to display the paths while creating it.
  50. }
  51. VAR
  52.   InString : String[4];
  53.   ch : Char;
  54.   ErrorCode : Integer;
  55.  
  56. BEGIN  { GetParameters }
  57. ClrScr;
  58. Repeat
  59.   Write('Number of Rows [5..23]: ');
  60.   Readln(InString);
  61.   Val(InString, MazeRows, ErrorCode);
  62. Until (ErrorCode = 0) and (MazeRows in [5..23]);
  63. MazeRows := MazeRows - 1;
  64. Repeat
  65.   Write('Number of Columns [5..80]: ');
  66.   Readln(InString);
  67.   Val(InString, MazeCols, ErrorCode);
  68. Until (ErrorCode = 0) and (MazeCols in [5..80]);
  69. MazeCols := MazeCols - 1;
  70. Repeat
  71.   Write('Display Paths? ');
  72.   Readln(Ch);
  73.   DisplayPaths := Ch in ['y', 'Y'];
  74. Until ch in ['y', 'Y', 'n', 'N'];
  75. END;  { GetParameters }
  76.  
  77.  
  78. {.cp 14}
  79. PROCEDURE RemoveCursor;
  80. {
  81.      Removes the distracting cursor from the screen during drawing activity.
  82. }
  83. VAR
  84.   regs : register;
  85.  
  86. BEGIN  { RemoveCursor }
  87. with regs do begin
  88.   ax := $0100;
  89.   cx := (32 shl 8) or 32;              { Don't know why these numbers work   }
  90.   Intr($10, regs);                     {   but they do                       }
  91.   end;
  92. END;  { RemoveCursor }
  93.  
  94.  
  95. {.cp 14}
  96. PROCEDURE RestoreCursor;
  97. {
  98.      Returns the cursor to the screen.
  99. }
  100. VAR
  101.   regs : register;
  102.  
  103. BEGIN  { RestoreCursor }
  104. with regs do begin
  105.   ax := $0100;
  106.   cx := (6 shl 8) or 7;
  107.   Intr($10, regs);
  108.   end;
  109. END;  { RestoreCursor }
  110.  
  111.  
  112. {.cp 13}
  113. FUNCTION num_of(VAR D): byte;
  114. {
  115.       This function takes advantage of the fact that the elements
  116.       of a set are represented by setting BITS within the SET
  117.       variable.  If the first item is present in the set, the
  118.       first bit will be a 1.
  119. }
  120. VAR
  121.   X : byte absolute D;
  122.  
  123. BEGIN  { Num_of }
  124. num_of := X;
  125. END;
  126.  
  127.  
  128. {.cp 7}
  129. PROCEDURE Mark_Square(CH: Char;
  130.                      row,
  131.                      col: Integer);
  132. BEGIN  { Mark_Square }
  133. GoToXY(col+1, row+1);
  134. Write(CH);
  135. END;           { procedure Mark_Square(CH : char; row,col : integer) }
  136.  
  137.  
  138. {.cp 28}
  139. PROCEDURE SetSquare(row,
  140.                     col: Integer;
  141.                      wp: DirSet);
  142. BEGIN  { Set_Square }
  143. maze[row, col] := wp;
  144. if out in WP then
  145.   TextColor(Yellow + Blink);
  146. if (out in wp) or (DisplayPaths) then
  147.   CASE (Num_Of(wp) and $F) OF
  148.     0 : Mark_Square(' ', row, col);
  149.     1 : Mark_Square(chr(223), row, col);
  150.     2 : Mark_Square(chr(220), row, col);
  151.     3 : Mark_Square(chr(186), row, col);
  152.     4 : Mark_Square(chr(221), row, col);
  153.     5 : Mark_Square(chr(188), row, col);
  154.     6 : Mark_Square(chr(187), row, col);
  155.     7 : Mark_Square(chr(185), row, col);
  156.     8 : Mark_Square(chr(222), row, col);
  157.     9 : Mark_Square(chr(200), row, col);
  158.     10: Mark_Square(chr(201), row, col);
  159.     11: Mark_Square(chr(204), row, col);
  160.     12: Mark_Square(chr(205), row, col);
  161.     13: Mark_Square(chr(202), row, col);
  162.     14: Mark_Square(chr(203), row, col);
  163.     15: Mark_Square(chr(206), row, col);
  164.     END;
  165. TextColor(NewPath);
  166. END;                    { procedure SetSquare() }
  167.  
  168.  
  169. {.pa}
  170. PROCEDURE CreateMaze(VAR Maze : MazeArray);
  171.       {CREATED:  11/24/1985}
  172. VAR
  173.      row, col : Integer;
  174.           dir : direction;
  175. SquareCounter : Integer;
  176. NestLevel     : Integer;
  177. MaxLevel      : Integer;
  178. InitialHeap   : Integer;
  179. MinHeap       : Integer;
  180.  
  181.  
  182. FUNCTION randdir : direction;
  183. BEGIN
  184. CASE Random(4) OF
  185.   0 : randdir := North;
  186.   1 : randdir := South;
  187.   2 : randdir := West;
  188.   3 : randdir := East;
  189.   END;
  190. END;                    { function randdir }
  191.  
  192.  
  193. {.cp 26}
  194. FUNCTION legalPath(row, col : Integer; dir : direction) : Boolean;
  195.     (* ============================================================ *)
  196.     (* It's legal to extend the path in a given direction IFF that  *)
  197.     (* extension would NOT intersect an already-created path.       *)
  198.     (* ============================================================ *)
  199. VAR
  200.   legal : Boolean;
  201.  
  202. BEGIN  { LegalPath }
  203. legal := False;
  204. CASE dir OF
  205.   North :
  206.     IF row > 0 THEN
  207.       Legal := (maze[row-1, col] = []);
  208.   South :
  209.     IF row < MazeRows THEN
  210.       Legal := (maze[row+1, col] = []);
  211.   West  :
  212.     IF col > 0 THEN
  213.       Legal := (maze[row, col-1] = []);
  214.   East  :
  215.     IF col < MazeCols THEN
  216.       Legal := (maze[row, col+1] = []);
  217.   END;
  218. legalPath := legal;
  219. END;                    { function legalPath(row,col : integer; dir : direction) }
  220.  
  221.  
  222. {.cp 66}
  223. PROCEDURE BuildPath(row, col : Integer; dir : direction);
  224.     (* ============================================================ *)
  225.     (*  BuildPath is first called with a starting location and a    *)
  226.     (*  direction.  If it's legal to go in that direction, it does  *)
  227.     (*  so.  Then it attempts to BuildPath from the new location    *)
  228.     (*  in each of the four directions.  Highly recursive!          *)
  229.     (* ============================================================ *)
  230. VAR
  231.   unused : dirset;
  232.   ch     : char;
  233.  
  234. BEGIN  { BuildPath }
  235. NestLevel := NestLevel + 1;            { Keeps track of Recursion Level      }
  236. If NestLevel > MaxLevel then Begin
  237.   MaxLevel := NestLevel;
  238.   Gotoxy(28, 24);
  239.   Write(MaxLevel:4);
  240.   end;
  241. Gotoxy(18, 24);
  242. write(NestLevel:4);
  243. CASE dir OF
  244.   North : BEGIN
  245.     SetSquare(row, col, Maze[row,col] + [North]);
  246.     SetSquare(row-1, col, Maze[row-1,col] + [South]);
  247.     row := row-1;
  248.     END;
  249.   South : BEGIN
  250.     SetSquare(row, col, Maze[row,col] + [South]);
  251.     SetSquare(row+1, col, Maze[row+1,col] + [North]);
  252.     row := row+1;
  253.     END;
  254.   West : BEGIN
  255.     SetSquare(row, col, Maze[row,col] + [West] );
  256.     SetSquare(row, col-1, Maze[row,col-1] + [East]);
  257.     col := col-1;
  258.     END;
  259.   East : BEGIN
  260.     SetSquare(row, col, Maze[row,col] + [East]);
  261.     SetSquare(row, col+1, Maze[row,col+1] + [West]);
  262.     col := col+1;
  263.     END;
  264.   END;
  265. Unused := [North..East];
  266. SquareCounter := SquareCounter + 1;
  267. If (SquareCounter Mod 10) = 0 then BEGIN
  268.   Gotoxy(18, 25);
  269.   Write(SquareCounter:4);
  270.   END;
  271.  
  272. REPEAT
  273.   dir := randdir;
  274.   IF Dir IN unused THEN BEGIN
  275.     unused := unused-[dir];
  276.     IF LegalPath(row, col, dir) THEN
  277.       BuildPath(row, col, dir);    {<< note the recursive call!}
  278.   END;
  279. UNTIL unused = [];
  280. NestLevel := NestLevel - 1;
  281. Gotoxy(18, 24);
  282. write(NestLevel:4);
  283. If MemAvail < MinHeap then Begin
  284.   MinHeap := MemAvail;
  285.   Gotoxy(75, 24);
  286.   write(MinHeap:5);
  287.   end;
  288. END;                    { procedure BuildPath(row,col : integer; dir : direction) }
  289.  
  290.  
  291. {.cp 45}
  292. BEGIN  { CreateMaze }
  293. Nestlevel := 0;
  294. MaxLevel := 0;
  295. Gotoxy(1, 24);
  296. write('Recursion Level:      Max:');
  297. Gotoxy(36, 24);
  298. Write('Available Heap - Initial:       Min:');
  299. Gotoxy(62, 24);
  300. InitialHeap := MemAvail;
  301. MinHeap := InitialHeap;
  302. write(InitialHeap:5);
  303. SquareCounter := 0;
  304. FillChar(Maze, SizeOf(Maze),0);
  305. RemoveCursor;
  306. gotoxy(1,25);
  307. Write('Creating maze... ', SquareCounter:4, ' of ');
  308. Write((MazeRows+1) * (MazeCols+1):4, ' Squares defined.');
  309. col := random(MazeCols);
  310. row := random(MazeRows);
  311. REPEAT
  312.   dir := randdir
  313. UNTIL LegalPath(row, col, dir);
  314. buildPath(row, col, dir);
  315. {Now make an exit -- or don't!}
  316. case random(16) of
  317.   0..3: begin {North exit}
  318.     col := Random(MazeCols);
  319.     SetSquare(0, col, Maze[0,col] + [out,North]);
  320.     end;
  321.   4..7: begin {South exit}
  322.     col := random(MazeCols);
  323.     SetSquare(MazeRows,col, Maze[MazeRows,col] + [out,South]);
  324.     end;
  325.   8..11: begin {West exit}
  326.     row := random(MazeRows);
  327.     SetSquare(row,0, Maze[row,0] + [out,West]);
  328.     end;
  329.   12..15: begin {East exit}
  330.     row := random(MazeRows);
  331.     SetSquare(row,MazeCols, Maze[row,MazeCols] + [out,East]);
  332.     end;
  333. (*  16:; {no exit} *)                  { Eliminated no exit option }
  334.   end;
  335. RestoreCursor;
  336. END;                      { procedure CreateMaze(VAR Maze : MazeArray) }
  337.  
  338.  
  339. {.pa}
  340. FUNCTION SolveMaze(VAR Maze : MazeArray) : Boolean;
  341.  
  342. VAR
  343.   Solved    : Boolean;
  344.   row, col  : Integer;
  345.   tried     : ARRAY[0..MaxMazeRows, 0..MaxmazeCols] OF Boolean;
  346.   AutoSolve : Boolean;
  347.   Ch        : Char;
  348.  
  349.  
  350. FUNCTION try(row, col : Integer;
  351.                   dir : direction) : Boolean;
  352.  
  353. VAR
  354.   ok : Boolean;
  355.  
  356.  
  357. PROCEDURE Mark_Forward(row, col : Integer);
  358. BEGIN
  359. TextColor(OutPath);
  360. SetSquare(row,col,Maze[row,col]);
  361. END;       { procedure Mark_Forward(row,col : integer; dir : direction) }
  362.  
  363.  
  364. PROCEDURE Mark_Backward(row, col : Integer);
  365. BEGIN
  366. TextColor(BadPath);
  367. SetSquare(row,col,Maze[row,col]);
  368. END;                  { procedure Mark_Backward(row,col : integer); }
  369.  
  370. {.cp 30}
  371. BEGIN  { Try }
  372. (*        delay(20); *)
  373. ok := (dir in maze[row, col]);
  374. IF OK THEN BEGIN
  375.   tried[row, col] := True;
  376.   CASE dir OF
  377.     North : row := row-1;
  378.     South : row := row+1;
  379.     West  : col := col-1;
  380.     East  : col := col+1;
  381.     END;
  382.   OK :=  (NOT tried[row, col]);
  383.   IF OK THEN BEGIN
  384.     Mark_Forward(row, col);
  385.     OK := out in maze[row,col];
  386.     IF NOT OK THEN
  387.       OK := try(row, col, West);
  388.     IF NOT OK THEN
  389.       OK := try(row, col, South);
  390.     IF NOT OK THEN
  391.       OK := try(row, col, East);
  392.     IF NOT OK THEN
  393.       OK := try(row, col, North);
  394.     IF NOT OK THEN
  395.       Mark_Backward(row, col);
  396.     END;
  397.   END;
  398. try := ok;
  399. END;                { function try(row,col:integer; dir : direction) }
  400.  
  401. {.pa}
  402. FUNCTION SolvedItMyself: Boolean;
  403. {
  404.      Allows the more adventurous among you to solve the maze yourself
  405.      using the arrow keys to move around.  For all you cowards, 'Q' allows
  406.      you to quit early.
  407. }
  408. VAR
  409.   Success   : Boolean;                 { Have you done it or not ?           }
  410.   NewDir    : Direction;               { Direction selected by adventurer    }
  411.   ScanCode  : Byte;                    { Code of keystroke                   }
  412.  
  413.  
  414. {.cp 21}
  415. FUNCTION KeyStroke: Byte;
  416. {
  417.      Calls DOS Interrupt 16 to get the scan code of the keystroke.  The
  418.      returned value is used to determine the legality of the key struck and
  419.      the direction it selects.
  420. }
  421.  
  422. VAR
  423.   regs : register;
  424.  
  425. BEGIN  { KeyStroke }
  426. with regs do begin
  427.   ax := $0000;
  428.   Intr($16, regs);
  429.   KeyStroke := Hi(ax);
  430.   end;
  431. END;  { KeyStroke }
  432.  
  433.  
  434. {.cp 39}
  435. BEGIN  { SolvedItMyself }
  436. GoToxy(1, MaxCrtRow);
  437. ClrEol;
  438. Write('Use arrow keys to solve maze or "Q" to quit.');
  439. success := false;
  440. TextColor(Yellow);
  441. REPEAT
  442.   ScanCode := KeyStroke;
  443.   If not (ScanCode in [16, 72, 75, 77, 80]) then
  444.     write(chr(7))
  445.   else begin
  446.     case ScanCode of
  447.       16 :  begin
  448.         SolvedItMyself := false;
  449.         exit;
  450.         end;
  451.       72 :  NewDir := North;
  452.       75 :  NewDir := West;
  453.       77 :  NewDir := East;
  454.       80 :  NewDir := South;
  455.       end;
  456.     if (NewDir in Maze[row, col]) then begin
  457.       SetSquare(row, col, Maze[row, col]);
  458.       case NewDir of
  459.         North : row := row - 1;
  460.         West  : col := col - 1;
  461.         East  : col := col + 1;
  462.         South : row := row + 1;
  463.         end;
  464.       TextColor(NewPath + Blink);
  465.       SetSquare(row, col, Maze[row, col]);
  466.       success := out in Maze[row, col];
  467.       end
  468.     else
  469.       write(chr(7));
  470.     end;
  471. UNTIL success;
  472. SolvedItMyself := success;
  473. END;  { SolvedItMyself }
  474.  
  475.  
  476. {.cp 39}
  477. BEGIN  { SolveMaze }
  478. Displaypaths := true;
  479. FOR row := 0 TO MazeRows DO
  480.   FOR col := 0 TO MazeCols DO
  481.     tried[row, col] := False;
  482. col := 2 * (Random((MazeCols DIV 2) - 1)) + 1;
  483. row := 2 * (Random((MazeRows DIV 2) - 1)) + 1;
  484. TextColor(Yellow);
  485. SetSquare(row, col, Maze[row,col]);
  486. TextColor(NewPath);
  487. REPEAT
  488.   GoToXY(1, MaxCRTRow);
  489.   ClrEol;
  490.   Write('Print maze [P] or Continue [C]? ');
  491.   Read(kbd, ch);
  492.   If ch in ['p','P'] then
  493.   begin
  494.     Write(Lst,chr(27),chr(37),chr(1),chr(0));
  495.     Write(Lst,chr(27),chr(65),chr(8));
  496.     GoToXY(1,MaxCRTRow);
  497.     ClrEol;
  498.     Write('Press the PrtSc key and then press Return.');
  499.     Read(kbd,ch);
  500.     write(Lst,chr(27),chr(37),chr(0),chr(0));
  501.     write(Lst,chr(27),Chr(50));
  502.   end;
  503. UNTIL (Ch in ['c', 'C']);
  504. REPEAT
  505.   GoToXY(1, MaxCRTRow);
  506.   ClrEol;
  507.   Write('Solve Manually [M] or Automatically [A]? ');
  508.   Read(kbd, ch);
  509.   AutoSolve := (Ch in ['a', 'A']);
  510. UNTIL (Ch in ['a', 'A', 'm', 'M']);
  511. write(ch);
  512. RemoveCursor;
  513. solved := out in Maze[row,col];
  514. If not solved then
  515.   if AutoSolve then begin
  516.     GoToXY(1, MaxCRTRow);
  517.     ClrEol;
  518.     Write('Press a Key to begin AutoSolve Mode...');
  519.     REPEAT UNTIL KeyPressed; Read(Kbd);
  520.     if not solved then
  521.       solved := try(row, col, East);
  522.     if not solved then
  523.       solved := try(row,col,West);
  524.     if not solved then
  525.       solved := try(row,col,North);
  526.     if not solved then
  527.       solved := try(row,col,South);
  528.     end else
  529.       solved := SolvedItMyself;
  530. SolveMaze := solved;
  531. RestoreCursor;
  532. END;                      { function SolveMaze(VAR Maze:MazeArray) }
  533.  
  534. {.pa}
  535. BEGIN  { Main Program }
  536. Randomize;
  537. REPEAT
  538.   TextBackground(bakGrnd);
  539.   TextColor(NewPath);
  540.   GetParameters(MazeRows, MazeCols, DisplayPaths);
  541.   ClrScr;
  542.   CreateMaze(Maze);
  543.   Got_Out := SolveMaze(Maze);
  544.   GoToXY(1, MaxCRTRow); ClrEOL;
  545.   IF Got_Out THEN Write('SUCCEEDED!  ')
  546.   ELSE Write('FAILED . . .');
  547.   Write('<C> to continue, <Q> to quit');
  548.   REPEAT UNTIL KeyPressed;
  549.   Read(Kbd, CH);
  550. UNTIL UpCase(CH) = 'Q';
  551. ClrScr;
  552. END.
  553.  
  554.