####################################################################################################################### # # 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"