diff options
| author | hachem <im@hachem.wtf> | 2026-09-06 04:12:25 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-09-06 04:12:25 +0200 |
| commit | 054d372a716bca4f628674e524e3d027f6824019 (patch) | |
| tree | f1b8a86430476b4aed8173857bdab0f960e5fdb1 /2025/day2.asm | |
| parent | 78c4d3d06d8e863cfe2489281ccfe206544cbd7f (diff) | |
refactor: clean up repository layout
Diffstat (limited to '2025/day2.asm')
| -rw-r--r-- | 2025/day2.asm | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/2025/day2.asm b/2025/day2.asm new file mode 100644 index 0000000..987fbf9 --- /dev/null +++ b/2025/day2.asm @@ -0,0 +1,324 @@ +; Advent of Code 2025 – Day 2 + +bits 64 +default rel + +global _start + +%include "utils/io.asm" +%include "utils/parse.asm" + +section .data + input_path db "input/day2.txt", 0 + + label1 db "Part 1: ", 0 + label2 db "Part 2: ", 0 + +section .bss + buffer resb 4096 + line_buffer resb 65536 + line_len resd 1 + + sum1 resq 1 + sum2 resq 1 + +section .text + +_start: + mov rax, SYS_OPEN + mov rdi, input_path + mov rsi, O_RDONLY + xor rdx, rdx + syscall + + mov r12, rax ; file descriptor + mov dword [line_len], 0 + +read_loop: + mov rax, SYS_READ + mov rdi, r12 + mov rsi, buffer + mov rdx, 4096 + syscall + + cmp rax, 0 + jle eof + + mov rdi, buffer + mov rbp, rax + +scan_chunk: + cmp rbp, 0 + je read_loop + + mov al, [rdi] + + cmp al, 13 + je skip_cr + + cmp al, 10 + je end_line + + mov edx, [line_len] + cmp edx, 65535 + jae skip_store + 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_line: + mov edx, [line_len] + mov byte [line_buffer+rdx], 0 + + cmp edx, 0 + je clear_line + + push rdi + mov rsi, line_buffer + call handle_line + pop rdi + +clear_line: + mov dword [line_len], 0 + inc rdi + dec rbp + jmp scan_chunk + +eof: + ; process final partial line if needed + 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 rax, [sum1] + call print_int64 + call print_newline + + mov rcx, label2 + call print_string + mov rax, [sum2] + call print_int64 + call print_newline + + mov rax, SYS_CLOSE + mov rdi, r12 + syscall + + mov rax, SYS_EXIT + xor rdi, rdi + syscall + +; parse "A-B,C-D,..."l, RSI = pointer to line +; uses r13 = current ID, r14 = end of range +handle_line: +next_range: + ; parse start + call parse_u64 + mov r13, rax + + cmp byte [rsi], '-' + jne done_line + inc rsi + + ; parse end + call parse_u64 + mov r14, rax + +range_loop: + cmp r13, r14 + jg after_range + + ; Save RSI (line pointer) across the checks, + ; because number_to_string / check_invalid* use RSI + push rsi + + ; Part 1: exact AA + mov rax, r13 + call check_invalid1 + test rax, rax + jz .skip_p1 + add qword [sum1], r13 +.skip_p1: + ; Part 2: any repeating block >= 2 + mov rax, r13 + call check_invalid2 + test rax, rax + jz .skip_p2 + add qword [sum2], r13 +.skip_p2: + pop rsi ; restore line pointer + + inc r13 + jmp range_loop + +after_range: + cmp byte [rsi], ',' + jne done_line + inc rsi + jmp next_range + +done_line: + ret + +; number_to_string: convert RAX to decimal ASCII, MSB-first +; Output: +; RSI = pointer to first digit +; ECX = length +number_to_string: + mov rdi, number_buffer+31 + mov byte [rdi], 0 ; terminator (for convenience) + dec rdi + + cmp rax, 0 + jne .conv + + ; handle zero + mov byte [rdi], '0' + mov rsi, rdi + mov ecx, 1 + ret + +.conv: + mov rbx, 10 +.next_digit: + xor rdx, rdx + div rbx ; RAX = quotient, RDX = remainder + add dl, '0' + mov [rdi], dl + dec rdi + test rax, rax + jnz .next_digit + + inc rdi ; now RDI points to first digit + mov rsi, rdi + mov rdx, number_buffer+31 + sub rdx, rsi ; RDX = length + mov ecx, edx + ret + +; check_invalid1: "AA" pattern +; RAX = number +; Returns RAX = 1 if digits == A A, else 0 +check_invalid1: + push rbx + push rdx + + call number_to_string ; RSI=string, ECX=len + mov eax, ecx ; EAX = len + + cmp eax, 2 + jl .no1 + + test eax, 1 + jnz .no1 ; odd length => cannot be AA + + shr eax, 1 ; half = len/2 + mov r8d, eax ; half + xor r9d, r9d ; i = 0 + +.loop1: + cmp r9d, r8d + jge .yes1 + + ; s[i] + mov rdx, r9 + movzx eax, byte [rsi + rdx] + + ; s[i+half] + mov rdx, r9 + add rdx, r8 + movzx ebx, byte [rsi + rdx] + + cmp eax, ebx + jne .no1 + + inc r9d + jmp .loop1 + +.yes1: + mov rax, 1 + jmp .ret1 + +.no1: + xor rax, rax + +.ret1: + pop rdx + pop rbx + ret + +; check_invalid2: any repeating block >= 2 +; RAX = number +; Returns RAX = 1 if string is some A repeated k>=2 times +check_invalid2: + push rbx + push rdx + + call number_to_string ; RSI=string, ECX=len + mov r11d, ecx ; n = length + + cmp r11d, 2 + jb .no2 + + mov r8d, 1 ; m = 1 (candidate period) +.outer: + cmp r8d, r11d + jge .no2 + + ; if n % m != 0 => cannot tile + mov eax, r11d + xor edx, edx + div r8d ; EAX=q, EDX=r + test edx, edx + jnz .next_m + + mov r9d, r11d + sub r9d, r8d ; limit = n - m + xor r10d, r10d ; i = 0 +.inner: + cmp r10d, r9d + jge .yes2 ; all positions checked + + ; s[i] + mov rdx, r10 + movzx eax, byte [rsi + rdx] + + ; s[i+m] + mov rdx, r10 + add rdx, r8 + movzx ebx, byte [rsi + rdx] + + cmp eax, ebx + jne .next_m + + inc r10d + jmp .inner +.yes2: + mov rax, 1 + jmp .ret2 +.next_m: + inc r8d + jmp .outer +.no2: + xor rax, rax +.ret2: + pop rdx + pop rbx + ret |
