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
Points50

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

ShowMode

Adv

UpdateTextScreen

AutoAdv

AutoSolve

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.

Starting Files

You will begin MP3 with the following files: You can copy all of these files to your directory with the following command:

xcopy /s E:\ece291\mp3 F:\mp3

MAZE.DEF

; 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

MAZEC.C

// Main program for the MAZE // John Lockwood - 10/96 #include <stdlib.h> #include <stdio.h> #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<MAZEROWS; y++) { for (x=0; ch!=EOF && x<MAZECOLS; x++) { ch = getc(fp); switch (ch) { case '#': *(&MAZE+position) = WALL; // Wall break; case ' ': *(&MAZE+position) = HALL; // Hallway break; case 'S': *(&MAZE+position) = HALL; // Starting Position POS = position; break; case 'E': *(&MAZE+position) = ENDPOS; break; default: *(&MAZE+position) = HALL; // Any other character (?) } position++; } while ((ch=getc(fp))!=10 && ch!=EOF); // Ignore any junk characters after 80th col } fclose(fp); } ProcessMaze() { int x, y, wallctr, position; for (y=1; y<(MAZEROWS-1); y++) for (x=1; x<(MAZECOLS-1); x++) { position=x+MAZECOLS*y; if (*(&MAZE+position) == HALL) { wallctr=0; if (*(&MAZE+position+1)==WALL) wallctr++; if (*(&MAZE+position-1)==WALL) wallctr++; if (*(&MAZE+position+MAZECOLS)==WALL) wallctr++; if (*(&MAZE+position-MAZECOLS)==WALL) wallctr++; if (wallctr<2) *(&MAZE+position) = DECPOS; } } } main() { ReadMaze("MAZE.DTA"); ProcessMaze(); ShowMaze(); MazeManual(); FXIT(); }

MAZE.ASM

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