%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 ;%define FINAL_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 %ifdef FINAL_PRINT 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 %endif .prnt_char: %ifdef FINAL_PRINT mov al, [esi+ecx+file] call print_char .prnt_done: p_string ansi_color_reset %endif .for_chars_cont: inc ecx cmp ecx, LINE_LEN-2 jbe .for_chars .for_chars_done: .for_lines_cont: %ifdef FINAL_PRINT call newline %endif add esi, LINE_LEN cmp esi, len(file) jb .for_lines %ifdef FINAL_PRINT mov eax, ebp call print_dec call newline call newline %endif 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: