adventofcode2023/17/main_part1.s

364 lines
6.3 KiB
ArmAsm
Raw Normal View History

2023-12-17 19:45:57 -06:00
%include "utils.s"
global _start
[bits 32]
[section .text]
; len +2 for padding
%define LINE_LEN (141+2)
%define FILENAME "input"
;%define LINE_LEN (13+2)
;%define FILENAME "input_test"
;%define DBG_PRINT
_start:
; convert input file to useful data
mov esi, file
mov edi, cost
convert_input:
lodsb
cmp al, 10 ; \n
je .cont
cmp al, '$'
jne .num
mov al, 0xFF
stosb
jmp .cont
.num:
sub al, '0'
stosb
.cont:
cmp esi, file.over
jb convert_input
; im lazy so doing dijkstra
; thanks wikipedia
; for each vertex v in Graph.Vertices:
; dist[v] ← INFINITY
; prev[v] ← UNDEFINED
; add v to Q
mov ecx, LINE_LEN*LINE_LEN*16
mov eax, 0xffffffff
mov edi, dist
rep stosd
mov ecx, LINE_LEN*LINE_LEN*16
mov eax, 0xffffffff
mov edi, prev
rep stosd
mov ecx, LINE_LEN*LINE_LEN*16
mov eax, 1
mov edi, q
rep stosb
; for all real dir:
; dist[source@dir] ← 0
mov dword [dist+((((LINE_LEN*16)+16))|0b0000)*4], 0
mov dword [dist+((((LINE_LEN*16)+16))|0b1000)*4], 0
; while Q is not empty and any dist[u] in Q < inf:
; u ← vertex in Q with min dist[u]
while_q:
xor ebp, ebp ; test node
mov ecx, 0xffffffff ; best dist
mov edx, 0xffffffff ; best node
.find_min:
cmp byte [q+ebp], 1
jne .cont
cmp [dist+ebp*4], ecx
cmovb ecx, [dist+ebp*4]
cmovb edx, ebp
.cont:
inc ebp
cmp ebp, LINE_LEN*LINE_LEN*16
jb .find_min
cmp ecx, 0xffffffff
je while_q_done
%ifdef DBG_PRINT
pushad
call newline
mov ebp, edx
mov eax, edx
xor edx, edx
shr eax, 4
mov ebx, LINE_LEN
div ebx
call print_dec
call space
mov eax, edx
call print_dec
call space
mov eax, ebp
and eax, 0b1111
call print_dec
call space
mov eax, ecx
call print_dec
call newline
popad
%endif
; remove u from Q
mov byte [q+edx], 0
; for each neighbor v of u still in Q:
; alt ← dist[u] + Graph.Edges(u, v)
; if alt < dist[v]:
; dist[v] ← alt
; prev[v] ← u
mov ebp, LINE_LEN*16 ; whatever
for_neighbor:
; turning neighbor 0
neighbor_0:
; neighbors += v@dir(u, ~u.dir & 0b1000)
mov ebx, edx
not ebx
and ebx, 0b1000
; tmp := 16
mov edi, 16
; bt dir, 3
bt ebx, 3
; if CF tmp := LINE_LEN
cmovc edi, ebp
; bt dir, 2
; if CF tmp := -tmp
mov esi, edi
neg esi
bt ebx, 2
cmovc edi, esi
; v := u + tmp
mov esi, edx
and esi, 0xFFFFFFF0
add edi, esi
; v.dir := dir
or edi, ebx
; alt ← dist[u] + cost(v)
; if alt < dist[v]:
; dist[v] ← alt
; prev[v] ← u
mov eax, edi
shr eax, 4
movzx eax, byte [cost+eax]
cmp al, 0xff
je neighbor_1 ; off graph
add eax, ecx
%ifdef DBG_PRINT
pushad
call space
mov esi, eax
mov eax, edi
shr eax, 4
mov ecx, LINE_LEN
xor edx, edx
div ecx
call print_dec
call space
mov eax, edx
call print_dec
call space
mov eax, edi
and eax, 0xf
call print_dec
call space
mov eax, esi
call print_dec
call newline
popad
%endif
cmp eax, [dist+edi*4]
jae neighbor_1 ; not better
mov [dist+edi*4], eax
mov [prev+edi*4], edx
; turning neighbor 1
neighbor_1:
; neighbors += v@dir(u, (~u.dir & 0b1000) | 0b0100)
mov ebx, edx
not ebx
and ebx, 0b1000
or ebx, 0b0100
; tmp := 16
mov edi, 16
; bt dir, 3
bt ebx, 3
; if CF tmp := LINE_LEN
cmovc edi, ebp
; bt dir, 2
; if CF tmp := -tmp
mov esi, edi
neg esi
bt ebx, 2
cmovc edi, esi
; v := u + tmp
mov esi, edx
and esi, 0xFFFFFFF0
add edi, esi
; v.dir := dir
or edi, ebx
; alt ← dist[u] + cost(v)
; if alt < dist[v]:
; dist[v] ← alt
; prev[v] ← u
mov eax, edi
shr eax, 4
movzx eax, byte [cost+eax]
cmp al, 0xff
je neighbor_2 ; off graph
add eax, ecx
%ifdef DBG_PRINT
pushad
call space
mov esi, eax
mov eax, edi
shr eax, 4
mov ecx, LINE_LEN
xor edx, edx
div ecx
call print_dec
call space
mov eax, edx
call print_dec
call space
mov eax, edi
and eax, 0xf
call print_dec
call space
mov eax, esi
call print_dec
call newline
popad
%endif
cmp eax, [dist+edi*4]
jae neighbor_2 ; not better
mov [dist+edi*4], eax
mov [prev+edi*4], edx
; straight - neighbor 2
neighbor_2:
; if u.dir & 0b0011 < 2
; neighbors += v@dir(u, u.dir + 1)
mov ebx, edx
and ebx, 0b0011
cmp ebx, 2
jae while_q_cont ; neighbors done
mov ebx, edx
and ebx, 0b1111
inc ebx
; tmp := 16
mov edi, 16
; bt dir, 3
bt ebx, 3
; if CF tmp := LINE_LEN
cmovc edi, ebp
; bt dir, 2
; if CF tmp := -tmp
mov esi, edi
neg esi
bt ebx, 2
cmovc edi, esi
; v := u + tmp
mov esi, edx
and esi, 0xFFFFFFF0
add edi, esi
; v.dir := dir
or edi, ebx
; alt ← dist[u] + cost(v)
; if alt < dist[v]:
; dist[v] ← alt
; prev[v] ← u
mov eax, edi
shr eax, 4
movzx eax, byte [cost+eax]
cmp al, 0xff
je while_q_cont ; off graph
add eax, ecx
%ifdef DBG_PRINT
pushad
call space
mov esi, eax
mov eax, edi
shr eax, 4
mov ecx, LINE_LEN
xor edx, edx
div ecx
call print_dec
call space
mov eax, edx
call print_dec
call space
mov eax, edi
and eax, 0xf
call print_dec
call space
mov eax, esi
call print_dec
call newline
popad
%endif
cmp eax, [dist+edi*4]
jae while_q_cont ; not better
mov [dist+edi*4], eax
mov [prev+edi*4], edx
while_q_cont:
jmp while_q
while_q_done:
call newline
; last dist values
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b0000)*4]
call print_sign_dec
call space
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b0001)*4]
call print_sign_dec
call space
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b0010)*4]
call print_sign_dec
call newline
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b0100)*4]
call print_sign_dec
call space
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b0101)*4]
call print_sign_dec
call space
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b0110)*4]
call print_sign_dec
call newline
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b1000)*4]
call print_sign_dec
call space
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b1001)*4]
call print_sign_dec
call space
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b1010)*4]
call print_sign_dec
call newline
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b1100)*4]
call print_sign_dec
call space
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b1101)*4]
call print_sign_dec
call space
mov eax, [dist+((((LINE_LEN-2)*(LINE_LEN*16))+((LINE_LEN-2)*16))+0b1110)*4]
call print_sign_dec
call newline
game_over:
jmp exit
[section .data]
file: incbin FILENAME
.over:
[section .bss]
dist: resd LINE_LEN*LINE_LEN*16
prev: resd LINE_LEN*LINE_LEN*16
q: resb LINE_LEN*LINE_LEN*16
cost: resb LINE_LEN*LINE_LEN
new_file: resb len(file)