hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/2025/day2.asm
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-06 04:12:25 +0200
committerhachem <im@hachem.wtf>2026-09-06 04:12:25 +0200
commit054d372a716bca4f628674e524e3d027f6824019 (patch)
treef1b8a86430476b4aed8173857bdab0f960e5fdb1 /2025/day2.asm
parent78c4d3d06d8e863cfe2489281ccfe206544cbd7f (diff)
refactor: clean up repository layout
Diffstat (limited to '2025/day2.asm')
-rw-r--r--2025/day2.asm324
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