hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/2025/day3.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/day3.asm
parent78c4d3d06d8e863cfe2489281ccfe206544cbd7f (diff)
refactor: clean up repository layout
Diffstat (limited to '2025/day3.asm')
-rw-r--r--2025/day3.asm234
1 files changed, 234 insertions, 0 deletions
diff --git a/2025/day3.asm b/2025/day3.asm
new file mode 100644
index 0000000..8330755
--- /dev/null
+++ b/2025/day3.asm
@@ -0,0 +1,234 @@
+; Advent of Code 2025 - Day 3
+
+bits 64
+default rel
+
+global _start
+
+%include "utils/io.asm"
+
+section .data
+ input_path db "input/day3.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
+
+ work_digits resb 64 ; stack for greedy subsequence
+
+section .text
+
+_start:
+ mov rax, SYS_OPEN
+ mov rdi, input_path
+ mov rsi, O_RDONLY
+ xor rdx, rdx
+ syscall
+
+ mov r12, rax ; fd
+ 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+edx], 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:
+ ; possible last partial line
+ mov edx, [line_len]
+ cmp edx, 0
+ jle print_results
+
+ mov byte [line_buffer+edx], 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
+
+handle_line:
+ mov rdi, rsi
+ xor ecx, ecx ; ECX = 0
+.length_loop:
+ mov al, [rdi+rcx]
+ cmp al, 0
+ je .length_done
+ inc ecx
+ jmp .length_loop
+.length_done:
+ mov r15d, ecx ; r15d = n
+
+ ; part 1: k = 2
+ mov ecx, r15d ; ECX = n
+ mov edi, 2 ; K = 2
+ call get_max_for_k ; RAX = best 2-digit value
+ add qword [sum1], rax
+
+ ; part 2: k = 12, only if n >= 12
+ cmp r15d, 12
+ jl .skip_part2
+
+ mov ecx, r15d
+ mov edi, 12
+ call get_max_for_k ; RAX = best 12-digit value
+ add qword [sum2], rax
+
+.skip_part2:
+ ret
+
+; Greedy lexicographically largest subsequence of length K
+;
+; Input:
+; RSI -> digits string
+; ECX = n (length)
+; EDI = k
+; Output:
+; RAX = numeric value of chosen k digits
+; Clobbers: R8..R11, EAX, EDX
+get_max_for_k:
+ ; drops_remaining = n - k
+ mov eax, ecx
+ sub eax, edi
+ mov r8d, eax ; r8d = drops
+
+ xor r9d, r9d ; r9d = stack_size
+ xor r10d, r10d ; r10d = i
+
+.loop:
+ cmp r10d, ecx
+ jge .after_input
+
+ ; current digit in AL
+ mov r11, r10
+ mov al, [rsi + r11]
+
+.pop:
+ cmp r9d, 0
+ jle .push
+ cmp r8d, 0
+ jle .push
+
+ mov edx, r9d
+ dec edx
+ mov r11d, edx
+ mov bl, [work_digits + r11]
+
+ cmp bl, al
+ jge .push
+
+ dec r9d
+ dec r8d
+ jmp .pop
+.push:
+ mov r11d, r9d
+ mov [work_digits + r11], al
+ inc r9d
+ inc r10d
+ jmp .loop
+
+.after_input:
+ ; trim if stack_size > k
+.trim:
+ cmp r9d, edi
+ jle .convert
+ dec r9d
+ jmp .trim
+.convert:
+ xor rax, rax
+ xor r11d, r11d
+.convert_loop:
+ cmp r11d, edi
+ jge .done
+
+ mov rdx, r11
+ mov dl, [work_digits + rdx]
+ sub dl, '0'
+ movzx rdx, dl
+
+ imul rax, rax, 10
+ add rax, rdx
+
+ inc r11d
+ jmp .convert_loop
+.done:
+ ret