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
|
; Advent of Code 2025 - Day 1.1
; #include <stddef.h>
; #include <stdio.h>
; #include <stdlib.h>
; #include <stdint.h>
;
; int main(void)
; {
; FILE* input = fopen("input/day1.txt", "r");
;
; int32_t angle = 50;
; int32_t password = 0;
;
; char line[256];
; while (fgets(line, sizeof(line), input))
; {
; int32_t direction = (line[0] == 'L') ? -1 : 1;
; int32_t steps = atoi(line + 1);
;
; angle += direction * steps;
; angle = (angle % 100 + 100) % 100;
;
; if (angle == 0)
; password++;
; }
;
; fclose(input);
; printf("Password: %d\n", password);
; }
global _start
%define SYS_EXIT 1
%define SYS_READ 3
%define SYS_WRITE 4
%define SYS_OPEN 5
%define SYS_CLOSE 6
%define O_RDONLY 0
%define STDOUT 1
section .data
inputPath db "input/day1.txt", 0
newline db 10 ; '\n'
angle dd 50 ; initial angle
password dd 0 ; result counter
section .bss
buffer resb 4096 ; chunk read buffer
lineBuffer resb 256 ; one line max 255 chars + NUL
numberBuffer resb 16 ; for PrintInt
lineLen resd 1 ; current line length
section .text
_start:
; open file
mov eax, SYS_OPEN
mov ebx, inputPath
mov ecx, O_RDONLY
int 0x80
mov esi, eax ; fd in ESI
mov dword [lineLen], 0 ; no chars in current line yet
ReadLoop:
; read up to 4096 bytes
mov eax, SYS_READ
mov ebx, esi
mov ecx, buffer
mov edx, 4096
int 0x80
cmp eax, 0
jle EOF ; 0 or negative = EOF or error
mov edi, buffer ; scan pointer
mov ecx, eax ; bytes remaining in this chunk
ScanChunk:
cmp ecx, 0
je ReadLoop ; chunk done, read next
mov al, [edi]
; windows can be a fucking bitch
; handle CR (13) -> just skip
cmp al, 13
je SkipCR
; handle LF (10) -> end of line
cmp al, 10
je EndOfLine
; normal character: append to lineBuffer if space left
mov edx, [lineLen]
cmp edx, 255 ; leave 1 byte for NUL
jae SkipStore ; ignore extra chars if too long
mov [lineBuffer + edx], al
inc edx
mov [lineLen], edx
SkipStore:
inc edi
dec ecx
jmp ScanChunk
SkipCR:
inc edi
dec ecx
jmp ScanChunk
EndOfLine:
; terminate current line
mov edx, [lineLen]
mov byte [lineBuffer + edx], 0
; if line isn't empty, process it
cmp edx, 0
je LineDone
push esi
mov esi, lineBuffer
call HandleLine
pop esi
LineDone:
mov dword [lineLen], 0 ; reset line length
inc edi
dec ecx
jmp ScanChunk
; process last line if not newline-terminated, then print result
EOF:
; if there is a partial line at EOF, process it
mov edx, [lineLen]
cmp edx, 0
jle FinishEOF
mov byte [lineBuffer + edx], 0
push esi
mov esi, lineBuffer
call HandleLine
pop esi
FinishEOF:
mov eax, [password]
call PrintInt
; newline after result
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, newline
mov edx, 1
int 0x80
; close file and exit
mov eax, SYS_CLOSE
mov ebx, esi
int 0x80
mov eax, SYS_EXIT
xor ebx, ebx
int 0x80
; Handle one line: ESI -> "L123" or "R45"
HandleLine:
mov al, [esi]
cmp al, 'L'
je .left
mov ebx, 1 ; direction = +1 for 'R' or anything else
jmp .after
.left:
mov ebx, -1 ; direction = -1 for 'L'
.after:
inc esi ; skip 'L' or 'R'
call ParseInt ; EAX = steps
imul eax, ebx ; EAX = dir * steps
mov edx, [angle]
add edx, eax ; update angle (can be out of range, signed)
; normalize edx into [0, 100[ using repeated +/-100 (no division)
NormLoop:
cmp edx, 0
jl NormAdd
cmp edx, 100
jl NormDone
sub edx, 100
jmp NormLoop
NormAdd:
add edx, 100
jmp NormLoop
NormDone:
mov [angle], edx
cmp edx, 0
jne .done
mov eax, [password]
inc eax
mov [password], eax
.done:
ret
; ParseInt: - parse decimal number at [ESI] into EAX
; - stops at first non-digit
ParseInt:
xor eax, eax ; result = 0
.parseLoop:
mov dl, [esi]
cmp dl, '0'
jl .done
cmp dl, '9'
jg .done
sub dl, '0' ; digit value 0..9
movzx edx, dl
imul eax, eax, 10 ; result *= 10
add eax, edx ; result += digit
inc esi
jmp .parseLoop
.done:
ret
; PrintInt: print unsigned integer in EAX to stdout
PrintInt:
mov edi, numberBuffer+15 ; write digits from the end
mov byte [edi], 0 ; terminator
dec edi
cmp eax, 0
jne .convert
mov byte [edi], '0'
jmp .finish
.convert:
; we will repeatedly compute:
; q = eax / 10
; r = eax % 10
; using only subtraction
.nextDigit:
mov edx, eax ; tmp = current value
mov ecx, 0 ; q = 0
cmp edx, 10
jb .lastDigit ; if < 10, quotient = 0, remainder = edx
.subLoop:
sub edx, 10
inc ecx ; q++
cmp edx, 10
jae .subLoop ; while tmp >= 10
.lastDigit:
; now:
; ecx = quotient
; edx = remainder (0..9)
add dl, '0'
mov [edi], dl ; store digit
dec edi
mov eax, ecx ; eax = quotient
test eax, eax
jnz .nextDigit ; more digits to extract?
inc edi ; move to first digit
.finish:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, edi
mov edx, numberBuffer+15
sub edx, edi ; length
int 0x80
ret
|