hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/2025/day4.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/day4.asm
parent78c4d3d06d8e863cfe2489281ccfe206544cbd7f (diff)
refactor: clean up repository layout
Diffstat (limited to '2025/day4.asm')
-rw-r--r--2025/day4.asm236
1 files changed, 236 insertions, 0 deletions
diff --git a/2025/day4.asm b/2025/day4.asm
new file mode 100644
index 0000000..60e53ec
--- /dev/null
+++ b/2025/day4.asm
@@ -0,0 +1,236 @@
+; Advent of Code 2025 - Day 4
+
+bits 64
+default rel
+
+global _start
+
+%include "utils/io.asm"
+
+%define RAW_SIZE 4194304 ; 4 MiB scratch for the raw file
+%define GRID_SIZE 4194304 ; 4 MiB for the padded grid / mark buffers
+
+section .data
+ input_path db "input/day4.txt", 0
+
+ label1 db "Part 1: ", 0
+ label2 db "Part 2: ", 0
+
+section .bss
+ raw resb RAW_SIZE ; raw file bytes
+ grid resb GRID_SIZE ; padded grid: 1 = roll, 0 = empty
+ mark resb GRID_SIZE ; per-round removal marks
+
+ raw_len resq 1
+ width resq 1 ; real columns per row
+ height resq 1 ; real rows
+ stride resq 1 ; width + 2 (padding on both sides)
+
+ part1 resq 1
+ part2 resq 1
+
+section .text
+
+_start:
+ mov rdi, input_path
+ lea rsi, [raw]
+ mov rdx, RAW_SIZE
+ call read_file
+ mov [raw_len], rax
+
+ xor rcx, rcx ; column scanner
+width_scan:
+ cmp rcx, [raw_len]
+ jge width_done
+ mov al, [raw + rcx]
+ cmp al, 13 ; CR
+ je width_done
+ cmp al, 10 ; LF
+ je width_done
+ inc rcx
+ jmp width_scan
+width_done:
+ mov [width], rcx
+ add rcx, 2 ; padding on left + right
+ mov [stride], rcx
+
+ ; real cell (r, c) lives at grid[(r+1)*stride + (c+1)]
+ mov r10, [raw_len]
+ xor r8, r8 ; i (raw index)
+ xor r9, r9 ; r (row, 0-based)
+ xor r11, r11 ; c (col, 0-based)
+fill_loop:
+ cmp r8, r10
+ jge fill_end
+ mov al, [raw + r8]
+ inc r8
+
+ cmp al, 13 ; CR -> ignore
+ je fill_loop
+ cmp al, 10 ; LF -> end of line
+ je fill_newline
+
+ cmp al, '@'
+ jne fill_next_col ; '.' leaves the zeroed cell alone
+
+ ; grid[(r9+1)*stride + (r11+1)] = 1
+ mov rbx, r9
+ inc rbx
+ imul rbx, [stride]
+ add rbx, r11
+ add rbx, 1
+ mov byte [grid + rbx], 1
+fill_next_col:
+ inc r11
+ jmp fill_loop
+fill_newline:
+ cmp r11, 0 ; blank line -> skip (e.g. trailing newline)
+ je fill_loop
+ inc r9
+ xor r11, r11
+ jmp fill_loop
+fill_end:
+ cmp r11, 0 ; last line had no trailing newline
+ je fill_height
+ inc r9
+fill_height:
+ mov [height], r9
+
+ mov r13, 1 ; row = 1..height
+p1_row:
+ cmp r13, [height]
+ jg p1_done
+ mov rbx, r13
+ imul rbx, [stride]
+ inc rbx ; idx of (row, col=1)
+ mov r12, 1 ; col = 1..width
+p1_col:
+ cmp r12, [width]
+ jg p1_row_next
+ movzx eax, byte [grid + rbx]
+ test eax, eax
+ jz p1_next ; not a roll
+ mov rdi, rbx
+ call count_neighbors
+ cmp rax, 4
+ jge p1_next ; 4 or more neighbors -> blocked
+ inc qword [part1]
+p1_next:
+ inc rbx
+ inc r12
+ jmp p1_col
+p1_row_next:
+ inc r13
+ jmp p1_row
+p1_done:
+
+peel_loop:
+ mov r13, 1
+mark_row:
+ cmp r13, [height]
+ jg mark_done
+ mov rbx, r13
+ imul rbx, [stride]
+ inc rbx
+ mov r12, 1
+mark_col:
+ cmp r12, [width]
+ jg mark_row_next
+ movzx eax, byte [grid + rbx]
+ test eax, eax
+ jz mark_zero ; empty cell
+ mov rdi, rbx
+ call count_neighbors
+ cmp rax, 4
+ jl mark_one ; accessible
+mark_zero:
+ mov byte [mark + rbx], 0
+ jmp mark_next
+mark_one:
+ mov byte [mark + rbx], 1
+mark_next:
+ inc rbx
+ inc r12
+ jmp mark_col
+mark_row_next:
+ inc r13
+ jmp mark_row
+mark_done:
+
+ xor r11, r11 ; removed this round
+ mov r13, 1
+apply_row:
+ cmp r13, [height]
+ jg apply_done
+ mov rbx, r13
+ imul rbx, [stride]
+ inc rbx
+ mov r12, 1
+apply_col:
+ cmp r12, [width]
+ jg apply_row_next
+ movzx eax, byte [mark + rbx]
+ test eax, eax
+ jz apply_next
+ mov byte [grid + rbx], 0
+ inc r11
+apply_next:
+ inc rbx
+ inc r12
+ jmp apply_col
+apply_row_next:
+ inc r13
+ jmp apply_row
+apply_done:
+ add [part2], r11
+ test r11, r11
+ jnz peel_loop ; something changed -> another round
+
+print_results:
+ mov rcx, label1
+ call print_string
+ mov rax, [part1]
+ call print_int64
+ call print_newline
+
+ mov rcx, label2
+ call print_string
+ mov rax, [part2]
+ call print_int64
+ call print_newline
+
+ mov rax, SYS_EXIT
+ xor rdi, rdi
+ syscall
+
+; count_neighbors: sum of the 8 cells around a padded index
+; Input: RDI = grid index
+; Output: RAX = number of neighboring rolls (0..8)
+; Clobbers: RAX, RCX, RDX, R8
+count_neighbors:
+ mov rcx, [stride]
+ xor eax, eax
+
+ mov rdx, rdi
+ sub rdx, rcx ; row above
+ movzx r8d, byte [grid + rdx - 1]
+ add eax, r8d
+ movzx r8d, byte [grid + rdx]
+ add eax, r8d
+ movzx r8d, byte [grid + rdx + 1]
+ add eax, r8d
+
+ movzx r8d, byte [grid + rdi - 1] ; same row, sides
+ add eax, r8d
+ movzx r8d, byte [grid + rdi + 1]
+ add eax, r8d
+
+ mov rdx, rdi
+ add rdx, rcx ; row below
+ movzx r8d, byte [grid + rdx - 1]
+ add eax, r8d
+ movzx r8d, byte [grid + rdx]
+ add eax, r8d
+ movzx r8d, byte [grid + rdx + 1]
+ add eax, r8d
+ ret