hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/aoc-2025/day3.asm
blob: e54747599e5030cb48125cb96b813c2feed00e22 (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
; Advent of Code 2025 - Day 3

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

section .data
    inputPath db "input/day3.txt", 0

    newline   db 10

    label1 db "Part 1: ", 0
    label2 db "Part 2: ", 0

section .bss
    buffer       resb 4096
    lineBuffer   resb 65536
    lineLen      resd 1

    sum1         resq 1
    sum2         resq 1

    workDigits   resb 64        ; stack for greedy subsequence
    numberBuffer resb 32        ; for printing

section .text

_start:
    mov     rax, SYS_OPEN
    mov     rdi, inputPath
    mov     rsi, O_RDONLY
    xor     rdx, rdx
    syscall

    mov     r12, rax                 ; fd
    mov     dword [lineLen], 0

ReadLoop:
    mov     rax, SYS_READ
    mov     rdi, r12
    mov     rsi, buffer
    mov     rdx, 4096
    syscall

    cmp     rax, 0
    jle     EOF

    mov     rdi, buffer
    mov     rbp, rax

ScanChunk:
    cmp     rbp, 0
    je      ReadLoop

    mov     al, [rdi]

    cmp     al, 13
    je      SkipCR

    cmp     al, 10
    je      EndLine

    mov     edx, [lineLen]
    cmp     edx, 65535
    jae     SkipStore
    mov     [lineBuffer+rdx], al
    inc     edx
    mov     [lineLen], edx

SkipStore:
    inc     rdi
    dec     rbp
    jmp     ScanChunk

SkipCR:
    inc     rdi
    dec     rbp
    jmp     ScanChunk

EndLine:
    mov     edx, [lineLen]
    mov     byte [lineBuffer+edx], 0

    cmp     edx, 0
    je      ClearLine

    push    rdi
    mov     rsi, lineBuffer
    call    HandleLine
    pop     rdi

ClearLine:
    mov     dword [lineLen], 0
    inc     rdi
    dec     rbp
    jmp     ScanChunk

EOF:
    ; possible last partial line
    mov     edx, [lineLen]
    cmp     edx, 0
    jle     PrintResults

    mov     byte [lineBuffer+edx], 0
    mov     rsi, lineBuffer
    call    HandleLine

PrintResults:
    mov     rcx, label1
    call    PrintString
    mov     rax, [sum1]
    call    PrintInt64
    call    Newline

    mov     rcx, label2
    call    PrintString
    mov     rax, [sum2]
    call    PrintInt64
    call    Newline

    mov     rax, SYS_CLOSE
    mov     rdi, r12
    syscall

    mov     rax, SYS_EXIT
    xor     rdi, rdi
    syscall

HandleLine:
    mov     rdi, rsi
    xor     ecx, ecx              ; ECX = 0
.lengthLoop:
    mov     al, [rdi+rcx]
    cmp     al, 0
    je      .lengthDone
    inc     ecx
    jmp     .lengthLoop
.lengthDone:
    mov     r15d, ecx             ; r15d = n

    ; part 1: k = 2
    mov     ecx, r15d             ; ECX = n
    mov     edi, 2                ; K = 2
    call    GetMaxForK            ; RAX = best 2-digit value
    add     qword [sum1], rax

    ; part 2: k = 12, only if n >= 12
    cmp     r15d, 12
    jl      .skipPart2

    mov     ecx, r15d
    mov     edi, 12
    call    GetMaxForK            ; RAX = best 12-digit value
    add     qword [sum2], rax

.skipPart2:
    ret

; Greedy lexicographically largest subsequence of length K
;
; Input:
;   RSI -> digits string
;   ECX = n (length)
;   EDI = k
; Output:
;   RAX = numeric value of chosen k digits
; Clobbers: R8..R11, EAX, EDX
GetMaxForK:
    ; dropsRemaining = n - k
    mov     eax, ecx
    sub     eax, edi
    mov     r8d, eax              ; r8d = drops

    xor     r9d, r9d              ; r9d = stackSize
    xor     r10d, r10d            ; r10d = i

.loop:
    cmp     r10d, ecx
    jge     .after_input

    ; current digit in AL
    mov     r11, r10
    mov     al, [rsi + r11]

.pop:
    cmp     r9d, 0
    jle     .push
    cmp     r8d, 0
    jle     .push

    mov     edx, r9d
    dec     edx
    mov     r11d, edx
    mov     bl, [workDigits + r11]

    cmp     bl, al
    jge     .push

    dec     r9d
    dec     r8d
    jmp     .pop
.push:
    mov     r11d, r9d
    mov     [workDigits + r11], al
    inc     r9d
    inc     r10d
    jmp     .loop

.after_input:
    ; trim if stackSize > k
.trim:
    cmp     r9d, edi
    jle     .convert
    dec     r9d
    jmp     .trim
.convert:
    xor     rax, rax
    xor     r11d, r11d
.convertLoop:
    cmp     r11d, edi
    jge     .done

    mov     rdx, r11
    mov     dl, [workDigits + rdx]
    sub     dl, '0'
    movzx   rdx, dl

    imul    rax, rax, 10
    add     rax, rdx

    inc     r11d
    jmp     .convertLoop
.done:
    ret

Newline:
    mov     rax, SYS_WRITE
    mov     rdi, STDOUT
    mov     rsi, newline
    mov     rdx, 1
    syscall
    ret

PrintInt64:
    mov     rdi, numberBuffer+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, numberBuffer+31
    sub     rdx, rsi
    syscall
    ret

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