hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/2025/day6.asm
blob: 728b8b0858462c6e4d5d1a00ced48dad453f5264 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
; 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