[Solved] CSE220-Programming Assignment 3

$25

File Name: CSE220-Programming_Assignment_3.zip
File Size: 292.02 KB

SKU: [Solved] CSE220-Programming Assignment 3 Category: Tag:
5/5 - (1 vote)

For this assignment you will be implementing a version of the classic game of Snak e in MIPS. Briefly, the snake consists of several body segments (represented by ASCII characters) that can move around a 2D game board, eating apples. Each time the snake eats an apple, its length increases by one. In the original game, the game ends when the snake runs into a wall, runs into itself, or runs out of bounds. We will implement the same basic logic in our version.

The head of the snake is represented by the ASCII character 1, with each following segment in the body given by consecutive digit characters (i.e., 2, 3, 4, etc.) After 9, body segments are denoted with uppercase letters, starting with A and going all the way through the alphabet to Z. Thus, the snake can be at most 9 + 26 = 35 body segments in length.

The game board consists of a 2D grid of ASCII characters (slots), with the period, ., representing an empty slot; a pound sign, #, representing a wall; the lowercase letter a representing an apple, and the digits and uppercase letters representing parts of the snake. Below is an example of an in-progress game on a 1530 grid (15 rows, 30 columns).

############

#.#

#.#

#.#

.a.123

..4

#.56.#

#.#

#.#

############

The player scores points as he/she moves the snake about the game grid and eats apples. Scoring is explained later.

Data Structures

To characterize the state of the game we track several pieces of data in the form of a struct , which is like an object with data fields only (no methods). We will call this data type GameState throughout this document.

  • num_rows: the number of rows in the grid (an unsigned byte)
  • num_cols: the number of columns in the grid (an unsigned byte)
  • head_row: the row of the snakes head (an unsigned byte)
  • head_col: the column of the snakes head (an unsigned byte)
  • length: the length of the snake (an unsigned byte)
  • grid: the contents of the game board (a null-terminated string that stores the board in row-major order)

The topmost row of the grid is row #0, and the leftmost column is column #0. Similarly, the bottom-most row is num_rows-1 , and the rightmost column is num_cols-1 . The maximum grid size is 9999.

As an example, the game board shown above would be represented in MIPS as follows:

.align 2 # ensures that the data structure is on a word-aligned boundary state: # name of the data structure (game state)

.byte 15 # num_rows (byte #0)

.byte 30 # num_cols (byte #1)

.byte 7 # head_row (byte #2)

.byte 15 # head_col (byte #3)

.byte 6 # length (byte #4)

# Game grid: (bytes #5-end)

.asciiz

######.

..#######.##.#

#.#.a

.123..4#.56.#.

..#.##.#### #########..

.

To access the fields of the struct, we need to be provided its starting address (i.e., the address of the num_rows field). From there we can use lbu with appropriate offsets to access the field values, including the contents of the grid.

Part 1: Load a Game Board from Disk

int, int load_game(GameState* state, string filename)

The load_game function reads the contents of a file that defines a game board and initializes the referenced GameState data structure. The notation GameState* indicates that state is the starting address of a GameState struct. You may assume that state points to a block of memory large enough to store the struct represented inside the file. If the file exists, you may assume that the files contents are valid. If the file does not exist, the function simply returns -1, -1.

The file format is very simple:

# of rows in the game grid # of columns in the game grid

contents of grid in which each row is on its own line

Important note: on Microsoft Windows, a line ends with the character combination r
, whereas on Mac and other Unix-like operating systems like Linux, a line ends only with
. Your code must be able to handle both line-ending styles. All lines of the file, including the final row of the grid, are guaranteed to end with
or r
. As an example, the above game grid would be saved in a Microsoft Windows-generated file as:

15r

30r

r

r

############r

#.#r

#.#r

#.#r

r

.a.123r

..4r

#.56.#r

#.#r

#.#r

############r

r

r

Again, your code must be able to contend with r
line-endings and with
line-endings.

To assist with reading and writing files, MARS provides several system calls:

Service Code in $v0 Arguments Results
open file 13 $a0 = address of null-terminated filename string$a1 = flags$a2 = mode $v0 contains file descriptor(negative if error)
read from file 14 $a0 = file descriptor$a1 = address of input buffer$a2 = maximum # of characters to read $v0 contains # of characters read (0 if end-of-file, negative if error)
write to file 15 $a0 = file descriptor$a1 = address of output buffer (negative if error)$a2 = maximum # of characters to write $v0 contains # of characters written
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 write-only with create and append. It ignores mode. The returned file descripto r 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 inpu t, writing to standard outpu t, and writing to standard erro r, respectively. An example of how to use these syscalls can be found on the MARS syscall web page.

Some advice: read the contents of the file one character at a time using system call #14. This system call requires a memory buffer to hold the character read from the disk. You should allocate four bytes of memory on the stack (by adjusting $sp) to store that byte temporarily. Discard newline characters (both r and
) as you read them and do not store them in the GameState struct. Finally, remember to reset $sp once you have finished reading the file contents and to close the file with system call #16.

MARS can be a little buggy when it comes to opening files. Therefore, either:

  • put all your .asm and .txt game files in the same directory as the MARS .jar file, or use absolute path names when giving the filename in your testing mains.

The function load_game takes the following arguments, in this order:

  • state: a pointer to (i.e., starting memory address of) an uninitialized GameState struct large enough to hold the contents of the game represented by file to be loaded. Assume that the contents of the struct are filled with random garbage.
  • filename: a string containing the filename to open and read the contents of

Returns in $v0:

  • -1 if the input file does not exist; otherwise: 1 if a lowercase letter a representing an apple was found in the file; 0, if not

Returns in $v1:

  • -1 if the input file does not exist; otherwise: the number of wall characters, #, found in the file

Additional requirements:

  • The function must not write any changes to main memory except as needed. If the file does not exist, no changes may be written to state .

Example #1:

filename = game01.txt

Return value in $v0: 1

Return value in $v1: 6

Contents of state must be updated to reflect the data structure defined in the file.

Example #2:

filename = game02.txt

Return value in $v0: 0

Return value in $v1: 16

Contents of state must be updated to reflect the data structure defined in the file.

Example #3:

filename = junk.txt (non-existent file)

Return value in $v0: -1

Return value in $v1: -1

Contents of state must be left unchanged.

Part 2: Get the Character Stored in the Game Grid

int get_slot(GameState* state, byte row, byte col)

The function get_slot returns the character stored in the slot at state.grid[row][col]. A recommendation: use lbu to read tile values from the game board. If row is outside the valid range or col is outside the valid range for the given GameState, the function returns -1. For instance, the valid range for the row argument is [0, board.num_rows-1].

The function takes the following arguments, in this order:

  • state: a pointer to a valid GameState struct
  • row: the row of the grid array from where we want to read a value. This is an 8-bit, twos complement value.
  • col: the column of the grid array from where we want to read a value. This is an 8-bit, twos complement value.

Returns in $v0:

  • the character located at grid[row][col], or
  • -1 for the error condition explained above

Additional requirements:

  • The function must not write any changes to main memory.

Examples:

In the examples below, imagine that we initialized state by loading it with game01.txt:

5

12

.a.#.1..#

#.2..#

#.3..#

..4567

Return values other than -1 are the ASCII codes of the returned characters.

row col Return Value ($v0)
1 5 49
2 3 35
3 16 -1
-3 5 -1

Part 3: Set the Character Stored in the Game Grid

int set_slot(GameState* state, byte row, byte col, char ch)

The function set_slot sets the value stored in the slot at state.grid[row][col] to ch. A recommendation: use sb to write a character in the game grid. If row is outside the valid range or col is outside the valid range for the given GameState, the function returns -1. Otherwise,the function returns ch. The function does not need to validate that ch is a valid character for the Snake game.

The function takes the following arguments, in this order:

  • state: a pointer to a valid GameState struct
  • row: the row of the grid array at which we want to write a character. This is an 8-bit, twos complement value.
  • col: the column of the grid array at which we want to write a character. This is an 8-bit, twos complement value.
  • ch: the character to write at grid[row][col]

Returns in $v0:

  • ch, provided that row and col are both valid, or
  • -1 for the error condition explained above

Additional requirements:

  • The function must not write any changes to main memory except as necessary.

Examples:

In the examples below, imagine that we initialized state by loading it with game01.txt.

5

12

.a.#.1..#

#.2..#

#.3..#

..4567

Example #1:

row = 0 col = 5 ch = Q

Return value in $v0: 81 Updated game state:

..Q

.a.#.1..#

#.2..#

#.3..#

..4567

Example #2: row = 2 col = 11 ch = Z

Return value in $v0: 90 Updated game state:

.a.#.1..#

#.2..#..Z #.3..#

..4567

Example #3: row = 3 col = 7 ch = ?

Return value in $v0: 63 Updated game state:

.a.#.1..#

#.2..#

#.3.?#

..4567

Example #4: row = -5 col = 2 ch = *

Return value in $v0: -1

The game state should be unchanged.

Part 4: Place an Apple in the Game Grid

int, int place_next_apple(GameState* state, byte[] apples, int apples_length)

The function place_next_apple searches the apples array for a valid apple to place in the game grid and places it. The apples array consists of apples_length pairs of integers stored in row-major order that represent (row, col) coordinates where an apple hasnt yet been placed in the game grid. The pair (-1, -1) in the array indicates that an apple has already been placed at that position in the grid. For example, perhaps that apple was placed during a prior call to place_next_apple.

As an example, suppose apples begins [4, 2, 7, 3, 1, 9, -1, -1, ]. This indicates that potential locations in the game grid where an apple could be placed include (4, 2), (7, 3), (1, 9), among others. To find an apple to place in the grid, the function will start with (4, 2) and see if that position in the grid is empty (i.e., state.grid[4][2] contains .). If so, state.grid[4][2] is changed to a with set_slot, and then apples[0] and apples[1] are both changed to -1. On the other hand, suppose state.grid[4][2] contains a wall or a part of the snake or another apple. In this case, place_next_apple skips over the (4, 2) pair and tries (7, 3). The search continues in this fashion until a valid apple can be placed. When the pair (-1, -1) is encountered in apples, place_next_apple skips over it and continues to the next pair. You may safely assume that place_next_apple will always be able to find a valid apple to place in the game grid.

The function takes the following arguments, in this order:

  • state: a pointer to a valid GameState struct
  • apples: an array of apples_length pairs of 8-bit, twos complement integers apples_length: the number of pairs of integers in apples

Returns in $v0:

  • the row of the apple that was placed

Returns in $v1:

  • the column of the apple that was placed

Additional requirements:

  • The function must not write any changes to main memory except as necessary.
  • The function must call get_slot and set_slot.

Examples:

In the examples below, imagine that we initialized state by loading it with game01.txt :

5

12

.a.#.1..#

#.2..#

#.3..#

..4567

Example #1:

apples = [3, 2, 1, 4, 4, 3] apples_length = 3

Return value in $v0: 3

Return value in $v1: 2

Updated apples : [-1, -1, 1, 4, 4, 3] Updated game state:

.a.#.1..#

#.2..#

..a#.3..#

..4567

Example #2:

apples = [2, 5, 3, 5, 1, 4, 4, 3, 2, 9] apples_length = 5

Return value in $v0: 1

Return value in $v1: 4

Updated apples : [2, 5, 3, 5, -1, -1, 4, 3, 2, 9] Updated game state:

.a.#a1..#

#.2..#

#.3..#

..4567

Example #3:

apples = [2, 5, 3, 5, -1, -1, -1, -1, 4, 1, 4, 3, 2, 9] apples_length = 7

Return value in $v0: 4

Return value in $v1: 1

Updated apples: [2, 5, 3, 5, -1, -1, -1, -1, -1, -1, 4, 3, 2, 9] Updated game state:

.a.#.1..#

#.2..#

#.3..#

.a4567

Part 5: Find the Next Body Segment of the Snake

int, int find_next_body_part(GameState* state, byte row, byte col, char target_part)

The function find_next_body_part inspects the four grid slots up, down, to the left and to the right of state.grid[row][col] for the character target_part. If target_part is found in one of those locations, then the coordinates of target_part are returned. Otherwise, the function returns -1, -1. The function also returns -1, -1 if row or col is outside its valid range for state.grid. This function is called by other functions inside of a loop to find all of the body segments of the snake.

The function takes the following arguments, in this order:

  • state: a pointer to a valid GameState struct
  • row: the row of the grid array slot around which we search for target_part. This is an 8-bit, twos complement value.
  • col: the column of the grid array slot around which we search for target_part. This is an 8-bit, twos complement value.
  • target_part: the part of the snakes body segment we are looking for

Returns in $v0:

  • the row of target_part, if it was found; -1, otherwise

Returns in $v1:

  • the column of target_part, if it was found; -1, otherwise

Additional requirements:

  • The function must not write any changes to main memory.
  • The function must call get_slot.

Examples:

In the examples below, imagine that we initialized state by loading it with game01.txt :

5

12

.a.#.1..#

#.2..#

#.3..#

..4567

row col target_part Return Values
3 5 4 4, 5
4 7 7 4, 8
3 5 9 -1, -1

Part 6: Slide (Slither) the Snake Forward One Slot

int slide_body(GameState* state, byte head_row_delta, byte head_col_delta, byte[] apples, int apples_length)

The function slide_body attempts to slide (slither) the snake one place forward in the direction

(head_row_delta, head_col_delta):

  • (1, 0): move the snake down one row, starting from the head and with the body following, one segment at a time
  • (-1, 0): move the snake up one row
  • (0, 1): move the snake right one column
  • (0, -1): move the snake left one column

This function does not merely slide the entire snake up, down, left or right. Rather, the pair (head_row_delta, head_col_delta) indicates how the snakes head should lead the movement. The fields state.head_row and state.head_row must be updated, as appropriate. For instance, suppose the snake is in the configuration below:

.

.a..

..1.

..234..

.56.

and we call slide_body with (0, -1) for ( head_row_delta, head_col_delta). The snake is now positioned as follows:

.

.a..

.12.

..345..

.6..

Suppose we call slide_body with (0, -1) for ( head_row_delta, head_col_delta) two more times. Now we have this:

.

.a..

..1234.

..56

.

Notice how the body slithers along with the head leading the way.

The function takes the following arguments, in this order:

  • state: a pointer to a valid GameState struct
  • head_row_delta: the vertical direction in which to move the snakes head. This is an 8-bit, twos complement value.
  • head_col_delta: the horizontal direction in which to move the snakes head. This is an 8-bit, twos complement value.
  • apples: an array of apples_length pairs of 8-bit, twos complement integers apples_length: the number of pairs of integers in apples

You may assume that the pair ( head_row_delta, head_col_delta) is one of the four combinations of -1, 0, 1 listed above.

The function returns a code in $v0 which indicates what happened during the attempted move:

  • 0 if the snakes head moved onto an empty slot (i.e., .) and slithered forward without any trouble
  • 1 if the snakes head moved onto a slot containing an apple (i.e., a) and slithered forward without any trouble
  • -1 if the snake could not move forward because doing so would take it outside the game board, would intersect a wall slot, or would intersect with a body part of the snake. Return -1 without making any changes to the state of the game grid.

To make the snake slither forward, first move the head one slot forward in the desired direction. Then, call find_next_body_part repeatedly in a loop to iteratively move each other part forward one place. Specifically, body segment 2 will take the place of 1 (the head), 3 will take the place of 2, 4 will take the place of 3, and so on, until the final body segment of the snake has moved.

In the case that the snake is about to move onto an apple, call place_next_apple before moving any segment of the snake forward. Then have the entire snake slither forward in the desired direction, with the head replacing the apple. Note that slide_body does not increase the length of the snake when the snake consumes an apple. That task is handled by a different function

(increase_snake_length ).

Additional requirements:

  • The function must not write any changes to main memory except as necessary.
  • The function must call get_slot , set_slot, place_next_apple and find_next_body_part.

Examples:

In the examples below, imagine that we initialized state by loading it with game03.txt :

8

14

..

##

..

..#..a..#..

..#..1234..#..

..56E

##.7..CD 89AB.

Example #1:

head_row_delta = 0 head_col_delta = -1 apples = [1, 7, 3, 2, 1, 4, 4, 3] apples_length = 4

Return value in $v0: 0

Expected apples: [1, 7, 3, 2, 1, 4, 4, 3] Updated game state:

..

##

..

..#..a..#..

..#.12345..#..

..67.

##.8..DE

9ABC.

Example #2:

head_row_delta = -1 head_col_delta = 0 apples = [1, 7, 3, 2, 1, 4, 4, 3] apples_length = 4

Return value in $v0: 1

Updated apples: [1, 7, 3, 2, -1, -1, 4, 3] Updated game state:

..

.a.##

..

..#..1..#..

..#..2345..#..

..67.

##.8..DE

9ABC.

Example #3:

head_row_delta = 0 head_col_delta = 1 apples = [1, 7, 3, 2, 1, 4, 4, 3] apples_length = 4

Return value in $v0: -1 apples remains unchanged.

Game state remains unchanged.

Part 7: Add a New Body Segment to the Tail of the Snake

int add_tail_segment(GameState* state, char direction, byte tail_row, byte tail_col)

The function add_tail_segment takes the coordinates of the snakes tail at ( tail_row, int tail_col) and attempts to add a new segment to the tail of the snake in the given direction ( char direction). Note that this function is essentially a helper function for increase_snake_length. For example, suppose that direction = U and tail_row = 3, tail_col = 6. These arguments indicate that the function should try to add a tail segment at index state.grid[2][6]. You may assume that state.grid[tail_row][tail_col] is the valid, actual tail of the snake. The new tail segment may only be placed on an empty grid slot, denoted by the period character, .. If the new tail segment is successfully added, the length field of the state object must be incremented by 1. That new length is returned by add_tail_segment. If the tail segment cannot be added (e.g., due to a collision or because the snakes length is already 35), the function makes no changes to main memory and returns -1.

The function takes the following arguments, in this order:

  • state: a pointer to a valid GameState struct
  • direction: the direction relative to the tail of the snake to append a new segment. Must be one of U, D, L or R. For example, D indicates that the new tail segment should be placed in the row immediately below the current tail segment (if possible). As another example, R indicates that the new tail segment should be placed in the column immediately to the right of the current tail segment (if possible).
  • tail_row: the row number of the final segment in the tail. You may assume that this value is valid. This is an 8-bit, twos complement value.
  • tail_col: the column number of the final segment in the tail. You may assume that this value is valid. This is an 8-bit, twos complement value.

Returns in $v0:

  • The updated value of length if the new tail segment was placed. If the tail segment could not be placed or if direction is not one of U, D, L or R, then $v0 is -1.
  • If direction is invalid, the function must not make any changes to memory and return -1.

Additional requirements:

  • The function must not write any changes to main memory except as necessary.
  • The function must call get_slot and set_slot.

Examples:

In the examples below, imagine that we initialized state by loading it with game01.txt:

5

12

.a.#.1..#

#.2..#

#.3..#

..4567

Example #1:

tail_row = 4 tail_col = 8 direction = R

Return value in $v0: 8 Updated game state:

.a.#.1..#

#.2..#

#.3..#

..45678..

Example #2:

tail_row = 4 tail_col = 8 direction = D

Return value in $v0: -1

Game state remains unchanged.

Example #3:

tail_row = 4 tail_col = 8 direction = U

Return value in $v0: -1

Game state remains unchanged.

Part 8: Increase the Length of the Snakes Body

int increase_snake_length(GameState* state, char direction)

The function increase_snake_length calls upon find_next_body_part (iteratively) and then add_tail_segment to find the tail of the snake in the game and append a new tail segment in the opposite direction that the snakes head is moving. For example, if direction = L , then increase_snake_length will attempt to add a new segment to the right of the current tail. Likewise, if direction = D , then increase_snake_length will attempt to add a new segment above the current tail segment. If this attempt is not successful, the function will search the cells in the neighborhood of the tail in counterclockwise order to find a position for the new tail segment. This aspect of the function will be made clear with a set of examples below. Note that increase_snake_length does not change the value of the length field in state .

The function takes the following arguments, in this order:

  • state: a pointer to a valid GameState struct
  • direction: the direction that the snakes head is moving. Must be one of U, D, L or R.

Returns in $v0:

  • length if a new tail segment was successfully added by add_tail_segment, or -1 if not.
  • If direction is invalid, the function must not make any changes to memory and return -1.

Additional requirements:

  • The function must not write any changes to the main memory itself. Any changes written to memory must be made via add_tail_segment.
  • The function must call find_next_body_part and add_tail_segment .

Example #1: The snakes head is moving to the left (direction = L), so increase_snake_length calls add_tail_segment to try appending a segment to the right end of the current tail. add_tail_segment returns 8, indicating success.

The game state has been initialized by loading it with game01.txt:

5

12

.a.#.1..#

#.2..#

#.3..#

..4567

direction = L

Return value in $v0: 8 Updated game state:

.a.#.1..#

#.2..#

#.3..#

..45678..

Example #2: The snakes head is moving to the up (direction = U), so increase_snake_length calls add_tail_segment to try appending a segment below the current tail. add_tail_segment returns -1 because a body segment is in the way. So, increase_snake_length calls add_tail_segment to try appending a segment to the right of the current tail. add_tail_segment once again returns -1 because that slot is out of bounds.

increase_snake_length continues by calling add_tail_segment to try appending a segment to the above the end of the current tail. add_tail_segment returns 15, indicating success.

The game state has been initialized by loading it with game04.txt:

8

14

..

##

.. ..#..#..

a.#..1234..#.. ..56E

##.7..CD

89AB.

direction = U

Return value in $v0: 15 Updated game state:

..

##

.. ..#..#..

a.#..1234..#.F ..56E

##.7..CD 89AB.

Example #3: The snakes head is moving down (direction = D ) , so increase_snake_length calls add_tail_segment to try appending a segment above the current tail. add_tail_segment returns -1 because an apple is in the way. So, increase_snake_length calls add_tail_segment to try appending a segment left of the current tail. add_tail_segment returns 14, indicating success.

The game state has been initialized by loading it with game05.txt :

8

14

..

##

..

..#..#..

..#..1234..#a.

..56..D.

##.7..C.

89AB.

direction = D

Return value in $v0: 14

Updated game state:

..

##

..

..#..#..

..#..1234..#a.

..56.ED.

##.7..C.

89AB.

Example #4: The snakes head is moving up (direction = U), so increase_snake_length calls add_tail_segment to try appending a segment below the current tail. add_tail_segment returns -1, indicating failure. Next, increase_snake_length will add_tail_segment three more times, attempting to append tail segments to the right, above and to the left of the current tail segment. In each case, add_tail_segment returns -1, indicating failure. Because in every case add_tail_segment returned -1, increase_snake_length returns -1.

The game state has been initialized by loading it with game06.txt:

5

5

.a ..1..

.#2#.

.#3#.

.###.

direction = U

Return value in $v0: -1

The grid after call to increase_snake_length remains unchanged.

Part 9: Move the Snake Forward One Slot

int, int move_snake(GameState* state, char direction, byte[] apples, int apples_length)

The function move_snake is a top-level function of the game that moves the snake through the game grid one slot at a time. Given the value of direction, it makes an appropriate call to slide_body in an attempt to move the snake forward one slot in the grid.

  • If the return value of slide_body is -1, then move_snake returns (0, -1) to indicate, respectively, that no points were scored during this call to move_snake and that ultimately the movement was unsuccessful.
  • On the other hand, if slide_body returned 1, this means the snake ate an apple. In response, move_snake calls increase_snake_length to attempt to increase the length of the snake, using the direction of the heads movement as the value for direction. The call to increase_snake_length returns either -1, indicating failure to increase the length of the body, or a value other than -1 to indicate success. If increase_snake_length failed, then move_snake returns (0, -1). Otherwise, it returns (100, 1) indicating that 100 points were scored.
  • The last possibility for slide_body is that it returned 0, indicating that the snakes head (and body) moved forward successfully and the head moved into an empty slot. In this case, move_snake returns (0, 1) to indicate that no points were scored, but that the snake successfully moved forward.

Note that if direction is invalid, move_snake returns (0, -1).

The function takes the following arguments, in this order:

  • state: a pointer to a valid GameState struct
  • direction: the direction that the snakes head is moving. Must be one of U, D, L or R.
  • apples: an array of apples_length pairs of (signed) integers apples_length: the number of pairs of integers in apples

Returns in $v0:

  • The number of points scored during this function call. Must be 0 or 100.

Returns in $v1:

  • 1 if increase_snake_length successfully added a new body segment to the tail of the snake or the snake simply moved forward into an empty slot;
  • or -1 if increase_snake_length does not add a segment or if direction is invalid.

Additional requirements:

  • The function must not write any changes to the main memory itself. Any changes written to memory must be made via slide_body and increase_snake_length.
  • The function must call slide_body and increase_snake_length.

Example #1:

Suppose that we initialized state by loading it with game03.txt:

8

14

..

##

..

..#..a..#..

..#..1234..#..

..56E

##.7..CD 89AB.

direction = U

apples = [1, 2, 2, 9, 0, 5, 1, 7, 6, 10, 3, 10, 3, 11, 2, 10, 2, 1, 2, 4,

2, 5, 1, 13] apples_length = 12

Return value in $v0: 100

Return value in $v1: 1

Updated apples : [-1, -1, 2, 9, 0, 5, 1, 7, 6, 10, 3, 10, 3, 11, 2, 10, 2, 1,

2, 4, 2, 5, 1, 13]

Updated game state:

..

..a##

..

..#..1..#..

..#..2345..#..

..67.

##.8..DE

9ABCF

Example #2:

Suppose that we initialized state by loading it with game03.txt :

8

14

..

##

..

..#..a..#..

..#..1234..#..

..56E

##.7..CD 89AB.

direction = D

apples = [1, 2, 2, 9, 0, 5, 1, 7, 6, 10, 3, 10, 3, 11, 2, 10, 2, 1, 2, 4,

2, 5, 1, 13] apples_length = 12

Return value in $v0: 0 Return value in $v1: 1 apples remains unchanged. Updated game state: ..

##

..

..#..a..#..

..#..2345..#..

..1..67.

##.8..DE 9ABC.

Example #3:

Suppose that we initialized state by loading it with game07.txt :

5

12

.a.#.#

#12..#

#.3..#

..4567

direction = L apples = [4, 4, 2, 7, 3, 5, 1, 8, 1, 7, 3, 11, 1, 11, 0, 4] apples_length = 8

Return value in $v0: 0 Return value in $v1: -1 apples remains unchanged.

Game state remains unchanged.

Example #4:

Suppose that we initialized state by loading it with game07.txt :

5

12

.a.#.#

#12..#

#.3..#

..4567

direction = Z apples = [4, 4, 2, 7, 3, 5, 1, 8, 1, 7, 3, 11, 1, 11, 0, 4] apples_length = 8

Return value in $v0: 0 Return value in $v1: -1 apples remains unchanged.

Game state remains unchanged.

Part 10: Simulate a Game of Snake

int, int simulate_game(GameState* state, string filename, string directions, int num_moves_to_execute, byte[] apples, int apples_length)

The function simulate_game simulates at most num_moves_to_execute moves of a game of Snake. The initial configuration of the game grid is given by the contents of the file with name filename. The null-terminated string directions consists of the uppercase letters L, R, U and D in any order and combination and represents the attempted moves of the player. The array apples contains the positions of potential apples that can be placed during the simulation. The simulation algorithm that you must implement is as follows:

  1. Call load_game to attempt to initialize the uninitialized state struct with the contents of filename.
    1. If load_game fails to initialize the struct, simulate_game returns -1, -1 and makes no changes to main memory. Otherwise, we continue on to the next step.
  2. If load_game did not find an apple while initializing the state struct, call place_next_apple with appropriate arguments.
  3. Initial a variable to store the total score to 0.
  4. While num_moves_to_execute is not yet 0 and the snakes length is still less than 35 and the player hasnt lost (e.g., by running into a wall or intersecting the snake itself) and there are still directions left to consider:
    1. Get the next direction to move from directions.
    2. Call move_snake with appropriate arguments.
      1. If move_snake returned a score of 100, then add score * (state.length 1) to the total score.
      2. On the other hand, if move_snake returned a result of -1, indicating failure to move the snake, immediately break out of the loop.
    3. Decrement num_moves_to_execute by 1.
  5. Return the number of executed moves in $v0 and the total score in $v1.

The function takes the following arguments, in this order:

  • state: a pointer to (i.e., starting memory address of) an uninitialized GameState struct large enough to hold the contents of the game represented by file to be loaded. Assume that the contents of the struct are filled with random garbage.
  • filename: a string containing the filename to open and read the contents of
  • directions: a null-terminated string of characters representing directions to move the snake. Each character is guaranteed to be one of U, D, L or R. You do not need to validate the contents of directions .
  • num_moves_to_execute: the maximum number of characters to read from directions apples: an array of apples_length pairs of 8-bit, twos complement integers Available at 0($sp).
  • apples_length: the number of pairs of integers in apples . Available at 4($sp).

Returns in $v0:

  • The number of moves executed.

Returns in $v1:

  • The total score at the end of the simulated game.

Additional requirements:

  • The function must not write any changes to main memory.
  • The function must call load_game , place_next_apple and move_snake

Examples:

Due to the complexity of the function arguments, examples of simulate_game are provided in simulate_game_test1.txt, simulate_game_test2.txt , etc., along with function arguments.

Reviews

There are no reviews yet.

Only logged in customers who have purchased this product may leave a review.

Shopping Cart
[Solved] CSE220-Programming Assignment 3
$25