hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/2025/day1.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/day1.asm
parent78c4d3d06d8e863cfe2489281ccfe206544cbd7f (diff)
refactor: clean up repository layout
Diffstat (limited to '2025/day1.asm')
-rw-r--r--2025/day1.asm228
1 files changed, 228 insertions, 0 deletions
diff --git a/2025/day1.asm b/2025/day1.asm
new file mode 100644
index 0000000..928e7a5
--- /dev/null
+++ b/2025/day1.asm
@@ -0,0 +1,228 @@
+; Advent of Code 2025 - Day 1
+
+bits 64
+default rel
+
+global _start
+
+%include "utils/io.asm"
+
+section .data
+ input_path db "input/day1.txt", 0
+
+ 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
+ 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_int64
+ call print_newline
+
+ mov rcx, label2
+ call print_string
+ mov eax, [password2]
+ call print_int64
+ call print_newline
+
+ 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