| ECE291 |
Computer Engineering II |
Lockwood, Fall 1996 |
Machine Problem 3: The Maze (Part I)
| Assigned | Tuesday October 15 |
| Due Date | Tuesday, October 29 |
| Purpose: |
Recursion, Linking to C, Video
|
| Points | 50 |
Introduction
You are a mouse that has found itself in a maze. In this machine problem,
you will implement a program that allows the mouse to explore a
two-dimensional maze. The program allows manual movement though the maze
and an 'Auto-Solve' function that automatically finds the
solution the maze.
This machine problem highlights three important concepts. First, this machine
problem uses the I/O system of the computer. In particular, the Video
Graphics Adapter (VGA) will be used in color text-mode to graphically
see the top-down view of the maze. Secondly, this machine problem will
demonstrate one of the most important tree algorithms -- The Depth First Search
(DFS).
Thirdly, the movement routines of this machine problem will
demonstrate important concepts for computer animation.
This is the first part of a series of machine problems. By the end
of this project, we will build a three-dimensional multi-user appliation
for exploring a maze. In the next machine problem, you will implement
a three-dimensional view of the maze which provides the "mouses' eye-view"
of the maze-- i.e., the view that the mouse would see inside the maze.
Problem Description
This machine problem represents the maze using three methods.
The maze is defined by a standard text file called MAZE.DTA. The maze
has 80 columns and 23 rows. Walls are indicated with the '#' character.
Hallways are indicated by the ' ' (space) character.
The starting location in the maze is indicated with the 'S' character.
The end of the maze is indicated with the 'E' character.
The MAZE.DTA file can be edited with any text editor.
The only restriction on the file is that the walls must surround the maze
(i.e., all of row 0, row 22, column 0, and column 79 hold the '#' character).
Internally, our program will represent the maze as a byte array of
80 (columns) * 23 (rows) = 1840 (bytes) called _MAZE.
The size of the maze is defined as a constant called MAZESIZE.
The array is stored in left-to-right, top-to-bottom order -- i.e.,
offset zero of _MAZE holds the top-left byte of the maze and
offset MAZESIZE-1 holds the bottom-right element of _MAZE.
Each byte defines a hallway, a wall, an endpoint, or a decision point.
A decision point is a location in the maze where the mouse must decide which
way to travel (i.e., the hallway branches). The location of decisions
points are computed for you just after the maze is read from the file.
To view the maze, the VGA adapter is used in text mode.
In text mode, each character on the screen is represented by two bytes --
an attribute byte
and the ASCII character. The attribute byte determines the background color,
the foreground color, intensity, and a flag to determine if the character
should be blinking. Details of programming the VGA adapter were described
in lecture, detailed in the ECE291 lab manual, and appear in the textbook.
The following diagram is a screen-dump of the running program:
The location of the mouse is determined by a variable called _POS.
_POS is a word-sized (16-bit) integer defined as an
offset into _MAZE. For example, if the mouse is at row 5, column 7
of the maze, _POS would equal 80*5+7. The mouse can move NORTH,
EAST, SOUTH, or WEST. North is defined as the top of the screen.
The mouse is represented on the screen as a green smiley character.
Operation of MAZE
The best way to understand the MAZE is to play the MAZE.
There are four
modes of operation to this program: Manual, Turbo, AutoAdvance, and
AutoSolve. Modes can be selected by pressing the 'M' key, followed
by a number (0 to 3). In manual mode (M0), pressing the arrows keys will
advance you by one position. In turbo mode (M1), the mouse will run down
a hallway until hitting a wall. In AutoAdvance mode (M2), the mouse will
traverse down a hallway until hitting a decision point. In AutoSolve mode
(M3), the mouse will find the solution to the maze automatically.
The mode of the program is displayed at the top-center of the screen.
In modes 1-3, the speed of the mouse can be adjusted. The (+) and (-)
keys determine the delay rate. A larger rate slows the mouse, while a smaller
makes the mouse move faster. The delay rate is displayed at the top-right
of the screen.
You can exit the program by pressing 'Q' to quit.
Implementation
The program will be implemented as a combination of ASM and C routines.
The C program (mazec.c) is used to start the program, read
the maze data file (maze.dta), and calculate the location of the
decision points. The ASM routines are used to provide high-speed graphic
update and maze movement routines.
Because this is a class on assembly; you are only
responsible for writing the ASM routines.
The six ASM procedures that you will need to implement are described below.
There are working library versions of each of these procedures in
libmp3.lib. Unless otherwise noted, it is expected that
the routine will preserve the value of any register that is modified.
ShowMaze
- Purpose: Draw the maze on the screen. and indicate the
initial location of the mouse using the green smiley
character.
- Variables: Both _MAZE and _POS are read
but not modified
- Inputs: ES points to the segment address of
the video display memory.
- Useful Constants: MAZESIZE, HALL, WALL, DECPOS, ENDPOS,
HALLCH, WALLCH, DECCH, ENDCH, and SMILECH.
- Called by: _ShowMaze
- Registers: All preserved
- Description:
The maze can be drawn on the screen as follows:
For each byte of the maze, this routine should write a word to the video
buffer.
For your convienience, a number of constants have been defined
in maze.def. MAZESIZE defines the size of the
maze (in bytes). This contant is equal to
80 (columns) * 23 (rows) = 1840 (bytes).
For each element in the maze, this routine will draw an element on the screen.
Constants are also used to define the values of _MAZE elements
and their Attribute:Character values used on the screen.
A table lookup is an effecient method to map the byte-value of
_MAZE[index] to a Attribute:Character value used by
the video buffer. The mapping function is summarized below.
_MAZE Value (byte) |
Attribute:Character (word) |
Description |
| HALL | HALLCH | Black background |
| WALL | WALLCH | Red, Solid Box |
| DECPOS | DECCH | Decision Position - Blue crosshair (+) |
| VISPOS | VISCH | Visited Position - Green crosshair (+) |
| FINPOS | FINSH | Finished Position - Red crosshair (+) |
| ENDPOS | ENDCH | Yellow End-of-maze Marker (E) |
After drawing the maze, the routine also needs to draw the location
of the mouse (green smiley character). The variable _POS
holds the initial position (byte offset into the maze). The constant
SMILECH is the attribute:character value for the green smiley
character.
ShowMode
- Purpose: Display the current mode and rate at the top
of the screen.
- Variables: Both mazemode and mazedelay
are read but not modified
- Inputs: ES points to the segment address of
the video display memory.
- Called by: _ShowMaze when the program begins
and by _MazeManual when the user changes mazemode
or mazedelay.
- Registers: All preserved
- Description:
At the top of the screen, there are two boxes that display the mode
of the game and the delay value.
Mazemode indicates the mode of the game. Its value ranges from 0 to 3.
For each of these values, a text message should be printed to indicate the
mode. This message should be printed at the top, center of the screen
using yellow text on a blue background. The mappings between mazemode
and output values are as follows:
| MazeMode | Text String | Description |
| 0 | 'MANUAL' | Manual Mode |
| 1 | 'TURBO' | Turbo Mode |
| 2 | 'AUTOADV' | Auto-Advance |
| 3 | 'AUTOSLV' | Auto-Solve |
Mazedelay indicates the delay between movements. Its value ranges
from 0 to 255. At the top, right of the screen, the value should be printed
using the same text attributes as used for the mode message.
Adv
- Purpose: Advance position by one character (if possible)
- Variables: _MAZE read, _POS modified.
- Inputs: AL indicates direction (NORTH, EASH, SOUTH, WEST)
- Outputs:
- AL: unchanged (still holds current direction)
- AH: AH=0 indicates a valid move, AH=1 indicates invalid move
- SI: Original position of mouse
- DI: New position of mouse (after advancing)
- Description:
This routine allows the mouse to move. This procedure is called
with AL holding the desired direction (NORTH, EAST, SOUTH, or WEST).
A move is only possible as long as the new position in the maze is
NOT inside a wall or at the endpoint.
The current position of the mouse in the maze is determined by the
variable _POS. This value should always be returned in SI.
If a move is possible, the new position should be computed then stored
in _POS and returned in DI. Further, AH should be set to zero
to indicate a valid move.
If a move is not possible,
AH should be set to 1 and DI should return the original position.
(i.e., DI=SI=_POS).
UpdateTextScreen
- Purpose: Draw mouse at new position on the screen after an advance.
- Inputs:
- SI: Original Position of Mouse
- DI: New position of Mouse
- Outputs: Writes only to screen
- Description:
After advancing by a position, it is necessary to update the screen.
This routine provides an efficient alternative to redrawing the entire screen.
The mouse should be drawn at the new position given by DI. The mouse
should be removed from the old position given by SI. To remove the mouse,
you will need to access _MAZE to determine what element
should be drawn on the screen. Possible values of maze include:
WALL, ENDPOS, HALL, DECPOS, VISPOS, and FINPOS.
The mappings from characters in _MAZE to attribute:character
elements for the screen is the same as were used for ShowMaze.
AutoAdv
- Purpose: Advance the mouse through the maze until hitting
a decision point.
- Inputs: AL holds starting direction
- Outputs: AL holds final direciton
- Useful Constants: NORTH, EAST, SOUTH, WEST,
DECPOS, VISPOS, FINPOS, ENDPOS.
- Description:
This routine allows the mouse to move through hallways
and turn at corners of the maze. The mouse will continue to
explore the maze until it reaches an intersection (decision point)
or hits the end of the maze.
This routine should use Adv, UpdateTextScreen
and Delay to move though straight hallways.
When the mouse runs into a wall, it will turn and walk down the hallway
further. If the mouse reaches a dead-end, it turns around and returns
to the decision point where it started from.
Decision points may be colored by the AutoSolve function.
This function should stop at ANY decision point
(DECPOS, VISPOS, and FINPOS), or at the end
of the maze (ENDPOS). Register AL should return with the
direction of the mouse when it stopped.
AutoSolve
- Purpose: Automatically solve the maze
- Inputs: AL holds starting direction
- Description
This is a recursive procedure that calls itself,
AutoAdv, Adv, UpdateTextScreen,
and Delay to automatically solve the maze.
The mouse uses a depth-first-search to find it's way to the endpoint
of the maze. From a given starting point and direction, the mouse will
begin by walking deeper and deeper into the maze. When the mouse
hits a dead-end, it backs up, and explores another direction. In the
library function, the stuck mouse next tries walking to the right.
After fully exploring that region it next tries walking to the left.
If, exploring all possible directions does not lead to the solution, the
the mouse backs up the the previous decision point.
The depth-first-search works by labeling decision points
as unvisited, visited, or finished.
Initially all decisions points are unvisited.
When the algorithm reaches another unvisited decision point,
it marks it as visited and recursively walks deeper into the maze.
If it is found that no further progress can be made by
walking in any direction (i.e., all hallsways lead to a dead-end or to
an already-explored region of the maze), the decision point is labeled
as finished and the algorithm back-tracks to the previous
decision point. To avoid infinite looping, previously-visited decision
points (either visited or finished) are never re-explored.
A node is only revisited if it was necessary to back-track.
For our problem, decision points are colored blue, green, or red.
Constants are defined in maze.def to define the values
in _MAZE and the attribute:character value for the video display.
They three types of decision points are summarized below:
Decision-Point Type |
Color |
_MAZE value |
Attribute: Character |
| Unvisited | + Blue | DECPOS | DECCH |
| Visited | + Green | VISPOS | VISCH |
| Finished | + Red | FINPOS | FINCH |
Points
You earn points by replacing each subroutine with your own code.
Your score will be proportional to the percentage of the code that
your write yourself. The breakdown in points is given below. Your
routine MUST perform all functions of the subroutine to receive credit.
- ShowMaze: 10 pts
- ShowMode: 5 pts
- Adv: 8 pts
- UpdateTextScreen: 7 pts
- AutoAdv: 10 pts
- AutoSolve: 10 pts.
Starting Files
You will begin MP3 with the following files:
- MAZEC.EXE: A fully functional executable
program using library routines
- MAZE.DTA: The maze definition file.
- MAZE.DEF:
Useful constants defined for this program
- MAZEC.C: Complete source code the C program which reads
MAZE.DTA, determines the decision points, stores the
data in _MAZE, and initiates the program.
(You shouldn't need to modify this program)
- MAZE.ASM:
A starting point for the program. You are given
the routines for reading and processing keyboard input, calling
the other functions, delaying movement, and interfacing with the
C program.
(Add your routines here and comment out the EXTRN lines)
- MAKE.BAT: A short batch program which compiles, assembles, and links
the programs.
- LIB291.LIB: The standard ECE291 library routines.
(you can always use these routines freely)
- LIBMP3.LIB: Library versions of the six routines that you need
to write.
You can copy all of these files to your directory with the following command:
xcopy /s E:\ece291\mp3 F:\mp3
; Definition File for MAZE.ASM
; John Lockwood; 10/96
MAZESIZE EQU 1840
; MAP Elements
WALL EQU 0
ENDPOS EQU 1
HALL EQU 2
DECPOS EQU 3
VISPOS EQU 4
FINPOS EQU 5
; Direction Definitions
NORTH EQU 0
EAST EQU 1
SOUTH EQU 2
WEST EQU 3
; Keyboard Input Codes
NORTHKEY EQU 72
SOUTHKEY EQU 80
WESTKEY EQU 75
EASTKEY EQU 77
; Video Text Memory Segment (Store in ES)
VIDSEG EQU 0B800h
; Screen Display values
HALLCH EQU 0000000000100000b
WALLCH EQU 0000110011011011b
SMILECH EQU 0000101000000010b
ENDCH EQU 0000111001000101b
DECCH EQU 0000000100101011b
VISCH EQU 0000001000101011b
FINCH EQU 0000010000101011b
; Attribute Byte for Mode Display
LB EQU 00011110b ; Blue background; Bright yellow text
MODEMAN EQU 0
MODEADV EQU 1
MODEAUTOADV EQU 2
MODEAUTOSOLVE EQU 3
// Main program for the MAZE
// John Lockwood - 10/96
#include
#include
#define MAZEROWS 23
#define MAZECOLS 80
#define WALL 0x0
#define ENDPOS 0x1
#define HALL 0x2
#define DECPOS 0x3
#define NORTH 0
#define EAST 1
#define SOUTH 2
#define WEST 3
extern void far FXIT();
extern int far ShowMaze();
extern int far MazeManual();
extern unsigned char far MAZE;
extern int far POS;
ReadMaze(char* fname) {
FILE* fp;
int x, y, ch;
int position=0;
fp = fopen(fname,"r"); // Open Maze File
for (y=0; y
PAGE 75, 132
TITLE MP3:MAZE Your Name Date
; ================ Constants / Definitions / MACROs =====================
INCLUDE maze.def
; ================== PUBLIC Variables & Procedures ======================
; LIB291 Routines
EXTRN DOSXIT:near, KBDIN:near, BINASC:near, DSPMSG:near;
; External Routines (called from C)
PUBLIC _FXIT, _MazeManual, _ShowMaze
; Public variables (used by C Program and libmp3)
PUBLIC _POS, _MAZE
; Public variables (used by libmp3)
PUBLIC Movement, mazemode, mazedelay
; =================== External Library Procedures =======================
; LIBMP3 Routines (Comment these out as your write your own code)
EXTRN ShowMaze:near
EXTRN ShowMode:near
EXTRN UpdateTextScreen:near
EXTRN Adv:near
EXTRN AutoAdv:near
EXTRN AutoSolve:near
EXTRN ShowLibUse:near ; (called at the end of the program)
; ============================ Program Data =============================
CSEG segment public
assume cs:CSEG ,ds:CSEG
; ============================= Variables ===============================
; The values of _MAZE and _POS are read in by the C program
_MAZE db MAZESIZE dup ('M')
_POS dw 0
; By default, Start in Manual Mode
mazemode db 0
; Default Delay Period
mazedelay db 16
; Movement Offsets for fast table-lookup operation
movement dw -80,+1,+80,-1
; ================= Procedures (Your code goes here) ====================
; ShowMaze PROC NEAR
; Purpose: (1) Draw initial Maze on screen,
; (2) Show initial Position of mouse (Smiley Character)
; Variables: _MAZE, _POS, mazemode, mazedelay (no variables modified)
; ShowMaze ENDP
; ------------------------------------------------------------------------
; ShowMode PROC NEAR
; ShowMode ENDP
; ------------------------------------------------------------------------
; Adv PROC NEAR
; Adv ENDP
; ------------------------------------------------------------------------
; UpdateTextScreen PROC NEAR
; UpdateTextScreen ENDP
; ------------------------------------------------------------------------
; AutoAdv PROC NEAR
; AutoAdv ENDP
; ------------------------------------------------------------------------
; AutoSolve PROC NEAR
; AutoSolve ENDP
; ============================== Free Code ==============================
_ShowMaze PROC FAR
; Purpose: (1) Draw initial Maze on screen,
; (2) Show initial Position of mouse (Smiley Character)
; (3) Show initial Mode
; Variables: _MAZE, _POS, mazemode, mazedelay (no variables modified)
PUSH DS
PUSH ES
MOV AX,CS ; Our DS=CS
MOV DS,AX
MOV AX,VIDSEG ; Use ES=Video Segment
MOV ES,AX
Call ShowMaze ; Display original maze and mouse on screen
Call ShowMode ; Display mazemode and mazedelay values on screen
POP ES
POP DS
RET
_ShowMaze ENDP
; ------------------------------------------------------------------------
_MazeManual PROC FAR
; Purpose: Main Program (Called from C and calls to all other routines)
; Interactively allows user to traverse maze and run AutoSolve
; Variables: _MAZE, mazemode, mazedelay
; Input: From keyboard
; Output: None. Preserves ALL registers (else the C program WILL crash)
PUSH DS
PUSH ES
PUSH SI
PUSH DI
PUSH BX
MOV AX,CS ; Our DS=CS
MOV DS,AX
MOV AX,VIDSEG ; Use ES=Video Segment
MOV ES,AX
MMLoop: Call KBDIN
CMP AL,'Q'
JE MMDone
CMP AL,'q'
JE MMDone
CMP AL,NORTHKEY
JE MMNorth
CMP AL,SOUTHKEY
JE MMSouth
CMP AL,WESTKEY
JE MMWest
CMP AL,EASTKEY
JE MMEast
CMP AL,'M'
JE MMode
CMP AL,'m'
JE MMode
CMP AL,'+'
JE MMSlower
CMP AL,'-'
JE MMFaster
JMP MMLoop
; Check for Keyboard Arrow Keys (up, down, left, right)
MMNorth: MOV AL,NORTH
JMP MMArrow
MMSouth: MOV AL,SOUTH
JMP MMArrow
MMWest: MOV AL,WEST
JMP MMArrow
MMEast: MOV AL,EAST
JMP MMArrow
; Set Game Mode ('M0','M1','M2','M3')
MMode: Call KBDIN
CMP AL,'0'
JB MMLoop
CMP AL,'3'
JA MMLoop
SUB AL,'0'
MOV mazemode,AL
Call ShowMode
JMP MMLoop
; Control Interactive Speed (Smaller Mazedelay==Faster)
MMFaster: DEC mazedelay
Call ShowMode
JMP MMLoop
MMSlower: INC mazedelay
Call Showmode
JMP MMLoop
MMArrow: CMP mazemode,3
JE MMASolve
CMP mazemode,2
JE MMAutoAdv
MMAdv: Call Adv
Call UpdateTextScreen
CMP mazemode,0
JE MMLoop
CMP _MAZE[DI],HALL
JNE MMLoop
CMP AH,1
JE MMLoop
Call delay
JMP MMAdv
MMAutoAdv: Call AutoAdv
JMP MMLoop
MMASolve: Call AutoSolve
JMP MMLoop
MMDone: Call ShowLibUse
MOV AX,0 ; Return value
POP BX
POP DI
POP SI
POP ES
POP DS
RET
_MazeManual ENDP
; ------------------------------------------------------------------------
Delay PROC NEAR
; Purpose: Burn CPU cycles between movements
; Inputs: variable mazedelay (0..255) - Delay constant
; Outputs: None - All Registers Preserved
; Notes: There is no need to modify this code (it is given for free)
CMP mazedelay,0
JE DLoopNone
PUSH CX
MOV CX,0FFFFh
DLoop: PUSH CX
MOV CH,0
MOV CL,mazedelay
DLoop2: NOP
LOOP DLoop2
POP CX
LOOP DLoop
POP CX
DLoopNone: ret
Delay ENDP
; ------------------------------------------------------------------------
_FXIT PROC FAR
; Purpose: Terminate program and return to DOS.
; This should be the Last function called by the C program
; Notes: There is no need to modify this code (it is given for free)
CALL DOSXIT
_FXIT ENDP
; ===================== End of Proceures & Data ==========================
CSEG ends
end