; Advent of Code 2025 - Day 6 bits 64 default rel global _start %include "utils/io.asm" %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 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 section .text _start: mov rdi, input_path lea rsi, [raw] mov rdx, RAW_SIZE call read_file mov [raw_len], rax ; 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