Introduction
Open_File Open a new maze input file.
Display_Maze Decode input maze into line drawing chars & display.
Rb_kbd.inc Get a key from user
Check_Move Check move validity: hitting a wall?
Move_It Move the piece from old to new location.
Move_Piece Decode movement commands.
}
{$I RB_KBD.INC} { Deciphers single keystroke inputs }
Const
Beep = #7; { Ring the bell Homer! }
ESC = #27;
M_Width = 80; { Maze width in character positions }
{ Must be an even number }
M_Depth = 24; { Maze depth in lines }
Namlgt = 255; { Max char length of a file name }
ShiftOut = 14; { ^N to invoke char set G1 }
ShiftIn = 15; { ^O to invoke char set G0 }
Type
Filename = String[Namlgt];
MazeLine = String[M_Width];
Var
Bumps : Integer; { Keep track of times bumped into wall}
Endx : Integer; { Ending column position }
Endy : Integer; { Ending line position }
Hor_Flip : Boolean; { Flip maze mirror image style }
In_Line : MazeLine;
Maze : Array[0..M_Depth] of MazeLine;
Maze_File : Filename; { input file contianing maze }
Maze_Lun : Text; { Maze file handle }
Maze_Num : Char; { Actually the letter designation }
Moves : Integer; { Keep track of number of moves }
NoMaze : Boolean; { Controls drawing of maze on screen }
OK : Boolean;
Py : Integer; { Current player line position }
Px : Integer; { Current player col position }
Vert_Flip : Boolean; { Flip maze upside down }
var Ch : char; { Character Pressed }
var F_Key : F_Key_Type; { Function Key Value }
var Ctrl_Key, {\ }
Shift_Key, { > True If On }
Lock_Key : boolean; {/ }
Begin
Writeln( ESC, '[2J', ESC,'[1;1H' );
Writeln( ESC, '#6 Welcome to Maze ver. 2, by Dave Cote' );
Writeln;
Writeln;
Writeln(' A Maze1a M Maze4a' );
Writeln(' B Maze1b N Maze4b' );
Writeln(' C Maze1c O Maze4c' );
Writeln(' D Maze1d P Maze4d' );
Writeln(' E Maze2a Q Maze5a' );
Writeln(' F Maze2b R Maze5b' );
Writeln(' G Maze2c S Maze5c' );
Writeln(' H Maze2d T Maze5d' );
Writeln(' I Maze3a U Maze6a' );
Writeln(' J Maze3b V Maze6b' );
Writeln(' K Maze3c W Maze6c' );
Writeln(' L Maze3d X Maze6d' );
Writeln;
Write(' Select a Maze, (A through X): ' );
If (Ch >= 'a') and (Ch <= 'z') Then Ch := chr( ord(Ch) - 32); { upcase }
Maze_Num := Ch;
If ((Ch >= 'E') and (Ch <= 'H')) Then Maze_File := 'Maze2.maz';
If ((Ch >= 'I') and (Ch <= 'L')) Then Maze_File := 'Maze3.maz';
If ((Ch >= 'M') and (Ch <= 'P')) Then Maze_File := 'Maze4.maz';
If ((Ch >= 'Q') and (Ch <= 'T')) Then Maze_File := 'Maze5.maz';
If ((Ch >= 'U') and (Ch <= 'X')) Then Maze_File := 'Maze6.maz';
Case ((ord(Ch) - ord('A')) mod 4) of
1: Vert_Flip := True;
2: Hor_Flip := True;
3: Begin
Vert_Flip := True;
Hor_Flip := True;
End;
End;
Writeln;
Write(' Do you want to play without drawing the maze (Y/N)? ');
RB_Kbd (Ch, F_Key, Ctrl_Key, Shift_Key, Lock_Key);
If (Ch = 'Y') or (Ch = 'y') Then NoMaze := True;
End; { of Proc. Introduction }
{*****************************************************************************}
Function Open_File( Filenm:Filename; Var File_Lun:Text ):Boolean;
{*****************************************************************************}
{ Generic input-file open/check routine. Given a filename in string 'Filenm'
try to open it, report failure if any, return logical name in 'File_Lun'.}
Var OK : Integer;
Begin
ASSIGN ( File_Lun, Filenm );
{$I-}
RESET ( File_Lun );
{$I+};
OK := IORESULT;
IF (OK = 0)
Then Open_File := True
Else
BEGIN
Open_File := False;
Write('The input data file ',Filenm );
Writeln(' could not be opened. IORESULT=',OK);
END;
{ set P_Line & P_Column to the current player position where 'S' is found }
Var
Line : Integer;
Ch : Char;
Col, Col2 : Integer;
N,S,E,W : Boolean;
Begin
Clrscr;
Writeln( ESC,'[2;1H', ESC,'[?8l' ); { place cursor, turnoff autorepeat }
If Vert_Flip { Read input file into internal array }
Then For Line := M_Depth-1 downto 1 do { Upside down }
Readln( Maze_Lun, Maze[Line] )
Else For Line := 1 to M_Depth do { Rightside up }
Readln( Maze_Lun, Maze[Line] );
If Hor_Flip { Make mirror image }
Then For Line := 1 to M_Depth do
Begin
Col2 := M_Width;
For Col := 1 to M_Width div 2 do
Begin
Ch := Maze[Line][Col];
Maze[Line][Col] := Maze[Line][Col2];
Maze[Line][Col2] := Ch;
Col2 := Col2 -1;
End;
End;
For Col := 1 to M_Width do
Begin
Maze[0][Col] := ' '; { Clear out line #0 }
Maze[M_Depth][Col] := ' '; { Clear out bottom line }
End;
For Line := 0 to M_Depth do
Begin
Maze[Line][1] := ' '; { Clear out leftmost column }
Maze[Line][M_Width] := ' '; { Clear out rightmost column }
End;
{ Convert '@' signs into appropriate line drawing characters }
{ at same time look for 'S'tart and 'E'nd locations }
For Line := 1 to M_Depth-1 do
For Col := 2 to M_Width-1 do
Begin
Ch := Maze[ Line ][ Col ];
If Ch <> ' ' Then { ignore spaces }
Begin
If (Ch = 'S') or (Ch = 's') { 'S'tart ? }
Then Begin Px := Col;
Py := Line;
Maze[ Line ][ Col ] := ' ';
End
Else If (Ch = 'E') or (Ch = 'e') { 'E'nd ? }
Then Begin Endx := Col;
Endy := Line;
Maze[ Line ][ Col ] := ' ';
End
Else { line segment, decode }
Begin
N := Maze[ Line-1 ][ Col ] <> ' '; { Check above pos }
S := Maze[ Line+1 ][ Col ] <> ' '; { Check below pos }
E := Maze[ Line ][ Col+1 ] <> ' '; { Check rightpos }
W := Maze[ Line ][ Col-1 ] <> ' '; { Check left pos }
If (N and S and E and W) Then Maze[Line][Col] := 'n'
Else If (N and S and E) Then Maze[Line][Col] := 't'
Else If (N and S and W) Then Maze[Line][Col] := 'u'
Else If (N and E and W) Then Maze[Line][Col] := 'v'
Else If (S and E and W) Then Maze[Line][Col] := 'w'
Else If (N and E) Then Maze[Line][Col] := 'm'
Else If (N and W) Then Maze[Line][Col] := 'j'
Else If (S and E) Then Maze[Line][Col] := 'l'
Else If (S and W) Then Maze[Line][Col] := 'k'
Else If (E or W) Then Maze[Line][Col] := 'q'
Else Maze[Line][Col] := 'x';
End;
End; { of "If Ch <> ' '" }
End; { of "For Col ..." loop }
Write( ESC, ')0', chr(ShiftOut) ); { invoke Line drawing set }
If not NoMaze
Then For Line := 1 to M_Depth-1 do { write Maze out to screen }
Writeln( Maze[ Line ] );
Write( ESC,'[',Endy:1,';',Endx:1,'H', ESC,'[5ma', ESC,'[0m' ); { End }
Write( ESC,'[',Py:1,';',Px:1,'H`' ); { Draw player's position }
Write( ESC,'[',Py:1,';',Px:1,'H' );
{ Check that new location doesn't bump into a wall }
Begin
Check_Move := False;
If (Newx < 2) or (Newx > M_Width-1) Then { out of bounds }
Else If (Newy < 1) or (Newy > M_Depth-1) Then { out of bounds }
Else If Maze[Newy][Newx] = ' ' Then Check_Move := True;
End; { of Func Check_Move }
{*****************************************************************************}
Procedure Move_It( Var Px, Py : Integer; Newx, Newy : Integer;
Direction : F_Key_Type; Var Done : Boolean );
{*****************************************************************************}
Var N : Integer;
Begin
Done := False;
Write( ESC,'[',Py:1,';',Px:1,'H.' ); { drop breadcrumb on previous pos }
Write( ESC,'[',Newy:1,';',Newx:1,'H`' ); { draw new position }
Write( ESC,'[',Newy:1,';',Newx:1,'H' ); { Reset cursor }
Px := Newx;
Py := Newy;
If (Px = Endx) and (Py = Endy) { are we done ? }
Then Begin
Done := True;
For N := 1 to 15 do Write(ESC,'[?5h', Beep, ESC,'[?5l');
End
Else Begin { stretch move }
If (Direction = _UpArrow)
Then Begin
If (Maze[Py-1][Px] = ' ') and (Py > 2) and
(Maze[Py][Px-1] <> ' ') and (Maze[Py][Px+1] <> ' ')
Then Move_It( Px, Py, Newx, Newy-1, Direction, Done );
End
Else If (Direction = _DownArrow)
Then Begin
If (Maze[Py+1][Px] = ' ') and (Py < M_Depth-1) and
(Maze[Py][Px-1] <> ' ') and (Maze[Py][Px+1] <> ' ')
Then Move_It( Px, Py, Newx, Newy+1, Direction, Done );
End
Else If (Direction = _LeftArrow)
Then Begin
If (Maze[Py][Px-1] = ' ') and (Px > 2) and
(Maze[Py-1][Px] <> ' ') and (Maze[Py+1][Px] <> ' ')
Then Move_It( Px, Py, Newx-1, Newy, Direction, Done );
End
Else If (Direction = _RightArrow)
Then Begin
If (Maze[Py][Px+1] = ' ') and (Px < M_Width-1) and
(Maze[Py-1][Px] <> ' ') and (Maze[Py+1][Px] <> ' ')
Then Move_It( Px, Py, Newx+1, Newy, Direction, Done );
End;
{ Get arrow key inputs or <EXIT> and process these commands }
{ F_Key will equal _Exit, _UpArrow, _DownArrow, _RightArrow, or _LeftArrow }
var Ch : char; { Character Pressed }
var F_Key : F_Key_Type; { Function Key Value }
var Ctrl_Key, {\ }
Shift_Key, { > True If On }
Lock_Key : boolean; {/ }
Done: Boolean;
Newx, Newy : Integer;
OK : Boolean;
If not done
Then Begin
Moves := Moves + 1;
OK := Check_Move( Newx, Newy );
If OK Then Move_It( Px, Py, Newx, Newy, F_Key, Done )
Else Begin
Write( Beep );
Bumps := Bumps + 1;
End;
End;
until Done;
End; { of Proc. Move_Piece }
{*****************************************************************************}
{ Main body of Maze program }
{*****************************************************************************}
Begin
Bumps := 0; { How many times did we bump into a wall ? }
Moves := 0; { How many moves have we made totally ? }
NoMaze := False;
Introduction;
OK := Open_File( Maze_File, Maze_Lun );
Display_Maze;
Move_Piece;
Write( ESC, ')B', chr(ShiftIn) ); { turn off Line drawing set }
Write( ESC,'[24;1H', ESC,'[?8h' ); { Reset cursor, turn on autorepeat }
Write( 'While playing maze ',Maze_Num );
Write(' you''ve bumped into ',Bumps:3,' walls during ',Moves:3,' moves!');
End. { ye absolute end of program }