; Advent of Code 2025 - Day 1 bits 64 default rel global _start %define SYS_EXIT 60 %define SYS_READ 0 %define SYS_WRITE 1 %define SYS_OPEN 2 %define SYS_CLOSE 3 %define O_RDONLY 0 %define STDOUT 1 section .data input_path db "input/day1.txt", 0 newline db 10 label1 db "Password 1: ", 0 label2 db "Password 2: ", 0 angle1 dd 50 angle2 dd 50 password1 dd 0 password2 dd 0 section .bss buffer resb 4096 line_buffer resb 256 number_buffer resb 16 line_len resd 1 section .text _start: ; open file mov rax, SYS_OPEN mov rdi, input_path mov rsi, O_RDONLY xor rdx, rdx syscall mov r12, rax ; fd in R12 mov dword [line_len], 0 ; no chars in current line yet read_loop: ; read up to 4096 bytes mov rax, SYS_READ mov rdi, r12 mov rsi, buffer mov rdx, 4096 syscall cmp rax, 0 jle eof ; <=0 -> EOF or error mov rdi, buffer ; scan pointer mov rbp, rax ; bytes remaining in this chunk scan_chunk: cmp rbp, 0 je read_loop ; chunk done, read next mov al, [rdi] ; windows can be a fucking bitch ; handle (CR) -> just skip cmp al, 13 je skip_cr ; handle LF (10) -> end of line cmp al, 10 je end_of_line ; normal character -> append to line_buffer if space left mov edx, [line_len] cmp edx, 255 ; leave 1 byte for NULL jae skip_store ; ignore extra characters if too long mov [line_buffer+rdx], al inc edx mov [line_len], edx skip_store: inc rdi dec rbp jmp scan_chunk skip_cr: inc rdi dec rbp jmp scan_chunk end_of_line: ; terminate current line mov edx, [line_len] mov byte [line_buffer+rdx], 0 ; if line isn't empty, process it cmp edx, 0 je line_done push rdi mov rsi, line_buffer call handle_line pop rdi line_done: mov dword [line_len], 0 ; reset line length inc rdi dec rbp jmp scan_chunk ; process last line if not newline-terminated, then print result eof: ; if there is a partial line at EOF, process it mov edx, [line_len] cmp edx, 0 jle print_results mov byte [line_buffer+rdx], 0 mov rsi, line_buffer call handle_line print_results: mov rcx, label1 call print_string mov eax, [password1] call print_int ; newline mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, newline mov rdx, 1 syscall mov rcx, label2 call print_string mov eax, [password2] call print_int ; new linhe mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, newline mov rdx, 1 syscall mov rax, SYS_CLOSE mov rdi, r12 syscall mov rax, SYS_EXIT xor rdi, rdi syscall ; Handle one line: RSI -> "L123" or "R45" handle_line: mov al, [rsi] cmp al, 'L' je .left mov ebx, 1 ; direction = +1 for 'R' or anything else jmp .after .left: mov ebx, -1 ; direction = -1 for 'L' .after: inc rsi ; skip 'L' or 'R' call parse_int ; EAX = steps mov ecx, eax ; Part 1 p1_start: mov eax, ecx imul eax, ebx add eax, [angle1] call normalize_angle mov [angle1], eax cmp eax, 0 jne p2_start mov rdi, password1 mov edx, [rdi] inc edx mov [rdi], edx ; Part 2 p2_start: mov rdi, password2 .loop: test ecx, ecx jle p2_exit dec ecx mov eax, [angle2] call update_angle_count mov [angle2], eax jmp .loop p2_exit: ret ; normalize eax to 0..99 normalize_angle: cmp eax, 0 jl .add cmp eax, 100 jl .done sub eax, 100 jmp normalize_angle .add: add eax, 100 jmp normalize_angle .done: ret ; eax = angle, ebx = direction, rdi = password counter addr update_angle_count: add eax, ebx call normalize_angle cmp eax, 0 jne .done mov edx, [rdi] inc edx mov [rdi], edx .done: ret ; parse ASCII integer into EAX parse_int: xor eax, eax ; result = 0 .parse_loop: mov dl, [rsi] cmp dl, '0' jl .done cmp dl, '9' jg .done sub dl, '0' ; digit value 0..9 movzx edx, dl imul eax, eax, 10 ; result *= 10 add eax, edx ; result += digit inc rsi jmp .parse_loop .done: ret print_int: mov edi, number_buffer+15 ; write digits from the end mov byte [rdi], 0 ; terminator dec rdi cmp eax, 0 jne .convert mov byte [rdi], '0' jmp .finish .convert: ; we will repeatedly compute: ; q = eax / 10 ; r = eax % 10 ; using only subtraction .next_digit: mov edx, eax ; tmp = current value mov ecx, 0 ; q = 0 cmp edx, 10 ; if < 0, q=0, r=edx jb .last_digit .sub_loop: sub edx, 10 inc ecx ; q++ cmp edx, 10 jae .sub_loop ; while tmp >= 10 .last_digit: ; now: ; ecx = quotient ; edx = remainder (0..9) add dl, '0' mov [rdi], dl ; store digit dec rdi mov eax, ecx ; eax = quotient test eax, eax jnz .next_digit ; more digits to extract? inc rdi ; move to first digit .finish: mov rax, SYS_WRITE mov rsi, rdi ; buffer pointer mov rdi, STDOUT mov rdx, number_buffer+15 sub rdx, rsi ; length syscall ret print_string: push rcx push rdx mov rdx, 0 .count: cmp byte [rcx+rdx], 0 je .done_count inc rdx jmp .count .done_count: mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, rcx syscall pop rdx pop rcx ret