adventofcode2023/16/main.s

503 lines
12 KiB
ArmAsm
Raw Normal View History

2023-12-16 19:26:15 -06:00
%include "utils.s"
global _start
[bits 32]
[section .text]
%define LINE_LEN 111 ; real
%define FILENAME "input"
;%define LINE_LEN 11 ; test
;%define FILENAME "input_test"
;%define ITER_PRINT
_start:
; bit 3 bit 2 bit 1 bit 0
; up down left right
; start top left going right
mov dword [test_edge_line], 0
mov dword [test_edge_col], 0
mov byte [test_edge_dir], 1
mov byte [energized], 1
jmp next_iteration
next_edge_tile:
; clear energized
mov edi, energized
xor eax, eax
mov ecx, (128*128)/4
rep stosd
mov eax, [test_edge_line]
mov ecx, [test_edge_col]
mov bl, [test_edge_dir]
cmp bl, 1 ; we're testing going right
jne .maybe_2
; we're going down first col
cmp eax, LINE_LEN-2 ; check if last line
je .bl_corner
inc eax
jmp start_iterations
.bl_corner:
mov bl, 8 ; try going up
jmp start_iterations
.maybe_2:
cmp bl, 2 ; we're testing going left
jne .maybe_4
; we're going up the last col
cmp eax, 0 ; check if first line
je .tr_corner
dec eax
jmp start_iterations
.tr_corner:
mov bl, 4 ; try going down
jmp start_iterations
.maybe_4:
cmp bl, 4 ; we're testing going down
jne .maybe_8
; we're going along the top line backward
cmp ecx, 0 ; check if first col
je .tl_corner
dec ecx
jmp start_iterations
.tl_corner:
jmp game_over ; nothing to do! jump to exit
.maybe_8: ; we're testing going up
; we're going along the bottom line
cmp ecx, LINE_LEN-2 ; check if last col
je .br_corner
inc ecx
jmp start_iterations
.br_corner:
mov bl, 2 ; try going left
jmp start_iterations
start_iterations:
mov [test_edge_line], eax
mov [test_edge_col], ecx
mov [test_edge_dir], bl
mov edx, LINE_LEN
mul edx
add eax, ecx
mov byte [energized+eax], bl
next_iteration:
%ifdef ITER_PRINT
; debug printing
dbg:
xor esi, esi ; top line
.for_lines:
xor ecx, ecx ; leftmost char
.for_chars:
movzx eax, byte [esi+ecx+energized]
movzx ebx, byte [esi+ecx+file]
pushad
test al, al
jz .prnt_char
p_string ansi_color_highbold_green
cmp bl, '.'
jne .prnt_char
popcnt ecx, eax
cmp ecx, 1
jg .prnt_num
cmp al, 1
je .prnt_right
cmp al, 2
je .prnt_left
cmp al, 4
je .prnt_down
.prnt_up: mov al, '^'
call print_char
jmp .prnt_done
.prnt_down: mov al, 'v'
call print_char
jmp .prnt_done
.prnt_left: mov al, '<'
call print_char
jmp .prnt_done
.prnt_right: mov al, '>'
call print_char
jmp .prnt_done
.prnt_num:
mov eax, ecx
call print_dec
jmp .prnt_done
.prnt_char:
mov al, [esi+ecx+file]
call print_char
.prnt_done:
p_string ansi_color_reset
popad
.for_chars_cont:
inc ecx
cmp ecx, LINE_LEN-2
jbe .for_chars
.for_chars_done:
.for_lines_cont:
call newline
add esi, LINE_LEN
cmp esi, len(file)
jb .for_lines
call newline
; debug printing end
%endif
xor esi, esi ; top line
for_lines:
xor ecx, ecx ; leftmost char
for_chars:
movzx eax, byte [esi+ecx+energized]
movzx ebx, byte [esi+ecx+file]
; skip if not energized
test eax, eax
jz for_chars_cont
; select thing
cmp bl, '.'
je empty
cmp bl, '/'
je mirror_one
cmp bl, '\'
je mirror_two
cmp bl, '-'
je horz_split
cmp bl, '|'
je vert_split
p_string what_the_fuck
jmp exit
empty: ; .
; propagate
; test right
bt eax, 0
jnc .t_left
or byte [esi+ecx+energized+1], 1<<0
.t_left:
bt eax, 1
jnc .t_down
or byte [esi+ecx+energized-1], 1<<1
.t_down:
bt eax, 2
jnc .t_up
or byte [esi+ecx+energized+LINE_LEN], 1<<2
.t_up:
bt eax, 3
jnc .done
or byte [esi+ecx+energized-LINE_LEN], 1<<3
.done:
jmp for_chars_cont
mirror_one: ; /
; our energized is what hits us
; test right >/
bt eax, 0
jnc .t_left
or byte [esi+ecx+energized-LINE_LEN], 1<<3 ; up char going up
.t_left: ; /<
bt eax, 1
jnc .t_down
or byte [esi+ecx+energized+LINE_LEN], 1<<2 ; down going down
.t_down:
bt eax, 2 ; v
jnc .t_up ; /
or byte [esi+ecx+energized-1], 1<<1 ; left going left
.t_up:
bt eax, 3 ; /
jnc .done ; ^
or byte [esi+ecx+energized+1], 1<<0 ; right going right
.done:
jmp for_chars_cont
mirror_two: ; \
; our energized is what hits us
; test right >\
bt eax, 0
jnc .t_left
or byte [esi+ecx+energized+LINE_LEN], 1<<2 ; down char going down
.t_left: ; \<
bt eax, 1
jnc .t_down
or byte [esi+ecx+energized-LINE_LEN], 1<<3 ; up going up
.t_down:
bt eax, 2 ; v
jnc .t_up ; \
or byte [esi+ecx+energized+1], 1<<0 ; right going right
.t_up:
bt eax, 3 ; \
jnc .done ; ^
or byte [esi+ecx+energized-1], 1<<1 ; left going left
.done:
jmp for_chars_cont
horz_split: ; -
; our energized is what hits us
; right and left propagate
; test right
bt eax, 0
jnc .t_left
or byte [esi+ecx+energized+1], 1<<0
.t_left:
bt eax, 1
jnc .t_vert
or byte [esi+ecx+energized-1], 1<<1
; down and up go both left and right
.t_vert:
and eax, 1<<2 | 1<<3
jz .done
or byte [esi+ecx+energized+1], 1<<0 ; right going right
or byte [esi+ecx+energized-1], 1<<1 ; left going left
.done:
jmp for_chars_cont
vert_split: ; |
; our energized is what hits us
; down and up propagate
; test down
bt eax, 2
jnc .t_up
or byte [esi+ecx+energized+LINE_LEN], 1<<2
.t_up:
bt eax, 3
jnc .t_vert
or byte [esi+ecx+energized-LINE_LEN], 1<<3
; left and right go both down and up
.t_vert:
and eax, 1<<0 | 1<<1
jz .done
or byte [esi+ecx+energized+LINE_LEN], 1<<2 ; down going down
or byte [esi+ecx+energized-LINE_LEN], 1<<3 ; up going up
.done:
for_chars_cont:
inc ecx
cmp ecx, LINE_LEN-2
jbe for_chars
for_chars_done:
for_lines_cont:
add esi, LINE_LEN
cmp esi, len(file)
jb for_lines
xor ebp, ebp ; energized count
sub esi, LINE_LEN ; last line
; now go through backward
bkwd_for_lines:
mov ecx, LINE_LEN-2 ; rightmost char
bkwd_for_chars:
movzx eax, byte [esi+ecx+energized]
movzx ebx, byte [esi+ecx+file]
; skip if not energized
test eax, eax
jz bkwd_for_chars_cont
inc ebp ; energized count
; select thing
cmp bl, '.'
je bkwd_empty
cmp bl, '/'
je bkwd_mirror_one
cmp bl, '\'
je bkwd_mirror_two
cmp bl, '-'
je bkwd_horz_split
cmp bl, '|'
je bkwd_vert_split
p_string what_the_fuck
jmp exit
bkwd_empty: ; .
; propagate
; test right
bt eax, 0
jnc .t_left
or byte [esi+ecx+energized+1], 1<<0
.t_left:
bt eax, 1
jnc .t_down
or byte [esi+ecx+energized-1], 1<<1
.t_down:
bt eax, 2
jnc .t_up
or byte [esi+ecx+energized+LINE_LEN], 1<<2
.t_up:
bt eax, 3
jnc .done
or byte [esi+ecx+energized-LINE_LEN], 1<<3
.done:
jmp bkwd_for_chars_cont
bkwd_mirror_one: ; /
; our energized is what hits us
; test right >/
bt eax, 0
jnc .t_left
or byte [esi+ecx+energized-LINE_LEN], 1<<3 ; up char going up
.t_left: ; /<
bt eax, 1
jnc .t_down
or byte [esi+ecx+energized+LINE_LEN], 1<<2 ; down going down
.t_down:
bt eax, 2 ; v
jnc .t_up ; /
or byte [esi+ecx+energized-1], 1<<1 ; left going left
.t_up:
bt eax, 3 ; /
jnc .done ; ^
or byte [esi+ecx+energized+1], 1<<0 ; right going right
.done:
jmp bkwd_for_chars_cont
bkwd_mirror_two: ; \
; our energized is what hits us
; test right >\
bt eax, 0
jnc .t_left
or byte [esi+ecx+energized+LINE_LEN], 1<<2 ; down char going down
.t_left: ; \<
bt eax, 1
jnc .t_down
or byte [esi+ecx+energized-LINE_LEN], 1<<3 ; up going up
.t_down:
bt eax, 2 ; v
jnc .t_up ; \
or byte [esi+ecx+energized+1], 1<<0 ; right going right
.t_up:
bt eax, 3 ; \
jnc .done ; ^
or byte [esi+ecx+energized-1], 1<<1 ; left going left
.done:
jmp bkwd_for_chars_cont
bkwd_horz_split: ; -
; our energized is what hits us
; right and left propagate
; test right
bt eax, 0
jnc .t_left
or byte [esi+ecx+energized+1], 1<<0
.t_left:
bt eax, 1
jnc .t_vert
or byte [esi+ecx+energized-1], 1<<1
; down and up go both left and right
.t_vert:
and eax, 1<<2 | 1<<3
jz .done
or byte [esi+ecx+energized+1], 1<<0 ; right going right
or byte [esi+ecx+energized-1], 1<<1 ; left going left
.done:
jmp bkwd_for_chars_cont
bkwd_vert_split: ; |
; our energized is what hits us
; down and up propagate
; test down
bt eax, 2
jnc .t_up
or byte [esi+ecx+energized+LINE_LEN], 1<<2
.t_up:
bt eax, 3
jnc .t_vert
or byte [esi+ecx+energized-LINE_LEN], 1<<3
; left and right go both down and up
.t_vert:
and eax, 1<<0 | 1<<1
jz .done
or byte [esi+ecx+energized+LINE_LEN], 1<<2 ; down going down
or byte [esi+ecx+energized-LINE_LEN], 1<<3 ; up going up
.done:
bkwd_for_chars_cont:
dec ecx
jnz bkwd_for_chars
bkwd_for_chars_done:
bkwd_for_lines_cont:
sub esi, LINE_LEN
jns bkwd_for_lines
cmp ebp, [last_energized]
mov [last_energized], ebp
jne next_iteration
; print final
xor ebp, ebp
print_final:
xor esi, esi ; top line
.for_lines:
xor ecx, ecx ; leftmost char
.for_chars:
movzx eax, byte [esi+ecx+energized]
movzx ebx, byte [esi+ecx+file]
test al, al
jz .prnt_char
inc ebp
p_string ansi_color_highbold_green
cmp bl, '.'
jne .prnt_char
popcnt edx, eax
cmp edx, 1
jg .prnt_num
cmp al, 1
je .prnt_right
cmp al, 2
je .prnt_left
cmp al, 4
je .prnt_down
.prnt_up: mov al, '^'
call print_char
jmp .prnt_done
.prnt_down: mov al, 'v'
call print_char
jmp .prnt_done
.prnt_left: mov al, '<'
call print_char
jmp .prnt_done
.prnt_right: mov al, '>'
call print_char
jmp .prnt_done
.prnt_num:
mov eax, edx
call print_dec
jmp .prnt_done
.prnt_char:
mov al, [esi+ecx+file]
call print_char
.prnt_done:
p_string ansi_color_reset
.for_chars_cont:
inc ecx
cmp ecx, LINE_LEN-2
jbe .for_chars
.for_chars_done:
.for_lines_cont:
call newline
add esi, LINE_LEN
cmp esi, len(file)
jb .for_lines
mov eax, ebp
call print_dec
call newline
call newline
cmp [final_value], ebp
cmova ebp, [final_value]
mov [final_value], ebp
jmp next_edge_tile
game_over:
mov eax, [final_value]
call print_dec
call newline
jmp exit
[section .data]
final_value: dd 0
last_energized: dd 0
test_edge_line: dd 0
test_edge_col: dd 0
test_edge_dir: dd 0
file: incbin FILENAME
.over:
[section .bss]
padding: resb 128
energized: resb 128*128
[section .rodata]
what_the_fuck: db "Something is terribly wrong in this world."
.over:
ansi_color_reset: db `\e[0m`
.over:
ansi_color_green: db `\e[0;32m`
.over:
ansi_color_highbold_green: db `\e[1;92m`
.over: