diff options
Diffstat (limited to 'aoc-2025/day6.asm')
| -rw-r--r-- | aoc-2025/day6.asm | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/aoc-2025/day6.asm b/aoc-2025/day6.asm new file mode 100644 index 0000000..774ca4c --- /dev/null +++ b/aoc-2025/day6.asm @@ -0,0 +1,419 @@ +; Advent of Code 2025 - Day 6 + +bits 64 +default rel + +global _start + +%define SYS_EXIT 60 +%define SYS_READ 0 +%define SYS_WRITE 1 +%define SYS_OPEN 2 +%define SYS_CLOSE 3 + +%define O_RDONLY 0 +%define STDOUT 1 + +%define RAW_SIZE 1048576 +%define MAX_W 8192 +%define MAX_H 64 +%define GRID_SIZE (MAX_W * MAX_H) + +section .data + input_path db "input/day6.txt", 0 + + newline db 10 + + label1 db "Part 1: ", 0 + label2 db "Part 2: ", 0 + +section .bss + raw resb RAW_SIZE + grid resb GRID_SIZE ; height x width, space-filled + + raw_len resq 1 + width resq 1 + height resq 1 + + blk_c0 resq 1 ; current block: columns [blk_c0, blk_c1) + blk_c1 resq 1 + op resq 1 ; 0 = add, 1 = mul, -1 = none + + part1 resq 1 + part2 resq 1 + + number_buffer resb 32 + +section .text + +_start: + mov rax, SYS_OPEN + mov rdi, input_path + mov rsi, O_RDONLY + xor rdx, rdx + syscall + mov r12, rax + + xor r13, r13 +read_loop: + mov rax, SYS_READ + mov rdi, r12 + lea rsi, [raw + r13] + mov rdx, RAW_SIZE + sub rdx, r13 + syscall + cmp rax, 0 + jle read_done + add r13, rax + jmp read_loop +read_done: + mov [raw_len], r13 + + mov rax, SYS_CLOSE + mov rdi, r12 + syscall + + ; width = length of the first line + xor rcx, rcx +width_scan: + cmp rcx, [raw_len] + jge width_done + mov al, [raw + rcx] + cmp al, 10 + je width_done + cmp al, 13 + je width_done + inc rcx + jmp width_scan +width_done: + mov [width], rcx + + ; height = number of lines (newlines, plus one if the last line has no newline) + xor rcx, rcx + xor r8, r8 +height_scan: + cmp rcx, [raw_len] + jge height_tail + mov al, [raw + rcx] + cmp al, 10 + jne height_next + inc r8 +height_next: + inc rcx + jmp height_scan +height_tail: + mov rax, [raw_len] + test rax, rax + jz height_store + mov dl, [raw + rax - 1] + cmp dl, 10 + je height_store + inc r8 +height_store: + mov [height], r8 + + ; space-fill the grid, then copy the raw bytes into it + mov rax, [height] + imul rax, [width] + mov rcx, rax + lea rdi, [grid] + mov al, ' ' + rep stosb + + xor r8, r8 ; raw index + xor r9, r9 ; row + xor r10, r10 ; col +fill_loop: + cmp r8, [raw_len] + jge fill_done + mov al, [raw + r8] + inc r8 + cmp al, 10 + je fill_newline + cmp al, 13 + je fill_loop + cmp r10, [width] + jge fill_loop + mov rdx, r9 + imul rdx, [width] + add rdx, r10 + mov [grid + rdx], al + inc r10 + jmp fill_loop +fill_newline: + inc r9 + xor r10, r10 + jmp fill_loop +fill_done: + + ; walk the columns, carving out blocks between all-space separators + xor r15, r15 ; column cursor +block_scan: + cmp r15, [width] + jge blocks_done + mov rdi, r15 + call col_is_sep + test rax, rax + jnz block_sep + mov [blk_c0], r15 +block_extend: + cmp r15, [width] + jge block_end + mov rdi, r15 + call col_is_sep + test rax, rax + jnz block_end + inc r15 + jmp block_extend +block_end: + mov [blk_c1], r15 + call process_block + jmp block_scan +block_sep: + inc r15 + jmp block_scan +blocks_done: + +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 + +; col_is_sep: is every row of column RDI a space? +; Output: RAX = 1 if the column is a separator, else 0 +; Clobbers: RAX, RDX, R8 +col_is_sep: + xor r8, r8 +.loop: + cmp r8, [height] + jge .sep + mov rax, r8 + imul rax, [width] + add rax, rdi + movzx edx, byte [grid + rax] + cmp dl, ' ' + jne .not + inc r8 + jmp .loop +.sep: + mov rax, 1 + ret +.not: + xor rax, rax + ret + +; process_block: fold the block [blk_c0, blk_c1) for both parts. +; Part 1 reads each row as a number; part 2 reads each column as a number. +; The bottom row supplies the operator. Clobbers RAX, RCX, RDX, R8-R14. +process_block: + ; find the operator on the bottom row within the block + mov rax, [height] + dec rax + imul rax, [width] + mov r11, rax ; offset of the operator row + mov qword [op], -1 + mov rcx, [blk_c0] +.find_op: + cmp rcx, [blk_c1] + jge .op_done + mov rdx, r11 + add rdx, rcx + mov al, [grid + rdx] + cmp al, '+' + je .set_add + cmp al, '*' + je .set_mul + inc rcx + jmp .find_op +.set_add: + mov qword [op], 0 + jmp .op_done +.set_mul: + mov qword [op], 1 +.op_done: + cmp qword [op], 0 + jl .ret ; no operator -> not a real problem + + ; part 1: one number per row + mov r12, [op] + xor r13, r13 ; accumulator + test r12, r12 + jz .p1_acc + mov r13, 1 +.p1_acc: + xor r14, r14 ; count of numbers folded + xor r10, r10 ; row +.p1_rows: + mov rax, [height] + dec rax + cmp r10, rax + jge .p1_done + mov rax, r10 + imul rax, [width] + mov r11, rax ; row offset + xor r8, r8 ; number + xor r9, r9 ; saw a digit? + mov rcx, [blk_c0] +.p1_cols: + cmp rcx, [blk_c1] + jge .p1_fold + mov rdx, r11 + add rdx, rcx + movzx eax, byte [grid + rdx] + cmp al, '0' + jl .p1_col_next + cmp al, '9' + jg .p1_col_next + sub al, '0' + movzx rax, al + imul r8, r8, 10 + add r8, rax + mov r9, 1 +.p1_col_next: + inc rcx + jmp .p1_cols +.p1_fold: + test r9, r9 + jz .p1_row_next + test r12, r12 + jnz .p1_mul + add r13, r8 + jmp .p1_counted +.p1_mul: + imul r13, r8 +.p1_counted: + inc r14 +.p1_row_next: + inc r10 + jmp .p1_rows +.p1_done: + test r14, r14 + jz .p2 + add [part1], r13 + + ; part 2: one number per column +.p2: + mov r12, [op] + xor r13, r13 + test r12, r12 + jz .p2_acc + mov r13, 1 +.p2_acc: + xor r14, r14 + mov rcx, [blk_c0] ; column +.p2_cols: + cmp rcx, [blk_c1] + jge .p2_done + xor r8, r8 ; number + xor r9, r9 ; saw a digit? + xor r10, r10 ; row +.p2_rows: + mov rax, [height] + dec rax + cmp r10, rax + jge .p2_fold + mov rax, r10 + imul rax, [width] + add rax, rcx + movzx edx, byte [grid + rax] + cmp dl, '0' + jl .p2_row_next + cmp dl, '9' + jg .p2_row_next + sub dl, '0' + movzx rdx, dl + imul r8, r8, 10 + add r8, rdx + mov r9, 1 +.p2_row_next: + inc r10 + jmp .p2_rows +.p2_fold: + test r9, r9 + jz .p2_col_next + test r12, r12 + jnz .p2_mul + add r13, r8 + jmp .p2_counted +.p2_mul: + imul r13, r8 +.p2_counted: + inc r14 +.p2_col_next: + inc rcx + jmp .p2_cols +.p2_done: + test r14, r14 + jz .ret + add [part2], r13 +.ret: + ret + +print_newline: + mov rax, SYS_WRITE + mov rdi, STDOUT + mov rsi, newline + mov rdx, 1 + syscall + ret + +print_int64: + mov rdi, number_buffer+31 + mov byte [rdi], 0 + dec rdi + + cmp rax, 0 + jne .conv + + mov byte [rdi], '0' + jmp .done +.conv: + mov rbx, 10 +.next: + xor rdx, rdx + div rbx + add dl, '0' + mov [rdi], dl + dec rdi + test rax, rax + jnz .next + + inc rdi +.done: + mov rax, SYS_WRITE + mov rsi, rdi + mov rdi, STDOUT + mov rdx, number_buffer+31 + sub rdx, rsi + syscall + ret + +print_string: + push rcx + push rdx + mov rdx, 0 +.length: + cmp byte [rcx+rdx], 0 + je .submit + inc rdx + jmp .length +.submit: + mov rax, SYS_WRITE + mov rdi, STDOUT + mov rsi, rcx + syscall + pop rdx + pop rcx + ret |
