#######################################################################################################################
#
#                                  Bagnacani Andrea     -     Bigliardi Luca
#
#                                       Progetto Assembly AA 2004/2005
#                                                    Dama
#
#----------------------------------------------------------------------------------------------------------------------
#
# Descrizione:
# Il programma non ha chiamate a funzioni ausiliarie in quanto, a parte alcune istruzioni di inizio
# e fine (init_grid, end_game), tutto il codice si ripete ciclicamente ad ogni input.
# 
# All'entrata del programma il codice init_grid viane utilizzato per facilitare il puntamento
# ad una pedina nelle parti successive del programma, in questo modo si ha accesso diretto all'indirizzo di
# memoria di ogni riga della matrice che rappresenta la griglia di gioco attraverso il vettore "pezzi".
#
# main_loop e' il ciclo principale del programma, esso si puo' suddividere in tre grandi blocchi:
# - stampa della scacchiera
#	Attraverso due cicli annidati viene visitata tutta la griglia di gioco.
#	Ad ogni elemento esaminato viene associato (e stampato) un carattere secondo il seguente mapping:
#		0 = bianco        ==> print 'o'
#		1 = nero          ==> print 'x'
#		2 = damone bianco ==> print 'O'
#		3 = damone nero   ==> print 'X'
#		4 = casella vuota ==> print ' '
#	Registri utilizzati:
#		$t0 => contiene l'indice delle righe
#		$t1 => contiene l'indice delle colonne
#		$t2 => utilizzato per memorizzare valori locali
#		$t3 => utilizzato per memorizzare valori locali
#	
# - richiesta mossa
#	Viene stampato un prompt (mossa bianco / mossa nero) in base al valore di $s0. Alla prima esecuzione
#	$s0 vale 0 (per le proprieta' dell'emulatore), quindi il turno e' bianco. L'input dato viene immagazzinato
#	in un buffer: move_buffer.
#	
# - verifiche sulla mossa ed eventuale mossa
#	In successione vengono verificate le seguenti condizioni:
#		+ sorgente: la pedina puntata e' sulla griglia ? appartiene al giocatore corrente ? 
#		+ destinazione: la casella puntata e' sulla griglia ? e' vuota ?
#		+ mossa: esiste spostamento ? lo spostamento e' diagonale ? lo spostamento e' di una casella o di due ?
#		+ mangiata: nel caso in cui lo spostamento sia di due, viene mangiata solo una pedina avversaria ?
#			    posso proclamare un vincitore ed uscire ?
#		+ promozione: la pedina e' arrivata al margine opposto della griglia di gioco ? posso promuoverla ?
# 	Nel caso in cui una delle condizioni non sia rispettata si salta ad 'input_error' che stampa un messaggio
#	di errore e fa ricominciare il main_loop.
#	In questa parte di programma vengono utilizzati molti registri per immagazzinare dati anziche' dover accedere
#	alla memoria ogni volta che si ha bisogno di questi.
#	Registri utilizzati:
#		$s0 = turno   ==> 0 = bianco , 1 = nero
#		$s1 = damone  ==> 0 = pedina , 1 = damone
#		$s2 = x1      ==> ascissa sorgente
#		$s3 = y1      ==> ordinata sorgente
#		$s4 = x2      ==> ascissa destinazione
#		$s5 = y2      ==> ordinata destinazione
#		$s6 = x2 - x1 ==> gap ascissa
#		$s7 = y2 - y1 ==> gap ordinata
#		$t5 = tipo pedina sorgente
#		$t6 = tipo pedina destinazione
#		$t7 = tipo pedina mangiata
#


	.text
	.globl main

main:

init_grid:				# inizializza le componenti di pezzi con l'indirizzo di memoria
	bgt $t0, 28, end_init_grid	# dell'array a cui si riferiscono
	lw $t1, pezzi($t0)
	la $t1, ($t1)
	sw $t1, pezzi($t0)
	addu $t0, $t0, 4
end_init_grid:

main_loop:
	li $v0, 4			######### INIZIO STAMPA SCACCHIERA
	la $a0, border			# stampa margine superiore
	syscall
print_grid:				# stampa griglia scacchiera con due cicli annidati (ext=riga int=col)
	li $t0, 7			# $t0 = indice riga
	li $t1, 0			# $t1 = indice colonna
print_raws:
	bltz $t0, end_print_grid	# ciclo su ogni riga (se < 0 la griglia e' completa)
	sll $t2, $t0, 2
	lw $t2, pezzi($t2)
	li $v0, 1			# stampo il numero della riga
	move $a0, $t0
	addu $a0, $a0, 1
	syscall
	li $v0, 4
	la $a0, blank
	syscall
print_cols:
	li $v0, 4			# stampo separatore
	la $a0, pipe
	syscall
	bgt $t1, 7, print_endline	# ciclo per ogni elemento di una riga (se > 7 sono a fine riga)
char_printing:				# determino il tipo di pezzo
	lb $t3, ($t2)
	sll $t3, $t3, 2
	lw $t3, print_type($t3)		# in base al tipo di pezzo stampo un carattere (non c'e' il default case
	jr $t3				# poiche' non sono possibili altri casi)
print_blank :				# Mapping:	0 = bianco ==> print white
	li $v0, 4			#		1 = nero ==> print black
	la $a0, blank			#		2 = damone bianco ==> print White
	syscall				#		3 = damone nero ==> print Black
	j end_char_printing		#		4 = casella vuota ==> print blank
print_black :
	li $v0, 4
	la $a0, black
	syscall
	j end_char_printing
print_white :   
	li $v0, 4
	la $a0, white
	syscall
	j end_char_printing
print_Black :   
	li $v0, 4
	la $a0, Black
	syscall
	j end_char_printing
print_White :   
	li $v0, 4
	la $a0, White
	syscall
end_char_printing:			# ho finito di determinare il tipo di pezzo
	addu $t1, $t1, 1
	addu $t2, $t2, 1
	j print_cols
print_endline:				# finisci stampa riga e vai a capo
	li $v0, 4
	la $a0, newline
	syscall
	li $t1, 0
	subu $t0, $t0, 1
	j print_raws
end_print_grid:
	li $v0, 4			# stampa margine inferiore
	la $a0, border
	syscall
	li $v0, 4			# stampa lettere sotto scacchiera
	la $a0, letters
	syscall

					######### INIZIO GESTIONE INPUT
	
	bnez $s0, black_move
	li $v0, 4			# stampo il prompt (confronto il flag per vedere chi deve giocare)
	la $a0, white_prompt
	syscall
	j end_move_req
black_move:
	li $v0, 4
	la $a0, black_prompt
	syscall
end_move_req:
	li $v0, 8
	la $a0, move_buffer		# salvo l'input
	li $a1, 128
	syscall

#-------------------CHECK VALID MOVE
	li $s1, 0			# reinizializzo registri usati per la stampa ed i flag degli attributi:
	li $t0, 0			# $s1 = flag damone ( 0 = dama, 1 = damone)
	li $t1, 0
	li $t2, 0
	li $t3, 0

					# Mapping:	$s2 = x1
					#		$s3 = y1
					#		$s4 = x2
					#		$s5 = y2
					#		$s6 = x2 - x1
					#		$s7 = y2 - y1
					#		$t5 = codice src
					#		$t6 = codice dst
					#		$t7 = codice eat
	lbu $t1, move_buffer($t0)	# load and check x1
	subu $s2, $t1, 65
	bltz $s2, input_error
	bgt $s2, 7, input_error
	addu $t0, $t0, 1
	lbu $t1, move_buffer($t0)	# load and check y1
	subu $s3, $t1, 49
	bltz $s3, input_error
	bgt $s3, 7, input_error
	sll $t1, $s3, 2			# carica codice src
	lw $t1, pezzi($t1)
	addu $t1, $t1, $s2
	lbu $t5, ($t1)
	move $t1, $t5			# copiamo il codice perche' poi lo modifichiamo
	beq $t1, 4, input_error		# controllo che ci sia una pedina
	blt $t1, 2, is_dama		# controllo che la sorgente appartenga al giocatore
	li $s1, 1			# (qui so sicuramente che e' damone)
	subu $t1, $t1, 2
is_dama:
	bne $t1, $s0, input_error
	addu $t0, $t0, 1		# check x2
	lbu $t1, move_buffer($t0)
	subu $s4, $t1, 65
	bltz $s4, input_error
	bgt $s4, 7, input_error
	addu $t0, $t0, 1		# check y2
	lbu $t1, move_buffer($t0)
	subu $s5, $t1, 49
	bltz $s5, input_error
	bgt $s5, 7, input_error
	sll $t1, $s5, 2			# carica codice dst
	lw $t1, pezzi($t1)
	addu $t1, $t1, $s4
	lbu $t6, ($t1)
	bne $t6, 4, input_error		# controllo che la destinazione sia blank
	
	subu $s6, $s4, $s2		# carico x2-x1 e y2-y1
	subu $s7, $s5, $s3

	beqz $s6, input_error		# non puo' essere 0 il gap, non controllo le y
					# perche' qui sotto guardo se lo spostamento
					# e' la diagonale di un quadrato:
	abs $t0, $s7			# t0 = |y2-y1|
	abs $t1, $s6			# t1 = |x2-x1|
	bne $t0, $t1, input_error	# controllo che |x2-x1| = |y2-y1|
						
					# controllo direzione pedine
	bnez $s1, end_check_direction	# il damone si muove in qualsiasi direzione
	beqz $s0, white_direction
	bgt $s7, -1, input_error
	j end_check_direction
white_direction:
	blt $s7, 1, input_error
end_check_direction:

	beq $t0, 1, simple_move		# in $t0 ho ancora il valore assoluto,
	beq $t0, 2, check_eat		# controllo che tipo di mossa ho fatto
	bgt $t0, 2, input_error


check_eat:
	bltz, $s6, left_eat_x		# controllo in che direzione mangio e carico
	addu $t0, $s2, 1		# le coordinate della pedina mangiata
	j check_eat_y			# ( $t0 = x, $t1 = y )
left_eat_x:
	subu $t0, $s2, 1
check_eat_y:
	bltz $s7, left_eat_y
	addu $t1, $s3, 1
	j load_type
left_eat_y:
	subu $t1, $s3, 1
load_type:
	sll $t2, $t1, 2
	lw $t2, pezzi($t2)
	addu $t0, $t2, $t0		# carico in $t0 l'indirizzo della pedina
	lbu $t1, ($t0)			# carico il tipo di pedina mangiata in $t1
	beq $t1, 4, input_error		# controllo che ci sia una pedina
	blt $t1, 2, is_dama_eat		# controllo se dama o damone
	li $t3, 1			# $t3 = 1 se il mangiato e' un damone
	subu $t1, $t1, 2
is_dama_eat:
	beq $t1, $s0, input_error	# se la pedina mangiata e' mia errore
	bnez $s1, eat_baby		# se sono damone posso fare tutto
	bnez $t3, input_error		# io sono pedina, se lui e' damone errore
eat_baby:
	li $t4, 4			# elimino la pedina
	sb $t4, ($t0)
	beqz $t1, decr_white		# aggiorno il rispettivo contatore
	la $t0, b_counter
	j decr
decr_white:
	la $t0, w_counter
decr:
	lb $t1, ($t0)
	subu $t1, $t1, 1
	sb $t1, ($t0)
	
	lb $t0, b_counter		# controllo il numero di pezzi neri
	bnez $t0, white_counter		# se sono zero il bianco ha vinto ed esco
	li $v0, 4
	la $a0, white_wins
	syscall
	j end_game
white_counter:
	lb $t0, w_counter		# controllo il numero di pezzi bianchi
	bnez $t0, simple_move		# se sono zero il nero ha vinto ed esco
	li $v0, 4			# (altrimenti faccio un altro ciclo)
	la $a0, black_wins
	syscall
	j end_game
	
simple_move:
	sll $t0, $s3, 2			# carico indirizzo src in t0
	lw $t0, pezzi($t0)
	addu $t0, $t0, $s2
	li $t1, 4
	sb $t1, ($t0)			# tolgo la pedina
	sll $t0, $s5, 2			# carico indirizzo dst in t0
	lw $t0, pezzi($t0)
	addu $t0, $t0, $s4
	bnez $s1, insert_dst		# se sono damone non controllo se posso diventarlo
	beqz $s0, damone_white		# se y2 e' l'altra estremita' della scacchiera mi promuovo
	bnez $s5, insert_dst
	addu $t5, $t5, 2
	j insert_dst
damone_white:
	bne $s5, 7, insert_dst
	addu $t5, $t5, 2
insert_dst:
	sb $t5, ($t0)			# inserisco la pedina
	
	xori $s0, $s0, 1		# cambio il turno
	j main_loop

input_error:				# stampo un messaggio di errore e ritorno al prompt
	li $v0, 4
	la $a0, error_message
	syscall
	j main_loop

end_game:
	jr $ra



		.data
pezzi:	.word r0, r1, r2, r3, r4, r5, r6, r7
r0:	.byte 4, 0, 4, 0, 4, 0, 4, 0
r1:	.byte 0, 4, 0, 4, 0, 4, 0, 4
r2:	.byte 4, 0, 4, 0, 4, 0, 4, 0
r3:	.byte 4, 4, 4, 4, 4, 4, 4, 4
r4:	.byte 4, 4, 4, 4, 4, 4, 4, 4
r5:	.byte 1, 4, 1, 4, 1, 4, 1, 4
r6:	.byte 4, 1, 4, 1, 4, 1, 4, 1
r7:	.byte 1, 4, 1, 4, 1, 4, 1, 4

print_type:	.word print_white, print_black, print_White, print_Black, print_blank
border:		.asciiz "  -----------------\n"
letters:	.asciiz "   A B C D E F G H\n"
newline:	.asciiz "\n"
blank:		.asciiz " "
pipe:		.asciiz "|"
black:		.asciiz "x"
white:		.asciiz "o"
Black:		.asciiz "X"
White:		.asciiz "O"
white_prompt:	.asciiz "mossa bianco: "
black_prompt:	.asciiz "mossa nero: "
move_buffer:	.space 128
b_counter:	.byte 12
w_counter:	.byte 12
error_message:	.asciiz "\nThe expression you entered is wrong,\nplease type again.\n\n"
white_wins:	.asciiz "\nWhite has won!\n"
black_wins:	.asciiz "\nBlack has won!\n"
