# init
true = 1
false = 0
CONNECT = 4
MIN_BOARD_DIMENSION = 4
MAX_BOARD_WIDTH = 9
MAX_BOARD_HEIGHT = 16
CELL_EMPTY = '.'
CELL_RED = 'R'
CELL_YELLOW = 'Y'
WINNER_NONE = 0
WINNER_RED = 1
WINNER_YELLOW = 2
TURN_RED = 0
TURN_YELLOW = 1
.data
# char board[MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
board: .space MAX_BOARD_HEIGHT * MAX_BOARD_WIDTH
board_width: .word 0
board_height: .word 0
enter_board_width_str: .asciiz "Enter board width: "
enter_board_height_str: .asciiz "Enter board height: "
game_over_draw_str: .asciiz "The game is a draw!\n"
game_over_red_str: .asciiz "Game over, Red wins!\n"
game_over_yellow_str: .asciiz "Game over, Yellow wins!\n"
board_too_small_str_1: .asciiz "Board dimension too small (min "
board_too_small_str_2: .asciiz ")\n"
board_too_large_str_1: .asciiz "Board dimension too large (max "
board_too_large_str_2: .asciiz ")\n"
red_str: .asciiz "[RED] "
yellow_str: .asciiz "[YELLOW] "
choose_column_str: .asciiz "Choose a column: "
invalid_column_str: .asciiz "Invalid column\n"
no_space_column_str: .asciiz "No space in that column!\n"
debug: .asciiz "Debug:\n"
.text
main:
# Args: void
# Returns:
# - $v0: int
#
# Frame: [$ra, ...]
# Uses: [...]
# Clobbers: [...]
#
# Locals:
# - [...]
#
# Structure:
# main
# -> [prologue]
# -> body
# -> [epilogue]
main__prologue:
begin # begin a new stack frame
push $ra # | $ra
main__body:
# check valid board dimensions
# print width string
la $a0, enter_board_width_str
li $v0, 4
syscall
# read and store width integer into board_width
li $v0, 5 # read integer
syscall
la $t0, board_width
sw $v0, ($t0)
move $a0, $v0
li $a1, MIN_BOARD_DIMENSION
li $a2, MAX_BOARD_WIDTH
jal assert_board_dimension
# print height string
la $a0, enter_board_height_str
li $v0, 4
syscall
# read and store height integer into board_height
li $v0, 5
syscall
la $t1, board_height
sw $v0, ($t1)
move $a0, $v0
li $a1, MIN_BOARD_DIMENSION
li $a2, MAX_BOARD_HEIGHT
jal assert_board_dimension
# initialise board
jal initialise_board
# print board
jal print_board
# play game
jal play_game
main__epilogue:
pop $ra # | $ra
end # ends the current stack frame
li $v0, 0
jr $ra # return 0;
########################################################################
# .TEXT <assert_board_dimension>
.text
assert_board_dimension:
# Args:
# - $a0: int dimension
# - $a1: int min
# - $a2: int max
# Returns: void
#
# Frame: [...]
# Uses: [...]
# Clobbers: [...]
#
# Locals:
# - [...]
#
# Structure:
# assert_board_dimension
# -> [prologue]
# -> body
# -> [epilogue]
assert_board_dimension__prologue:
begin
push $ra
assert_board_dimension__body:
blt $a0, $a1, assert_board_dimension__small
bgt $a0, $a2, assert_board_dimension__large
assert_board_dimension__epilogue:
pop $ra
end
jr $ra # return;
assert_board_dimension__small:
la $a0, board_too_small_str_1
li $v0, 4
syscall
li $a0, 4
li $v0, 1
syscall
la $a0, board_too_small_str_2
li $v0, 4
syscall
# returns with error code 1
li $a0, 1
li $v0, 17
syscall
assert_board_dimension__large:
la $a0, board_too_large_str_1
li $v0, 4
syscall
li $a0, 16
li $v0, 1
syscall
la $a0, board_too_large_str_2
li $v0, 4
syscall
# returns with error code 1
li $a0, 1
li $v0, 17
syscall
#j assert_board_dimension__epilogue
########################################################################
# .TEXT <initialise_board>
.text
initialise_board:
# Args: void
# Returns: void
#
# Frame: [...]
# Uses: [...]
# Clobbers: [...]
#
# Locals:
# - [...]
#
# Structure:
# initialise_board
# -> [prologue]
# -> body
# -> [epilogue]
initialise_board__prologue:
begin
push $ra
initialise_board__body:
li $s0, 0 # row
la $t0, board
lw $t6, board_width
lw $t7, board_height
initialise_board__row_loop:
bge $s0, $t7, initialise_board__row_end
li $s1, 0 # col
initialise_board__col_loop:
bge $s1, $t6, initialise_board__col_end
# adding row offset
mul $t1, $s0, MAX_BOARD_WIDTH
# adding col offset
add $t3, $t1, $s1
li $t4, CELL_EMPTY
sb $t4, board($t3)
addi $s1, $s1, 1
b initialise_board__col_loop
initialise_board__col_end:
addi $s0, $s0, 1
b initialise_board__row_loop
initialise_board__row_end:
# clearing variables
li $s0, 0
li $s1, 0
initialise_board__epilogue:
pop $ra
end
jr $ra # return;
########################################################################
# .TEXT <play_game>
.text
play_game:
# Args: void
# Returns: void
#
# Frame: [...]
# Uses: [...]
# Clobbers: [...]
#
# Locals:
# - [...]
#
# Structure:
# play_game
# -> [prologue]
# -> body
# -> [epilogue]
play_game__prologue:
begin
push $ra
play_game__body:
li $s4, TURN_RED
li $s3, WINNER_NONE
play_game__loop:
bne $s3, WINNER_NONE, play_game__check
jal is_board_full
beq $v0, true, play_game__check
move $a0, $s4
jal play_turn
move $s4, $v0
jal print_board
jal check_winner
move $s3, $v0
b play_game__loop
play_game__check:
li $t0, WINNER_NONE
li $t1, WINNER_RED
li $t2, WINNER_YELLOW
beq $s3, $t0, play_game__draw
beq $s3, $t1, play_game__red
beq $s3, $t2, play_game__yellow
play_game__draw:
la $a0, game_over_draw_str
li $v0, 4
syscall
j play_game__epilogue
play_game__red:
la $a0, game_over_red_str
li $v0, 4
syscall
j play_game__epilogue
play_game__yellow:
la $a0, game_over_yellow_str
li $v0, 4
syscall
j play_game__epilogue
play_game__epilogue:
pop $ra
end
jr $ra # return;
########################################################################
# .TEXT <play_turn>
.text
play_turn:
# Args:
# - $a0: int whose_turn
# Returns: void
#
# Frame: [...]
# Uses: [...]
# Clobbers: [...]
#
# Locals:
# - [...]
#
# Structure:
# play_turn
# -> [prologue]
# -> body
# -> [epilogue]
play_turn__prologue:
begin
push $ra
lb $t0, board_width
play_turn__prints:
move $s0, $a0
beq $s0, TURN_RED, play_turn__print_red
beq $s0, TURN_YELLOW, play_turn__print_yellow
play_turn__print_red:
la $a0, red_str
li $v0, 4
syscall
j play_turn__body
play_turn__print_yellow:
la $a0, yellow_str
li $v0, 4
syscall
j play_turn__body
play_turn__body:
la $a0, choose_column_str
li $v0, 4
syscall
li $v0, 5
syscall
move $s1, $v0
sub $s1, $s1, 1 # user input 1-indexed (column)
blt $s1, $zero, play_turn__invalid
bge $s1, $t0, play_turn__invalid
lb $s2, board_height
sub $s2, $s2, 1 # row
play_turn__loop:
blt $s2, 0, play_turn__body_cont
li $t7, MAX_BOARD_WIDTH
mul $t0, $s2, $t7
add $t0, $t0, $s1
lb $t2, board($t0)
beq $t2, 46, play_turn__body_cont
sub $s2, $s2, 1
blt $s2, 0, play_turn__full
b play_turn__loop
play_turn__body_cont:
beq $s0, TURN_RED, play_turn__set_red
beq $s0, TURN_YELLOW, play_turn__set_yellow
play_turn__set_red:
mul $t0, $s2, MAX_BOARD_WIDTH
add $t0, $s1
li $t1, CELL_RED
sb $t1, board($t0)
li $s0, TURN_YELLOW
j play_turn__epilogue
play_turn__set_yellow:
mul $t0, $s2, MAX_BOARD_WIDTH
add $t0, $s1
li $t1, CELL_YELLOW
sb $t1, board($t0)
li $s0, TURN_RED
j play_turn__epilogue
play_turn__invalid:
la $a0, invalid_column_str
li $v0, 4
syscall
j play_turn__epilogue
play_turn__full:
la $a0, no_space_column_str
li $v0, 4
syscall
j play_turn__epilogue
play_turn__epilogue:
la $v0, ($s0)
pop $ra
end
jr $ra # return;
########################################################################
# .TEXT <check_winner>
.text
check_winner:
# Args: void
# Returns:
# - $v0: int
#
# Frame: [...]
# Uses: [...]
# Clobbers: [...]
#
# Locals:
# - [...]
#
# Structure:
# check_winner
# -> [prologue]
# -> body
# -> [epilogue]
check_winner__prologue:
begin
push $ra
check_winner__body:
li $s0, 0 # row
lw $t6, board_width
lw $t7, board_height
check_winner__row_loop:
bge $s0, $t7, check_winner__row_end
li $s1, 0 # col
check_winner__col_loop:
bge $s1, $t6, check_winner__col_end
# computing row offset
mul $t2, $s0, MAX_BOARD_WIDTH
# computing col offset
add $t2, $s1
## check vertical line
move $a0, $s0
move $a1, $s1
li $a2, 1
li $a3, 0
jal check_line
bne $v0, WINNER_NONE, check_winner__epilogue
# check horizontal line
move $a0, $s0
move $a1, $s1
li $a2, 0
li $a3, 1
jal check_line
bne $v0, WINNER_NONE, check_winner__epilogue
# check gradient = -1 line
move $a0, $s0
move $a1, $s1
li $a2, 1
li $a3, 1
jal check_line
bne $v0, WINNER_NONE, check_winner__epilogue
# check gradient = 1 line
move $a0, $s0
move $a1, $s1
li $a2, 1
li $a3, -1
jal check_line
bne $v0, WINNER_NONE, check_winner__epilogue
addiu $s1, 1
j check_winner__col_loop
check_winner__col_end:
addiu $s0, 1
j check_winner__row_loop
check_winner__row_end:
check_winner__epilogue:
pop $ra
end
jr $ra # return;
########################################################################
# .TEXT <check_line>
.text
check_line:
# Args:
# - $a0: int start_row
# - $a1: int start_col
# - $a2: int offset_row
# - $a3: int offset_col
# Returns:
# - $v0: int
#
# Frame: [...]
# Uses: [...]
# Clobbers: [...]
#
# Locals:
# - [...]
#
# Structure:
# check_line
# -> [prologue]
# -> body
# -> [epilogue]
check_line__prologue:
begin
push $ra
lw $s2, board_height
lw $s5, board_width
# calculating offset
mul $t0, $a0, MAX_BOARD_WIDTH
add $t0, $t0, $a1 # first_cell
lb $t1, board($t0)
beq $t1, CELL_EMPTY, check_line__winner_none
add $t2, $a0, $a2 # row
add $t3, $a1, $a3 # col
# how many connects required
li $t5, CONNECT
sub $t5, $t5, 1
# i for loop
li $t4, 0
# clearing t7 register
li $t8, 0
check_line__body:
bge $t4, $t5, check_line__body_cont
blt $t2, $zero, check_line__winner_none
blt $t3, $zero, check_line__winner_none
bge $t2, $s2, check_line__winner_none
bge $t3, $s5, check_line__winner_none
mul $t8, $t2, MAX_BOARD_WIDTH
add $t8, $t8, $t3 # board[row][col]
lb $t9, board($t8)
bne $t1, $t9, check_line__winner_none
add $t2, $t2, $a2
add $t3, $t3, $a3
addiu $t4, 1
b check_line__body
check_line__winner_none:
li $v0, WINNER_NONE
j check_line__epilogue
check_line__winner_red:
li $v0, WINNER_RED
j check_line__epilogue
check_line__winner_yellow:
li $v0, WINNER_YELLOW
j check_line__epilogue
check_line__body_cont:
beq $t1, CELL_RED, check_line__winner_red
beq $t1, CELL_YELLOW, check_line__winner_yellow
check_line__epilogue:
pop $ra
end
jr $ra # return;
########################################################################
# .TEXT <is_board_full>
# YOU DO NOT NEED TO CHANGE THE IS_BOARD_FULL FUNCTION
.text
is_board_full:
# Args: void
# Returns:
# - $v0: bool
#
# Frame: []
# Uses: [$v0, $t0, $t1, $t2, $t3]
# Clobbers: [$v0, $t0, $t1, $t2, $t3]
#
# Locals:
# - $t0: int row
# - $t1: int col
#
# Structure:
# is_board_full
# -> [prologue]
# -> body
# -> loop_row_init
# -> loop_row_cond
# -> loop_row_body
# -> loop_col_init
# -> loop_col_cond
# -> loop_col_body
# -> loop_col_step
# -> loop_col_end
# -> loop_row_step
# -> loop_row_end
# -> [epilogue]
is_board_full__prologue:
is_board_full__body:
li $v0, true
is_board_full__loop_row_init:
li $t0, 0 # int row = 0;
is_board_full__loop_row_cond:
lw $t2, board_height
bge $t0, $t2, is_board_full__epilogue # if (row >= board_height) goto is_board_full__loop_row_end;
is_board_full__loop_row_body:
is_board_full__loop_col_init:
li $t1, 0 # int col = 0;
is_board_full__loop_col_cond:
lw $t2, board_width
bge $t1, $t2, is_board_full__loop_col_end # if (col >= board_width) goto is_board_full__loop_col_end;
is_board_full__loop_col_body:
mul $t2, $t0, MAX_BOARD_WIDTH # row * MAX_BOARD_WIDTH
add $t2, $t2, $t1 # row * MAX_BOARD_WIDTH + col
lb $t3, board($t2) # board[row][col];
bne $t3, CELL_EMPTY, is_board_full__loop_col_step # if (cell != CELL_EMPTY) goto is_board_full__loop_col_step;
li $v0, false
b is_board_full__epilogue # return false;
is_board_full__loop_col_step:
addi $t1, $t1, 1 # col++;
b is_board_full__loop_col_cond # goto is_board_full__loop_col_cond;
is_board_full__loop_col_end:
is_board_full__loop_row_step:
addi $t0, $t0, 1 # row++;
b is_board_full__loop_row_cond # goto is_board_full__loop_row_cond;
is_board_full__loop_row_end:
is_board_full__epilogue:
jr $ra # return;
########################################################################
# .TEXT <print_board>
# YOU DO NOT NEED TO CHANGE THE PRINT_BOARD FUNCTION
.text
print_board:
# Args: void
# Returns: void
#
# Frame: []
# Uses: [$v0, $a0, $t0, $t1, $t2]
# Clobbers: [$v0, $a0, $t0, $t1, $t2]
#
# Locals:
# - `int col` in $t0
# - `int row` in $t0
# - `int col` in $t1
#
# Structure:
# print_board
# -> [prologue]
# -> body
# -> for_header_init
# -> for_header_cond
# -> for_header_body
# -> for_header_step
# -> for_header_post
# -> for_row_init
# -> for_row_cond
# -> for_row_body
# -> for_col_init
# -> for_col_cond
# -> for_col_body
# -> for_col_step
# -> for_col_post
# -> for_row_step
# -> for_row_post
# -> [epilogue]
print_board__prologue:
print_board__body:
li $v0, 11 # syscall 11: print_int
la $a0, '\n'
syscall # printf("\n");
print_board__for_header_init:
li $t0, 0 # int col = 0;
print_board__for_header_cond:
lw $t1, board_width
blt $t0, $t1, print_board__for_header_body # col < board_width;
b print_board__for_header_post
print_board__for_header_body:
li $v0, 1 # syscall 1: print_int
addiu $a0, $t0, 1 # col + 1
syscall # printf("%d", col + 1);
li $v0, 11 # syscall 11: print_character
li $a0, ' '
syscall # printf(" ");
print_board__for_header_step:
addiu $t0, 1 # col++
b print_board__for_header_cond
print_board__for_header_post:
li $v0, 11
la $a0, '\n'
syscall # printf("\n");
print_board__for_row_init:
li $t0, 0 # int row = 0;
print_board__for_row_cond:
lw $t1, board_height
blt $t0, $t1, print_board__for_row_body # row < board_height
b print_board__for_row_post
print_board__for_row_body:
print_board__for_col_init:
li $t1, 0 # int col = 0;
print_board__for_col_cond:
lw $t2, board_width
blt $t1, $t2, print_board__for_col_body # col < board_width
b print_board__for_col_post
print_board__for_col_body:
mul $t2, $t0, MAX_BOARD_WIDTH
add $t2, $t1
## debug
#la $a0, ($t2)
#li $v0, 1
#syscall
## debug
lb $a0, board($t2) # board[row][col]
li $v0, 11 # syscall 11: print_character
syscall # printf("%c", board[row][col]);
li $v0, 11 # syscall 11: print_character
li $a0, ' '
syscall # printf(" ");
print_board__for_col_step:
addiu $t1, 1 # col++;
b print_board__for_col_cond
print_board__for_col_post:
li $v0, 11 # syscall 11: print_character
li $a0, '\n'
syscall # printf("\n");
print_board__for_row_step:
addiu $t0, 1
b print_board__for_row_cond
print_board__for_row_post:
print_board__epilogue:
jr $ra # return;