Systems Fundamentals I Homework Assignment #4 solved



Welcome to the Dungeon!
In this homework you will continue to work with 2D arrays, while also learning the basics of working with files
in MIPS and implementing algorithms that use the stack for computations.
You will be implementing a game called MipsHack, inspired by the 1987 ASCII game NetHack. Our intrepid
hero, Sir CodesALot, has entered a deep, dark dungeon in search of riches. He will need to find his way out, while
defeating enemies and filling his sack with loot! His objective is to collect at least 3 coins of treasure and escape
to the surface without getting killed.
Let the adventure begin!
Data Structures
The game relies on two data structures, primarily:
• a struct for representing the game world, and
• a struct for representing the player
The Map struct has the following definition:
struct Map {
unsigned byte num_rows; // byte #0
unsigned byte num_cols; // byte #1
unsigned byte cells[][]; // bytes #2 through #num_rows*num_cols+1
}
As implied in the definition, a Map specifies a rectangular region, where cells[0][0] is the upper-left corner
of the map and cells[num rows-1][num cols-1] is the lower-right corner. Each element (byte) in the
cells[][] array stores a 7-bit ASCII character in the lowest 7 bits. The most significant bit of a cell indicates
whether the cell is hidden (1) or not (0) from the player. Valid ASCII characters include the following:
@ Sir CodesALot, our hero
. empty floor
# a wall
/ a door
a dungeon exit
$ a single coin
* a gem, worth 5 coins
m a minion monster
B a boss monster
? inaccessible area (should always be hidden)
The Player struct has the following definition:
struct Player {
unsigned byte row; // byte #0 (unsigned)
unsigned byte col; // byte #1 (unsigned)
byte health; // byte #2 (signed)
unsigned byte coins; // byte #3 (unsigned)
}
The player’s position in the game map is row,col. Provided that Sir CodesALot’s health is greater than 0, he is
still alive and can continue to adventure in the dungeon.
File Format
The game map and other initial game state are stored in a plaintext file with a fixed format:
NUM_ROWS
NUM_COLS
MAP_DATA
STARTING_HEALTH
Every line ends with a ’\n’ character, which is a UNIX-style line ending. When you create plaintext files in
Windows, the OS will end each line with the two-character combination ’\r\n’. This WILL cause problems
for students who make custom maps in Windows. A solution is explained in the specification for the init game
function below.
As an example of how this file format is used, here is the contents of the 7-row, 25-column game world in
map3.txt file provided with this PDF:
07
25
###############???####??
#.....m.m......#???#..#??
#.....m*m......#####..###
#[email protected]/........#
#...........$..#####....#
#..B...........#???#....#
################???######
10
Note that any numbers in the file are given as two ASCII digit characters. Your code will need to perform the
required conversions to 4-byte integers.
File I/O in MIPS Assembly
To assist with reading and writing files, MARS has several system calls:
Code
Service in $v0 Arguments Results
open file 13 $a0 = address of null-terminated filename string
$v0 contains file descriptor
(negative if error)
$a1 = flags
$a2 = mode
read from file 14 $a0 = file descriptor $v0 contains # of characters read
$a1 = address of input buffer (0 if end-of-file, negative if error)
$a2 = maximum # of characters to read
close file 16 $a0 = file descriptor
Service 13: MARS implements three flag values: 0 for read-only, 1 for write-only with create, and 9 for writeonly with create and append. It ignores mode. The returned file descriptor will be negative if the operation
failed. MARS maintains file descriptors internally and allocates them starting with 3. File descriptors 0, 1 and
2 are always open for reading from standard input, writing to standard output, and writing to standard error,
respectively. An example of how to use these syscalls can be found on the MARS syscall web page.
Main File
We have provided you part of a main file and game loop in hw4 main.asm. We encourage you to add to it and
write a few helper functions like print map and print player info. The provided main has fixed sizes
for the map and visited structs. You will need to manually set the sizes of these arrays depending on which
map file you load. Guidance on how large to set these arrays is given in the main file.
Here is the general flow of what your main file should look like:
print "welcome" message
zero-out the map and player structs
filename = "map3.txt" # or other file
init_game(filename, map_ptr, player_ptr) # assuming successful execution
reveal_area(map_ptr, player_ptr.row, player_ptr.col)
move = 0
while player_ptr.health 0 and move == 0: # 0 means keep playing
print_map() # these functions take no arguments because the
print_player_info() # map and player structs are available globally
char = read 1 char from the keyboard
move = 0
if char == ’w’ then
move = player_turn(map_ptr, player_ptr, ’U’)
elif char == ’a’ then
move = player_turn(map_ptr, player_ptr, ’L’)
elif char == ’s’ then
move = player_turn(map_ptr, player_ptr, ’D’)
elif char == ’d’ then
move = player_turn(map_ptr, player_ptr, ’R’)
elif char == ’r’ then
flood_fill_reveal(map_ptr, player_ptr.row, player_ptr.col, visited)
if move == 0 then
reveal_area(map_ptr, player_ptr.row, player_ptr.col)
print_map()
if player_ptr.coins = 3 and player_ptr.health 0:
print "congratulations" message
else:
if player_ptr.health <= 0:
print "you died" message
else:
print "you failed" message
print_player_info()
Hint: when you are writing the print map function, as you load characters out of the map, if the character has 1
for the hidden flag, print a space instead of the character you loaded. Otherwise, assuming the character is visible,
simply print it using system call 11.
A Reminder on How Your Work Will be Graded
It is imperative (crucial, essential, necessary, critically important) that you implement the functions below
exactly as specified. Do not deviate from the specifications, even if you think you are implementing the
game in a better way. Modify the contents of memory only as described in the function specifications!
Remember how your work will be graded: we will test each function individually. We will not be playing
your game and watching things unfold – you will not even be submitting your main files, remember.
Part I: Initialize Game Data Structures
int init game(string map filename, Map *map ptr, Player *player ptr)
This function opens (syscall 13), reads (syscall 14), processes and then closes (syscall 16) the file named
map filename, which contains the starting game information. You may assume that the input file is always
formatted properly. The function reads the number of rows and columns from the game map and stores them at
bytes 0 and 1, respectively, of the Map struct that map ptr points to. It then proceeds to read the contents of the
game world, character-by-character. As it reads each character, the function sets the “hidden” flag at bit number
7 (the most significant bit) of the character before writing the character to memory. Note that these characters are
written to the Map struct starting at byte 2. Every character in the map is hidden initially. The bytes of the map
are stored in row-major order.
At some point while reading the map contents, the function will encounter the @ character. The function writes the
row and column numbers of the @ character as bytes 0 and 1, respectively, of the Player struct that player ptr
points to. At the end of the file the function will find the starting health of the player. It writes that value at byte 2
of the Player struct, and the number 0 at byte 3 of the Player struct to initialize the number of coins held by
the player to zero. Finally, the function closes the file.
Note that all numbers in the file are stored as two-digit ASCII characters, with leading zeroes as needed. For
example, in map3.txt, the number of columns in the map is twenty-five. This value is represented by the
ASCII characters ’2’ and ’5’ on line 2 of the file. You will need to perform the appropriate conversion to turn
this two-character string into an integer.
The function assumes that every line ends only with a ’\n’ character, not the two-character combination ’\r\n’
employed in Microsoft Windows. If you create your own maps for testing purposes, use MARS to edit the file.
If you are developing on a Windows computer, do not use a regular text editor like Notepad. Such an editor will
insert both characters. In contrast, MARS will insert only a ’\n’ at the end of each line, so only use MARS to
create custom maps.
The function takes the following arguments, in this order:
• map filename: A string the provides the filename of the file containing the map information and the
player’s starting helth.
• map ptr: A pointer to a Map struct that is large enough to store the dimensions of the map, as well as the
map contents.
• player ptr: A pointer to a Player struct that is large enough to store the four bytes that define the
player’s attributes.
Returns in $v0:
• 0 if the file was successfully opened and its contents were processed, or -1 for error.
Returns -1 in $v0 for error if a file with the name map filename could not be read off the disk.
Additional requirements:
• The function must not write any changes to main memory except as specified.
Example:
Suppose init game has been called with map3.txt as the filename. The Player and Map structs would be
initialized as follows, where the bytes of the game world are given in hexadecimal and all other values are given
in decimal. All values shown below are integers. Note that each byte in the cells array is ≥ 128 because all
cells are initially hidden:
player_ptr.row = 3
player_ptr.col = 2
player_ptr.health = 10
player_ptr.coins = 0
map_ptr.rows = 7
map_ptr.cols = 25
map_ptr.cells = [
A3 A3 A3 A3 A3 A3 A3 BE A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 AE AE AE AE AE ED AE ED AE AE AE AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
A3 AE AE AE AE AE ED AA ED AE AE AE AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
A3 AE C0 AE AE AE ED ED ED AE AE AE AE AE AE AF AE AE AE AE AE AE AE AE A3
A3 AE AE AE ED AE AE AE AE AE AE AE A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE C2 AE AE AE AE AE AE AE AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
]
Part II: Check for a Valid Cell Position
int is valid cell(Map *map ptr, int row, int col)
This function determines whether (row,col) represents a valid pair of indices into the game world. That is,
whether a potential access to map ptr.cells[row][col] would be valid.
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• row: The 0-based row index of the desired byte.
• col: The 0-based column index of the desired byte.
Returns in $v0:
• 0 if (row,col) is a valid index pair, or -1 if not
Returns -1 in $v0 in any of the following cases:
• row < 0
• row ≥ map ptr.num rows
• col < 0
• col ≥ map ptr.num cols
Additional requirements:
• The function must not write any changes to main memory.
Examples:
In these examples, suppose that the game world contains 25 rows and 7 columns.
Function Call Return Value
is valid cell(map ptr, 5, 3) 0
is valid cell(map ptr, 0, 0) 0
is valid cell(map ptr, 24, 6) 0
is valid cell(map ptr, 25, 3) -1
is valid cell(map ptr, -3, 4) -1
Part III: Get the Contents of a Cell
int get cell(Map *map ptr, int row, int col)
This function returns the byte stored at map position (row,col). It does not modify the hidden flag or perform
any processing before returning the value in the map.
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• row: The 0-based row index of the desired byte.
• col: The 0-based column index of the desired byte.
Returns in $v0:
• The byte at map ptr.cells[row][col].
Returns -1 in $v0 for error in any of the following cases:
• row < 0
• row ≥ map ptr.num rows
• col < 0
• col ≥ map ptr.num cols
Additional requirements:
• get cell must call is valid cell.
• The function must not write any changes to main memory.
Example:
Suppose that map3.txt was loaded and the state of the game world (visually) is as follows:
###
#.....m
#.....m
#.....mm
#[email protected]
#..*....
####
In memory, in hexadecimal, the game world will look like this:
23 23 23 A3 A3 A3 A3 BE A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
23 2E 2E 2E 2E 2E 6D AE ED AE AE AE AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
23 2E 2E 2E 2E 2E 6D AA ED AE AE AE AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
23 2E 2E 2E 2E 2E 6D 6D ED AE AE AE AE AE AE AF AE AE AE AE AE AE AE AE A3
23 2E 2E 2E 2E 2E 40 2E AE AE AE AE A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
23 2E 2E 2A 2E 2E 2E 2E AE AE AE AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
23 23 23 23 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
Function Call Return Value (decimal)
get cell(map ptr, 3, 8) 237
get cell(map ptr, 4, 6) 64
get cell(map ptr, 25, 3) -1
get cell(map ptr, -3, 4) -1
Part IV: Set the Contents of a Cell
int set cell(Map *map ptr, int row, int col, char ch)
This function changes the byte stored at map position (row,col) to ch. It does not modify the hidden flag of
ch or perform any processing of ch before writing the value to the map.
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• row: The 0-based row index of the byte to be modified.
• col: The 0-based column index of the byte to be modified.
• ch: The byte to be written to index (row,col).
Returns in $v0:
• 0 if the change to the map was successful, or -1 on error
Returns -1 in $v0 for error in any of the following cases:
• row < 0
• row ≥ map ptr.num rows
• col < 0
• col ≥ map ptr.num cols
Additional requirements:
• set cell must call is valid cell.
• The function must not write any changes to main memory except for the intended byte.
Examples:
Suppose that map3.txt was loaded and the state of the game world (visually) is as follows:
###
#.....m
#.....m
#.....mm
#[email protected]
#..*....
####
In memory, in hexadecimal, the game world will look like this:
23 23 23 A3 A3 A3 A3 BE A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
23 2E 2E 2E 2E 2E 6D AE ED AE AE AE AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
23 2E 2E 2E 2E 2E 6D AA ED AE AE AE AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
23 2E 2E 2E 2E 2E 6D 6D ED AE AE AE AE AE AE AF AE AE AE AE AE AE AE AE A3
23 2E 2E 2E 2E 2E 40 2E AE AE AE AE A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
23 2E 2E 2A 2E 2E 2E 2E AE AE AE AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
23 23 23 23 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
Function Call Return Value (decimal)
set cell(map ptr, 3, 6, ’$’) 0
set cell(map ptr, 4, 8, ’.’) 0
set cell(map ptr, 25, 3, ’.’) -1
set cell(map ptr, -3, 4, ’@’) -1
For test cases 1 and 2, the cells array would be updated at the given indices. For test cases 3 and 4, no changes
would be made to the cells array. As an example, for test case 1 the cells array would be updated to the
following:
23 23 23 A3 A3 A3 A3 BE A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
23 2E 2E 2E 2E 2E 6D AE ED AE AE AE AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
23 2E 2E 2E 2E 2E 6D AA ED AE AE AE AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
23 2E 2E 2E 2E 2E 24 6D ED AE AE AE AE AE AE AF AE AE AE AE AE AE AE AE A3
23 2E 2E 2E 2E 2E 40 2E AE AE AE AE A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
23 2E 2E 2A 2E 2E 2E 2E AE AE AE AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
23 23 23 23 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
Part V: Reveal the Cells in a 3×3 Area
void reveal area(Map *map ptr, int row, int col)
This function reveals all 9 characters in the 3×3 area centered at (row,col) in a game world. If (row,col)
itself is not a valid position, but some cells in a 3×3 area centered at (row,col) in the game world are valid,
then the valid cells are revealed. For example, suppose (row,col) = (-1,0), which is an invalid position.
The 3×3 area centered at this position consists of these (theoretical) indices:
-2,-1 -2, 0 -2, 1
-1,-1 -1, 0 -1, 1
0,-1 0, 0 0, 1
For this example, the cells at indices 0,0 and 0,1 would be revealed.
A cell is revealed by setting bit 7 of the cell to 0. For example, the # character has hexadecimal ASCII code
0x23, which is 0b00100011 in binary. Therefore, a hidden wall would be stored as 0b10100011 = 0xA3 in
memory. This function would change that byte to 0b00100011. A cell that is already revealed is not modified
by this function.
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• row: The 0-based row index of the byte in the center of the 3×3 area to be revealed.
• col: The 0-based column index of the byte in the center of the 3×3 area to be revealed.
Additional requirements:
• reveal area must call is valid cell, get cell and set cell.
• The function must not write any changes to main memory except for the intended bytes.
Examples:
Suppose that map3.txt was loaded and the state of the game world (visually) is as follows:
#####
.....m.
[email protected]*
.....mm
...
In memory, in hexadecimal, the game world will look like this:
A3 A3 23 23 23 23 23 BE A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 2E 2E 2E 2E 2E 6D 2E ED AE AE AE AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
A3 2E 2E 2E 2E 2E 40 2A ED AE AE AE AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
A3 2E 2E 2E 2E 2E 6D 6D ED AE AE AE AE AE AE AF AE AE AE AE AE AE AE AE A3
A3 2E 2E 2E AE AE AE AE AE AE AE AE A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE C2 AE AE AE AE AE AE AE AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
Now suppose we call reveal area(map ptr, 6, 4). Although it is true that the player is not in the
neighborhood of this cell, the function specification does not require that the player be in the center of the revealed
cell. In addition, the cell at index (6,4) is a hidden wall character at the edge of the map. Again, the specification
does not say it is illegal/invalid to call the function on a cell that is wall or that is on the edge of the map. For this
particular function call the game map would theoretically be updated as follows (visually):
#####
.....m.
[email protected]*
.....mm
...
B..
###
and in memory, in hexadecimal, the cells array would look like this:
A3 A3 23 23 23 23 23 BE A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 2E 2E 2E 2E 2E 6D 2E ED AE AE AE AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
A3 2E 2E 2E 2E 2E 40 2A ED AE AE AE AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
A3 2E 2E 2E 2E 2E 6D 6D ED AE AE AE AE AE AE AF AE AE AE AE AE AE AE AE A3
A3 2E 2E 2E AE AE AE AE AE AE AE AE A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE 42 2E 2E AE AE AE AE AE AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 23 23 23 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
Part VI: Acquiring a Target to Attack
int get attack target(Map *map ptr, Player *player ptr, char direction)
This function inspects a cell adjacent to a player, as indicated by direction, and returns the character at that
“target” cell, provided that the cell is an attackable target, namely, a minion monster (m), a boss monster (B) or
a door (/). If the targeted cell is not one of these targets or of the target cell is not valid (i.e., invalid indices),
the function returns -1. Otherwise, the function simply returns the character at the targeted cell. The function
assumes that the targeted cell is visible (i.e., not hidden).
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• player ptr: The starting address of a Player struct.
• direction: The character ’U’, ’D’, ’L’ or ’R’.
◦ ’U’ indicates that the player is attempting to attack a target in the same column, but previous row of
the game world (i.e., index (player ptr.row-1,player ptr.col)).
◦ ’D’ indicates that the player is attempting to attack a target in the same column, but next row of the
game world (i.e., index (player ptr.row+1,player ptr.col)).
◦ ’L’ indicates that the player is attempting to attack a target in the same row, but previous column of
the game world (i.e., index (player ptr.row,player ptr.col-1)).
◦ ’R’ indicates that the player is attempting to attack a target in the same row, but next column of the
game world (i.e., index (player ptr.row,player ptr.col+1)).
Returns in $v0:
• The targeted cell, which can be only one of ’m’, ’B’ or ’/’.
Returns -1 in $v0 for error in any of the following cases:
• direction is not one of ’U’, ’D’, ’L’ or ’R’.
• The targeted cell is not at a valid index. Although during normal gameplay this shouldn’t be possible, the
function must accommodate this possibility.
• The targeted cell is not one of ’m’, ’B’ or ’/’.
Additional requirements:
• get attack target must call get cell.
• The function must not write any changes to main memory.
Example:
Suppose that map3.txt was loaded and the state of the game world (visually) is as follows:
####
[email protected]
.....m m......#
.....mmm.......
...........$..#
.......
In memory, in hexadecimal, the game world will look like this:
A3 A3 A3 A3 A3 A3 A3 BE 23 23 23 23 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 AE AE AE AE AE ED AE 6D 40 2E 2E 2E 2E 2E A3 BF BF BF A3 AE AE A3 BF BF
A3 2E 2E 2E 2E 2E 6D AA 6D 2E 2E 2E 2E 2E 2E 23 A3 A3 A3 A3 AE AE A3 A3 A3
A3 2E 2E 2E 2E 2E 6D 6D 6D 2E 2E 2E 2E 2E 2E 2E AE AE AE AE AE AE AE AE A3
A3 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 24 2E 2E 23 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE C2 2E 2E 2E 2E 2E 2E 2E AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
Function Call Return Value Explanation
get attack target(map ptr, player ptr, ’U’) -1 cannot attack a wall
get attack target(map ptr, player ptr, ’D’) -1 cannot attack floor
get attack target(map ptr, player ptr, ’L’) 109 can attack a minion
get attack target(map ptr, player ptr, ’R’) -1 cannot attack floor
get attack target(map ptr, player ptr, ’Z’) -1 invalid argument
Part VII: Completing a Player’s Attack
void complete attack(Map *map ptr, Player *player ptr, int target row,
int target col)
This function is essentially a helper function for player turn. It is called once it has been determined external
to this function that the player can validly attack a targeted cell located at index (target row,target col)
of the game world. The possible outcomes of calling this function are as follows:
• The targeted cell is ’m’. The player completes a successful kill of the minion, which counterattacks during
the fight and causes 1 point of damage to the player. The value of player ptr.health is updated
accordingly. The ’m’ in the targeted cell is replaced with ’$’. The player’s position does not change.
• The targeted cell is ’B’. The player completes a successful kill of the boss monster, which counterattacks
during the fight and causes 2 points of damage to the player. The value of player ptr.health is
updated accordingly. The ’B’ in the targeted cell is replaced with ’*’. The player’s position does not
change.
• The targeted cell is ’/’. The player destroys the targeted door. The ’/’ in the targeted cell is replaced
with ’.’. The player’s position does not change.
While battling a monster, the player’s health might drop to 0 or −1, meaning that the player has died. In this case,
the ’@’ for the player is replaced with ’X’ in the game world. Note that the monster is still killed and loot (’$’
or ’*’) is still dropped.
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• player ptr: The starting address of a Player struct.
• target row: The row of a targeted cell.
• target col: The column of a targeted cell.
Additional requirements:
• complete attack must call get cell and set cell.
• The function must not write any changes to main memory except for the targeted cell.
Examples:
Suppose that map3.txt was loaded and the state of the game world (visually) is as follows:
####
[email protected]
.....m m......#
.....mmm.......
...........$..#
.......
In memory, in hexadecimal, the game world will look like this:
A3 A3 A3 A3 A3 A3 A3 BE 23 23 23 23 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 AE AE AE AE AE ED AE 6D 40 2E 2E 2E 2E 2E A3 BF BF BF A3 AE AE A3 BF BF
A3 2E 2E 2E 2E 2E 6D AA 6D 2E 2E 2E 2E 2E 2E 23 A3 A3 A3 A3 AE AE A3 A3 A3
A3 2E 2E 2E 2E 2E 6D 6D 6D 2E 2E 2E 2E 2E 2E 2E AE AE AE AE AE AE AE AE A3
A3 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 24 2E 2E 23 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE C2 2E 2E 2E 2E 2E 2E 2E AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
The player is located at map ptr.cells[1][9]. Suppose we make the function call
complete attack(map ptr, player ptr, 1, 8). At map ptr.cells[1][8] we can see that a
minion is present. Therefore, the player suffers 1 point of damage (i.e., player ptr.health decreases by 1)
and the contents of map ptr.cells[1][8] is changes to ’$’.
The state of the game world (visually) will change to this:
####
[email protected]
.....m m......#
.....mmm.......
...........$..#
.......
In memory, in hexadecimal, the game world will now look like this:
A3 A3 A3 A3 A3 A3 A3 BE 23 23 23 23 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 AE AE AE AE AE ED AE 24 40 2E 2E 2E 2E 2E A3 BF BF BF A3 AE AE A3 BF BF
A3 2E 2E 2E 2E 2E 6D AA 6D 2E 2E 2E 2E 2E 2E 23 A3 A3 A3 A3 AE AE A3 A3 A3
A3 2E 2E 2E 2E 2E 6D 6D 6D 2E 2E 2E 2E 2E 2E 2E AE AE AE AE AE AE AE AE A3
A3 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 24 2E 2E 23 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE C2 2E 2E 2E 2E 2E 2E 2E AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
Part VIII: When Monsters Attack
int monster attacks(Map *map ptr, Player *player ptr)
This function is essentially a helper function for player turn. It returns the number of points of damage
potentially inflicted by monsters against the player. Suppose (R,C) is the position of the player. The four grid
positions (R-1,C), (R+1,C), (R,C-1) and (R,C+1) are inspected to check if a monster is located there.
Every such minion (m) potentially inflicts one point of damage, and every boss (B) potentially inflicts two points
of damage.
Note that the function itself does not modify the Player struct’s health field. Rather, the function simply
returns the number of points of damage that the monsters at the given location could inflict on the target.
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• player ptr: The starting address of a Player struct.
Returns in $v0:
• The number of points of damage that monsters immediately up, down, left and right of
map ptr.cells[player ptr.row][player ptr.col] could potentially cause to the player.
Additional requirements:
• monster attacks must call get cell.
• The function must not write any changes to main memory.
Example #1:
Suppose that map3.txt was loaded and the state of the game world (visually) is as follows:
#####
m.....
[email protected]
.....mmm...
...........
B........
In memory, in hexadecimal, the game world will look like this:
A3 A3 A3 A3 A3 A3 23 3E 23 23 23 23 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 AE AE AE AE AE 6D 2E 2E 2E 2E 2E AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
A3 2E 2E 2E 2E 2E 6D 40 6D 2E 2E 2E AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
A3 2E 2E 2E 2E 2E 6D 6D 6D 2E 2E 2E AE AE AE AF AE AE AE AE AE AE AE AE A3
A3 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE 42 2E 2E 2E 2E 2E 2E 2E 2E AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
The function call monster attacks(map ptr, player ptr) will return the value 3 because there are 3
minions immediately above, below, left and/or right of the player. The player’s health remains unchanged. The
state of the cells array of the Map struct remains unchanged.
Example #2:
Suppose that map3.txt was loaded and the state of the game world (visually) is as follows:
.....
.....m
[email protected]
B...
In memory, in hexadecimal, the game world will look like this:
A3 A3 A3 A3 A3 A3 A3 BE A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 AE AE AE AE AE ED AE ED AE AE AE AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
A3 2E 2E 2E 2E 2E ED AA ED AE AE AE AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
A3 2E 2E 2E 2E 2E 6D ED ED AE AE AE AE AE AE AF AE AE AE AE AE AE AE AE A3
A3 2E 2E 2E 2E 40 2E AE AE AE AE AE A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE 42 2E 2E 2E AE AE AE AE AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
The function call monster attacks(map ptr, player ptr) will return the value 0 because there are
no monsters (neither minions nor bosses) immediately above, below, left and/or right of the player. The player’s
health remains unchanged. The state of the cells array of the Map struct remains unchanged.
Example #3:
Suppose that map3.txt was loaded and the state of the game world (visually) is as follows:
.....m
.....m
...m..
[email protected]
####
In memory, in hexadecimal, the game world will look like this:
A3 A3 A3 A3 A3 A3 A3 BE A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 BF BF
A3 AE AE AE AE AE ED AE ED AE AE AE AE AE AE A3 BF BF BF A3 AE AE A3 BF BF
A3 2E 2E 2E 2E 2E 6D AA ED AE AE AE AE AE AE A3 A3 A3 A3 A3 AE AE A3 A3 A3
A3 2E 2E 2E 2E 2E 6D ED ED AE AE AE AE AE AE AF AE AE AE AE AE AE AE AE A3
A3 2E 2E 2E 6D 2E 2E AE AE AE AE AE A4 AE AE A3 A3 A3 A3 A3 AE AE AE AE A3
A3 AE AE 42 40 2E 2E AE AE AE AE AE AE AE AE A3 BF BF BF A3 AE AE AE AE A3
A3 A3 A3 23 23 23 23 A3 A3 A3 A3 A3 A3 A3 A3 A3 BF BF BF A3 A3 A3 A3 A3 A3
The function call monster attacks(map ptr, player ptr) will return the value 3 because the monsters immediately above, below, left and/or right of the player (one minion, one boss) could collectively cause
3 points of damage. The player’s health remains unchanged. The state of the cells array of the Map struct
remains unchanged.
Part IX: Moving the Player
int player move(Map *map ptr, Player *player ptr, int target row,
int target col)
This function is essentially a helper function for player turn. It is called once it has been determined external
to this function that the player can validly attempt to move to the targeted cell located at index
(target row,target col) of the game world.
Before attempting to move the player, the function calls monster attacks to check whether any nearby
monsters land an attack on the player. The return value of monster attacks is subtracted from the player’s
health.
The possible outcomes of calling this function are as follows:
• Nearby monsters killed the player (i.e., the player’s health is ≤ 0). The ’@’ at the player’s position in the
game world is replaced with ’X’. The function returns 0.
• The targeted cell is ’.’. The ’@’ at the player’s position in the game world is replaced with ’.’, and the
’.’ at the targeted cell in the game world is replaced with ’@’. The Player struct’s position is updated
accordingly. The function returns 0.
• The targeted cell is ’$’. The ’@’ at the player’s position in the game world is replaced with ’.’, and the
’$’ at the targeted cell in the game world is replaced with ’@’. The Player struct’s position is updated
accordingly. The Player struct’s coins field is incremented by 1. The function returns 0.
• The targeted cell is ’*’. The ’@’ at the player’s position in the game world is replaced with ’.’, and the
’*’ at the targeted cell in the game world is replaced with ’@’. The Player struct’s position is updated
accordingly. The Player struct’s coins field is incremented by 5. The function returns 0.
• The targeted cell is ’’. The ’@’ at the player’s position in the game world is replaced with ’.’, and the
’’ at the targeted cell in the game world is replaced with ’@’. The Player struct’s position is updated
accordingly. The function returns -1. (Updated 11/20/2018.)
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• player ptr: The starting address of a Player struct.
• target row: The row of the cell the player will move to.
• target col: The column of the cell the player will move to.
Return values for $v0 are provided in the description above.
Additional requirements:
• player move must call get cell, set cell and monster attacks.
• The function must not write any changes to main memory except as specified.
Examples:
In the examples below, the player is playing a game using map3.txt.
Example #1: The player dies while trying to move
Suppose the state of the game visually is:
.....m
.....m
...m..
[email protected]
####
Suppose that the player has 1 point of health remaining, is at index (5,4) and the function call
player move(map ptr, player ptr, 5, 5) is made. monster attacks is called, causing 3 points
of damage to the player. The player dies from the monsters’ attacks. The state of the map becomes:
.....m
.....m
...m..
BX..
####
and the function returns 0. Note that the cell at the player’s position becomes ’X’ and the player does not move.
Example #2: The player moves to adjacent floor spot
Suppose the state of the game visually is:
.....m
.....$
[email protected]
.B...
Suppose that the player is at index (4,5) and the function call player move(map ptr, player ptr,
5, 5) is made. The state of the map becomes:
.....m
.....$
......
[email protected]
###
and the function returns 0.
Example #3: The player moves and picks up a coin
Suppose the state of the game visually is:
.....m
.....m
[email protected]
B...
####
Suppose that the player is at index (4,5) and the function call player move(map ptr, player ptr,
4, 4) is made. The state of the map becomes:
.....m
.....m
[email protected]
B...
####
and the function returns 0. Note that the player’s coins field is incremented by 1 during execution of the
function.
Example #4: The player moves and picks up a gem
Suppose the state of the game visually is:
.....m*m
[email protected]
........
B.....
####
Suppose that the player is at index (3,7) and the function call player move(map ptr, player ptr,
2, 7) is made. The state of the map becomes:
m.m
[email protected]
.....m.m
........
B.....
####
and the function returns 0. Note that the player’s coins field is incremented by 5 during execution of the
function.
Example #5: The player escapes the dungeon
Suppose the state of the game visually is:
######
[email protected]
.....m*m
....
...
Suppose that the player is at index (1,7), has 5 points of health remaining, and the function call
player move(map ptr, player ptr, 0, 7) is made. The state of the map becomes:
#####@#
.......m
.....m*m
....
...
and the function returns -1.
Example #6: The player dies while trying to escape the dungeon
Suppose the state of the game visually is:
####
[email protected]
.....m*m..
..........
...m......
Suppose that the player has 1 point of health remaining, is at index (1,7), and the function call
player move(map ptr, player ptr, 0, 7) is made. The state of the map becomes:
####
mX...
.....m*m..
..........
...m......
and the function returns 0 (not -1) because the player died.
Part X: Taking a Turn
int player turn(Map *map ptr, Player *player ptr, char direction)
This function is a top-level function and relies directly or indirectly on almost every other function on the assignment. player turn is intended to be called inside the game loop to process a player’s turn in the game. The
algorithm it must implement proceeds as follows:
1. Check if direction is one of ’U’, ’D’, ’L’ or ’R’. If not, then return -1. Otherwise, continue to step
2.
2. Check if the targeted cell is at a valid index. If not, then return 0. Otherwise, continue to step 3. Although
during normal gameplay shouldn’t be possible to target an invalid index, the function must accommodate
for this possibility.
3. Call get cell to check where the player is attempting to move to or attack. If the target cell is ’#’, return
0.
4. Assuming the target is a valid index to move to or attack, call get attack target to see if the target
cell is attackable.
• If the target cell is attackable, call complete attack and then return 0.
• Otherwise, call player move and return that function’s return value as the return value of player turn.
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• player ptr: The starting address of a Player struct.
• direction: The character ’U’, ’D’, ’L’ or ’R’.
◦ ’U’ indicates that the player is attempting to attack a target in the same column, but previous row of
the game world (i.e., index (player ptr.row-1,player ptr.col)).
◦ ’D’ indicates that the player is attempting to attack a target in the same column, but next row of the
game world (i.e., index (player ptr.row+1,player ptr.col)).
◦ ’L’ indicates that the player is attempting to attack a target in the same row, but previous column of
the game world (i.e., index (player ptr.row,player ptr.col-1)).
◦ ’R’ indicates that the player is attempting to attack a target in the same row, but next column of the
game world (i.e., index (player ptr.row,player ptr.col+1)).
Return values for $v0 are provided in the description above.
Additional requirements:
• player turn must call get cell, get attack target, complete attack and player move.
• The function must not write any changes to main memory except as specified.
Examples:
In the examples below, the player is playing a game using map3.txt.
Example #1: The player attempts to move into a wall
Suppose the state of the game visually is:
.....m
.....m
...m....
[email protected]
#####
Suppose that the player is at index (5,7), and the function call player turn(map ptr, player ptr,
’D’) is made. Because there is wall immediately below the player, the player cannot move. Therefore, the
function simply returns 0.
Example #2: The player wants to make an attack
Suppose the state of the game visually is:
.....m
.....mmm.
[email protected]
......
######
Suppose that the player is at index (4,8), and the function call player turn(map ptr, player ptr,
’U’) is made. Since the target cell is not ’#’, player turn then calls get attack target.
get attack target in this case will not return -1, meaning that the player can attack the target cell. Therefore, player turn then calls complete attack and, after complete attack returns, player turn
returns 0.
Example #3: The player wants to move to an adjacent cell
Suppose the state of the game visually is:
.....m
.....mmm..
[email protected]
.......
#######
Suppose that the player is at index (4,9), and the function call player turn(map ptr, player ptr,
’R’) is made. Since the target cell is not ’#’, player turn then calls get attack target.
get attack target in this case will return -1, meaning that the player cannot attack the target cell. Therefore, player turn then calls player move. player turn will return player move’s return value as its
own return value.
Part XI: Revealing a Large Area of the Game World
int flood fill reveal(Map *map ptr, int row, int col, bit[][] visited)
This function performs a “flood fill” operation to reveal empty floor spaces (’.’) in the neighborhood of the cell
at index (row,col) of the world map. The function uses the stack to track all adjacent cells which could be
revealed. See the pseudocode below for the algorithm you must implement. $fp is the frame pointer, a register
we can use in concert with $sp to manage the stack. The frame pointer is a preserved register, and therefore must
be preserved just like an $s register. In this algorithm the frame pointer is used to help us keep track of what cells
of the game world we still need to process and possibly reveal during the search.
if (row, col) represents an invalid index then
return -1
$fp = $sp
$sp.push(row)
$sp.push(col)
offsets = [(-1, 0), (1, 0), (0, -1), (0, 1)] # a list of pairs
while $sp != $fp:
col = $sp.pop()
row = $sp.pop()
make the cell at index (row,col) visible in the world map
foreach pair (i,j) of values in offsets[]:
if the cell at index (row+i, col+j) represents empty floor AND (*)
the cell has not been visited yet, then
(1) set that cell as having been visited
(2) $sp.push(row+i)
(3) $sp.push(col+j)
return 0
In the if-statement marked with the (*) above, the floor cell might be be hidden or revealed. Regardless of
whether the floor at that index is hidden or revealed, it must be pushed on the stack if it has not been visited yet.
The function takes the following arguments, in this order:
• map ptr: The starting address of a Map struct. Note: this is NOT the address of the character at index
[0][0] of the game world.
• row: The row index where the flood fill begins.
• col: The column index where the flood fill begins.
• visited: A 2D array of bits that record whether a particular cell has been visited by the algorithm. The
dimensions of the bit vector match the dimensions of the cells array. The function may assume that this
bit-vector has been initialized with all zero bits.
Returns in $v0:
• 0 if a flood fill was executed, or -1 on error.
Returns -1 in $v0 for error in any of the following cases:
• row < 0
• row ≥ map ptr.num rows
• col < 0
• col ≥ map ptr.num cols
Additional requirements:
• flood fill reveal must call get cell and set cell.
• The function must not write any changes to main memory except as specified.
Examples:
In the examples below, the player is playing a game using map3.txt.
Example #1:
The player is at index (3,2).
Suppose that before the function call flood fill reveal(map ptr, 3, 2, visited) the state of the
map is:
...
[email protected]
...
After the function call it will become:
..... ......
..... ......
[email protected] ......
... ....... ..
.. ...........
Example #2:
The player is at index (3,14).
Suppose that before the function call flood fill reveal(map ptr, 3, 14, visited) the state of the
map is:
.....m ..#
[email protected]
...m..........#
...........#
###
After the function call it will become:
..... ...... ..
.....m ......# ..
[email protected]
...m..........# ....
.. ...........# ....
###
Academic Honesty Policy
Academic honesty is taken very seriously in this course. By submitting your work to Blackboard you indicate
your understanding of, and agreement with, the following Academic Honesty Statement:
1. I understand that representing another person’s work as my own is academically dishonest.
2. I understand that copying, even with modifications, a solution from another source (such as the web or
another person) as a part of my answer constitutes plagiarism.
3. I understand that sharing parts of my homework solutions (text write-up, schematics, code, electronic or
hard-copy) is academic dishonesty and helps others plagiarize my work.
4. I understand that protecting my work from possible plagiarism is my responsibility. I understand the importance of saving my work such that it is visible only to me.
5. I understand that passing information that is relevant to a homework/exam to others in the course (either
lecture or even in the future!) for their private use constitutes academic dishonesty. I will only discuss
material that I am willing to openly post on the discussion board.
6. I understand that academic dishonesty is treated very seriously in this course. I understand that the instructor
will report any incident of academic dishonesty to the College of Engineering and Applied Sciences.
7. I understand that the penalty for academic dishonesty might not be immediately administered. For instance,
cheating in a homework may be discovered and penalized after the grades for that homework have been
recorded.
8. I understand that buying or paying another entity for any code, partial or in its entirety, and submitting it as
my own work is considered academic dishonesty.
9. I understand that there are no extenuating circumstances for academic dishonesty.
How to Submit Your Work for Grading
To submit your hw4.asm file for grading:
1. Login to Blackboard and locate the course account for CSE 220.
2. Click on “Assignments” in the left-hand menu and click the link for this assignment.
3. Click the “Browse My Computer” button and locate the hw4.asm file. Submit only that one .asm file.
4. Click the “Submit” button to submit your work for grading.
Oops, I messed up and I need to resubmit a file!
No worries! Just follow the steps again. We will grade only your last submission.