hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/2025/day7.asm
blob: 1d990a7cb9c6f6fedb73fc8772951f7b4d3113d7 (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
; Advent of Code 2025 - Day 7

bits 64
default rel

global _start

%include "utils/io.asm"

%define RAW_SIZE   1048576
%define MAX_W      1024
%define MAX_H      1024
%define GRID_SIZE  (MAX_W * MAX_H)

section .data
    input_path db "input/day7.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, '.'-filled
    g             resq (MAX_W * MAX_H)     ; part 2 timeline counts
    cur           resb MAX_W               ; part 1 active columns (this row)
    nxt           resb MAX_W               ; part 1 active columns (next row)

    raw_len       resq 1
    width         resq 1
    height        resq 1
    srow          resq 1
    scol          resq 1

    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
    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

    ; '.'-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:

    ; locate S
    xor     r8, r8
    mov     rax, [height]
    imul    rax, [width]
    mov     r9, rax
find_s:
    cmp     r8, r9
    jge     s_done
    mov     al, [grid + r8]
    cmp     al, 'S'
    je      s_found
    inc     r8
    jmp     find_s
s_found:
    mov     rax, r8
    xor     rdx, rdx
    div     qword [width]
    mov     [srow], rax
    mov     [scol], rdx
s_done:

    ; part 1: flood a set of active columns, counting splitter hits
    lea     rdi, [cur]
    mov     rcx, MAX_W
    xor     al, al
    rep     stosb
    mov     rax, [scol]
    mov     byte [cur + rax], 1

    xor     r15, r15   ; row
p1_row:
    cmp     r15, [height]
    jge     p1_done
    lea     rdi, [nxt]
    mov     rcx, MAX_W
    xor     al, al
    rep     stosb

    mov     rax, r15
    imul    rax, [width]
    mov     r14, rax   ; row offset
    xor     r13, r13   ; col
    xor     r12, r12   ; any beam alive?
p1_col:
    cmp     r13, [width]
    jge     p1_col_done
    mov     al, [cur + r13]
    test    al, al
    jz      p1_next
    mov     rdx, r14
    add     rdx, r13
    mov     al, [grid + rdx]
    cmp     al, '^'
    jne     p1_pass
    inc     qword [part1]
    mov     rbx, r13   ; left neighbor
    test    rbx, rbx
    jz      p1_no_left
    dec     rbx
    mov     byte [nxt + rbx], 1
    mov     r12, 1
p1_no_left:
    mov     rbx, r13   ; right neighbor
    inc     rbx
    cmp     rbx, [width]
    jge     p1_no_right
    mov     byte [nxt + rbx], 1
    mov     r12, 1
p1_no_right:
    jmp     p1_next
p1_pass:
    mov     byte [nxt + r13], 1
    mov     r12, 1
p1_next:
    inc     r13
    jmp     p1_col
p1_col_done:
    lea     rsi, [nxt]
    lea     rdi, [cur]
    mov     rcx, MAX_W
    rep     movsb
    test    r12, r12
    jz      p1_done
    inc     r15
    jmp     p1_row
p1_done:

    ; part 2: bottom-up DP of timeline counts, g[r][c]
    mov     r15, [height]
    dec     r15        ; row, counting down
p2_row:
    cmp     r15, 0
    jl      p2_done
    mov     rax, r15
    imul    rax, [width]
    mov     r14, rax   ; row offset
    xor     r13, r13   ; col
p2_col:
    cmp     r13, [width]
    jge     p2_col_done
    mov     rdx, r14
    add     rdx, r13   ; idx = r*W + c
    mov     al, [grid + rdx]
    cmp     al, '^'
    je      p2_split

    ; pass straight down: g = (r+1 in grid ? g[r+1][c] : 1)
    mov     rbx, r15
    inc     rbx
    cmp     rbx, [height]
    jge     p2_pass_exit
    mov     rcx, rdx
    add     rcx, [width]
    mov     rax, [g + rcx*8]
    jmp     p2_store
p2_pass_exit:
    mov     rax, 1
    jmp     p2_store

p2_split:
    ; left child enters (r+1, c-1)
    mov     rbx, r15
    inc     rbx
    cmp     rbx, [height]
    jge     p2_left_one
    cmp     r13, 0
    jle     p2_left_one
    mov     rcx, rdx
    add     rcx, [width]
    dec     rcx
    mov     r8, [g + rcx*8]
    jmp     p2_left_done
p2_left_one:
    mov     r8, 1
p2_left_done:
    ; right child enters (r+1, c+1)
    mov     rbx, r15
    inc     rbx
    cmp     rbx, [height]
    jge     p2_right_one
    mov     rbx, r13
    inc     rbx
    cmp     rbx, [width]
    jge     p2_right_one
    mov     rcx, rdx
    add     rcx, [width]
    inc     rcx
    mov     r9, [g + rcx*8]
    jmp     p2_right_done
p2_right_one:
    mov     r9, 1
p2_right_done:
    mov     rax, r8
    add     rax, r9
p2_store:
    mov     [g + rdx*8], rax
    inc     r13
    jmp     p2_col
p2_col_done:
    dec     r15
    jmp     p2_row
p2_done:
    mov     rax, [srow]
    imul    rax, [width]
    add     rax, [scol]
    mov     rax, [g + rax*8]
    mov     [part2], rax

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