-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmaze.asm
324 lines (254 loc) · 8.6 KB
/
maze.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
.data
################# Configuração do Labirinto #################
maze: .byte 'X','_','_','_','_'
.byte '_','#','#','#','#'
.byte '_','_','_','_','_'
.byte '#','#','#','#','_'
.byte '#','#','#','#','X'
start: .word 0 #x do início
.word 0 #y do início
size: .word 5 #linhas (size) => x
.word 5 #colunas 4(size) => y
step: .byte -1 #passo-a-passo: -1: não mostra, 1: mostra
elem: .word 25 #elementos na matriz
visited: .byte 0:25 #visitados memset(0)
##################### Variáveis Internas #####################
newline: .byte '\n'
pos: .word 0, -1 #(x, y-1)
.word 0, 1 #(x, y+1)
.word -1, 0 #(x-1, y)
.word 1, 0 #(x+1, y)
wall: .byte '#'
walkable: .byte '_'
walked: .byte 'o'
end: .byte 'X'
str_ori: .asciiz "Labirinto Original:\n\n"
str_sol: .asciiz "Solução do Labirinto:\n\n"
str_step: .asciiz "Passo a passo do algoritmo:\n\n"
str_no: .asciiz "O Labirinto não possui solução.\n"
###############################################################
.text
#macro para imprimir uma string, recebe o ponteiro da string como arg
.macro print_str($arg)
la $a0, $arg
li $v0, 4 #print_string
syscall
.end_macro
main:
#exibe o labirinto original
print_str(str_ori)
jal print
#resolve o labirinto
jal solve
exit:
li $v0, 10
syscall
###
### Chama a função que resolve o labirinto e verifica se foi resolvido ou não, imprimindo o resultado.
###
solve:
#salva o endereço de retorno da função
subu $sp, $sp, 4
sw $ra, 0($sp)
lb $t5, step
bgezal $t5, step_str
#chama dfs(start.x, start.y)
la $t0, start
lw $a0, 0($t0)
lw $a1, 4($t0)
jal dfs
#se o retorno for 0, não existe solução
beqz $v0, solution_notfound
#caso contrário, "maze" conterá a solucão
j solution_found
solution_found:
print_str(str_sol) #chama a macro para imprimir str_sol
jal print
j solve_end
solution_notfound:
print_str(str_no) #chama a macro para imprimir str_no
solve_end:
#carrega o endereço de retorno da função e pula para ele
lw $ra, 0($sp)
addiu $sp, $sp, 4
jr $ra
step_str:
#salva o endereço de retorno da função
subu $sp, $sp, 4
sw $ra, 0($sp)
print_str(str_step)
#carrega o endereço de retorno da função e pula para ele
lw $ra, 0($sp)
addiu $sp, $sp, 4
jr $ra
###
### Busca em profundidade recursiva, tenta chegar
### ao fim do labirinto enquanto existirem movimentos válidos
### Parâmetros: $a0 = x, $a1 = y
### Utiliza os seguintes registradores preservados pela chamada:
### $s0 = x
### $s1 = y
### $s2 = novox*linhas+novoy
### $s3 = contador de variações
### $s4 = novox (variação do x)
### $s5 = novoy (variação do y)
### Retorno: $v0 contendo 0 para sem solução ou 1 para com solução
### Caso tenha solução, a solução estará no "maze"
###
dfs:
#aloca espaço na pilha
subu $sp, $sp, 32
#salva o endereço de retorno da função
sw $ra, 28($sp)
#salva os registradores que serão modificados pela função
sw $s0, 24($sp)
sw $s1, 20($sp)
sw $s2, 16($sp)
sw $s3, 12($sp)
sw $s4, 8($sp)
sw $s5, 4($sp)
#salva x e y originais
move $s0, $a0
move $s1, $a1
lw $t0, size #carrega o tamanho da linha
#posição no array = x*n+y
multu $a0, $t0
mflo $t0
addu $t0, $t0, $a1
#visiteda (x,y)
li $t1, 1
sb $t1, visited($t0)
li $s3, 0 #i = 0
dfs_loop:
beq $s3, 32, dfs_loop_end #repete o loop para 8 words, consumindo 2 por iteração
#lê 2 inteiros, variação de x e y
lw $t0, pos($s3) #varx
lw $t1, pos+4($s3) #vary
addi $s3, $s3, 8 #i+=2
#gera e salva o novox e novoy
add $s4, $s0, $t0 #novox = x+varx
add $s5, $s1, $t1 #novoy = y+vary
#chama coord_check(novox, novoy)
move $a0, $s4 #novox
move $a1, $s5 #novoy
jal coord_check
#se retornar 0, ignora pois é uma coordenada inválida
beqz $v0, dfs_loop
#guarda a posicao (pos = x*n+y) da nova coordenada
move $s2, $v0
#carrega nos registradores temporários os caracteres
lb $t0, maze($s2)
lb $t1, end
lb $t2, walkable
#encontrou o caractere do fim, retorna true
beq $t0, $t1, dfs_found
#encontrou uma parede, ignora e passa para a próxima iteração
bne $t0, $t2, dfs_loop
#muda o maze[novox][novoy] para o caractere "walked"
lb $t3, walked
sb $t3, maze($s2)
lb $t5, step
bgezal $t5, print
#chamada recursiva dfs(novox, novoy)
move $a0, $s4
move $a1, $s5
jal dfs
#se achou na chamada recursiva, retorna true
bnez $v0, dfs_found
#backtracking, como não achou nas chamadas recursivas pode remover o "walked" de maze[novox][novoy]
#pois ele não faz parte de um caminho válido
lb $t3, walkable
sb $t3, maze($s2)
lb $t5, step
bgezal $t5, print
#próxima iteração
j dfs_loop
dfs_loop_end:
li $v0, 0 #retorna false
j dfs_return
dfs_found:
li $v0, 1 #retorna true
dfs_return:
#carrega o endereço de retorno
lw $ra, 28($sp)
#carrega os registradores para os anteriores à chamada da função
lw $s0, 24($sp)
lw $s1, 20($sp)
lw $s2, 16($sp)
lw $s3, 12($sp)
lw $s4, 8($sp)
lw $s5, 4($sp)
#decrementa a pilha
addiu $sp, $sp, 32
#pula para o endereço de retorno da função
jr $ra
###
### Checa se a coordenada é válida, checando se está dentro da range permitida
### e se a posição não foi visitada.
### Parâmetros: $a0 = x, $a1 = y
###
coord_check:
#salva o endereço de retorno da função
subu $sp, $sp, 4
sw $ra, 0($sp)
#carrega o tamanho da linha do labirinto
lw $t0, size
#checa se o x,y tá dentro do range permitido
bltz $a0, coord_invalid #x < 0
bltz $a1, coord_invalid #y < 0
bge $a0, $t0, coord_invalid #x >= size
bge $a1, $t0, coord_invalid #y >= size
#posição no array = x*n+y
multu $a0, $t0
mflo $t0
addu $t0, $t0, $a1
#checa se a posicao ja foi visitada
lb $t1, visited($t0)
bgtz $t1, coord_invalid
coord_valid:
move $v0, $t0 #retorna o endereço da coordenada no maze
j coord_end
coord_invalid:
li $v0 0 #define retorno como 0: inválido
coord_end:
#carrega o endereço de retorno da função e pula para ele
lw $ra, 0($sp)
addiu $sp, $sp, 4
jr $ra
###
### Exibe o labirinto contido em "maze"
###
print:
#salva o endereço de retorno da função
subu $sp, $sp, 4
sw $ra, 0($sp)
#prepara para impressão
li $t0, 0 #i = 0
lw $t2, elem #quantidade de elementos que serão impressos
lw $t3, size #tamanho da linha
print_loop:
#se chegou no último elemento, acaba a impressão
beq $t0, $t2, print_end #t2 = n*m
#carrega um elemento do labirinto
lb $t1, maze($t0)
addi $t0, $t0, 1 #i++
la $a0, ($t1) #carrega o endereço para imprimir
li $v0, 11 #print_char
syscall
#imprime newline ao fim de cada linha
div $t0, $t3 #$t3 = n
mfhi $t6 #mod = hi, div = lo
bne $t6, 0, print_loop #imprime o próximo elemento se não acabou a linha
la $a0, newline #caso tenha acabado a linha, imprime \n
li $v0, 4
syscall
#próxima iteração
j print_loop
print_end:
#imprime uma nova linha e retorna para o endereço de retorno da função
la $a0, newline
li $v0, 4
syscall
lw $ra, 0($sp)
addiu $sp, $sp, 4
jr $ra