diff options
| -rw-r--r-- | aoc-2025/day1.asm | 178 | ||||
| -rw-r--r-- | aoc-2025/day2.asm | 192 | ||||
| -rw-r--r-- | aoc-2025/day3.asm | 146 | ||||
| -rw-r--r-- | aoc-2025/day4.asm | 322 | ||||
| -rw-r--r-- | aoc-2025/day5.asm | 331 | ||||
| -rw-r--r-- | aoc-2025/day6.asm | 419 | ||||
| -rw-r--r-- | aoc-2025/day7.asm | 390 | ||||
| -rw-r--r-- | aoc-2025/day8.asm | 431 |
8 files changed, 2140 insertions, 269 deletions
diff --git a/aoc-2025/day1.asm b/aoc-2025/day1.asm index 8ba8f0e..f130675 100644 --- a/aoc-2025/day1.asm +++ b/aoc-2025/day1.asm @@ -15,7 +15,7 @@ global _start %define STDOUT 1
section .data
- inputPath db "input/day1.txt", 0
+ input_path db "input/day1.txt", 0
newline db 10
label1 db "Password 1: ", 0
@@ -29,24 +29,24 @@ section .data section .bss
buffer resb 4096
- lineBuffer resb 256
- numberBuffer resb 16
- lineLen resd 1
+ line_buffer resb 256
+ number_buffer resb 16
+ line_len resd 1
section .text
_start:
; open file
mov rax, SYS_OPEN
- mov rdi, inputPath
+ mov rdi, input_path
mov rsi, O_RDONLY
xor rdx, rdx
syscall
- mov r12, rax ; fd in R12
- mov dword [lineLen], 0 ; no chars in current line yet
+ mov r12, rax ; fd in R12
+ mov dword [line_len], 0 ; no chars in current line yet
-ReadLoop:
+read_loop:
; read up to 4096 bytes
mov rax, SYS_READ
mov rdi, r12
@@ -55,80 +55,80 @@ ReadLoop: syscall
cmp rax, 0
- jle EOF ; <=0 -> EOF or error
+ jle eof ; <=0 -> EOF or error
- mov rdi, buffer ; scan pointer
- mov rbp, rax ; bytes remaining in this chunk
+ mov rdi, buffer ; scan pointer
+ mov rbp, rax ; bytes remaining in this chunk
-ScanChunk:
+scan_chunk:
cmp rbp, 0
- je ReadLoop ; chunk done, read next
+ je read_loop ; chunk done, read next
mov al, [rdi]
; windows can be a fucking bitch
; handle (CR) -> just skip
cmp al, 13
- je SkipCR
+ je skip_cr
; handle LF (10) -> end of line
cmp al, 10
- je EndOfLine
+ je end_of_line
- ; normal character -> append to lineBuffer if space left
- mov edx, [lineLen]
- cmp edx, 255 ; leave 1 byte for NULL
- jae SkipStore ; ignore extra characters if too long
- mov [lineBuffer+rdx], al
+ ; normal character -> append to line_buffer if space left
+ mov edx, [line_len]
+ cmp edx, 255 ; leave 1 byte for NULL
+ jae skip_store ; ignore extra characters if too long
+ mov [line_buffer+rdx], al
inc edx
- mov [lineLen], edx
+ mov [line_len], edx
-SkipStore:
+skip_store:
inc rdi
dec rbp
- jmp ScanChunk
+ jmp scan_chunk
-SkipCR:
+skip_cr:
inc rdi
dec rbp
- jmp ScanChunk
+ jmp scan_chunk
-EndOfLine:
+end_of_line:
; terminate current line
- mov edx, [lineLen]
- mov byte [lineBuffer+rdx], 0
+ mov edx, [line_len]
+ mov byte [line_buffer+rdx], 0
; if line isn't empty, process it
cmp edx, 0
- je LineDone
+ je line_done
push rdi
- mov rsi, lineBuffer
- call HandleLine
+ mov rsi, line_buffer
+ call handle_line
pop rdi
-LineDone:
- mov dword [lineLen], 0 ; reset line length
+line_done:
+ mov dword [line_len], 0 ; reset line length
inc rdi
dec rbp
- jmp ScanChunk
+ jmp scan_chunk
; process last line if not newline-terminated, then print result
-EOF:
+eof:
; if there is a partial line at EOF, process it
- mov edx, [lineLen]
+ mov edx, [line_len]
cmp edx, 0
- jle PrintResults
- mov byte [lineBuffer+rdx], 0
+ jle print_results
+ mov byte [line_buffer+rdx], 0
- mov rsi, lineBuffer
- call HandleLine
+ mov rsi, line_buffer
+ call handle_line
-PrintResults:
+print_results:
mov rcx, label1
- call PrintString
+ call print_string
mov eax, [password1]
- call PrintInt
+ call print_int
; newline
mov rax, SYS_WRITE
@@ -138,9 +138,9 @@ PrintResults: syscall
mov rcx, label2
- call PrintString
+ call print_string
mov eax, [password2]
- call PrintInt
+ call print_int
; new linhe
mov rax, SYS_WRITE
@@ -157,67 +157,67 @@ PrintResults: syscall
; Handle one line: RSI -> "L123" or "R45"
-HandleLine:
+handle_line:
mov al, [rsi]
cmp al, 'L'
je .left
- mov ebx, 1 ; direction = +1 for 'R' or anything else
+ mov ebx, 1 ; direction = +1 for 'R' or anything else
jmp .after
.left:
mov ebx, -1 ; direction = -1 for 'L'
.after:
- inc rsi ; skip 'L' or 'R'
- call ParseInt ; EAX = steps
+ inc rsi ; skip 'L' or 'R'
+ call parse_int ; EAX = steps
mov ecx, eax
; Part 1
-P1_Start:
+p1_start:
mov eax, ecx
imul eax, ebx
add eax, [angle1]
- call NormalizeAngle
+ call normalize_angle
mov [angle1], eax
cmp eax, 0
- jne P2_Start
+ jne p2_start
mov rdi, password1
mov edx, [rdi]
inc edx
mov [rdi], edx
; Part 2
-P2_Start:
+p2_start:
mov rdi, password2
.loop:
test ecx, ecx
- jle P2_Exit
+ jle p2_exit
dec ecx
mov eax, [angle2]
- call UpdateAngleCount
+ call update_angle_count
mov [angle2], eax
jmp .loop
-P2_Exit:
+p2_exit:
ret
; normalize eax to 0..99
-NormalizeAngle:
+normalize_angle:
cmp eax, 0
jl .add
cmp eax, 100
jl .done
sub eax, 100
- jmp NormalizeAngle
+ jmp normalize_angle
.add:
add eax, 100
- jmp NormalizeAngle
+ jmp normalize_angle
.done:
ret
; eax = angle, ebx = direction, rdi = password counter addr
-UpdateAngleCount:
+update_angle_count:
add eax, ebx
- call NormalizeAngle
+ call normalize_angle
cmp eax, 0
jne .done
@@ -228,29 +228,29 @@ UpdateAngleCount: ret
; parse ASCII integer into EAX
-ParseInt:
- xor eax, eax ; result = 0
-.parseLoop:
+parse_int:
+ xor eax, eax ; result = 0
+.parse_loop:
mov dl, [rsi]
cmp dl, '0'
jl .done
cmp dl, '9'
jg .done
- sub dl, '0' ; digit value 0..9
+ sub dl, '0' ; digit value 0..9
movzx edx, dl
- imul eax, eax, 10 ; result *= 10
- add eax, edx ; result += digit
+ imul eax, eax, 10 ; result *= 10
+ add eax, edx ; result += digit
inc rsi
- jmp .parseLoop
+ jmp .parse_loop
.done:
ret
-PrintInt:
- mov edi, numberBuffer+15 ; write digits from the end
- mov byte [rdi], 0 ; terminator
+print_int:
+ mov edi, number_buffer+15 ; write digits from the end
+ mov byte [rdi], 0 ; terminator
dec rdi
cmp eax, 0
@@ -262,48 +262,48 @@ PrintInt: ; q = eax / 10
; r = eax % 10
; using only subtraction
-.nextDigit:
- mov edx, eax ; tmp = current value
- mov ecx, 0 ; q = 0
+.next_digit:
+ mov edx, eax ; tmp = current value
+ mov ecx, 0 ; q = 0
- cmp edx, 10 ; if < 0, q=0, r=edx
- jb .lastDigit
-.subLoop:
+ cmp edx, 10 ; if < 0, q=0, r=edx
+ jb .last_digit
+.sub_loop:
sub edx, 10
- inc ecx ; q++
+ inc ecx ; q++
cmp edx, 10
- jae .subLoop ; while tmp >= 10
-.lastDigit:
+ jae .sub_loop ; while tmp >= 10
+.last_digit:
; now:
; ecx = quotient
; edx = remainder (0..9)
add dl, '0'
mov [rdi], dl ; store digit
dec rdi
- mov eax, ecx ; eax = quotient
+ mov eax, ecx ; eax = quotient
test eax, eax
- jnz .nextDigit ; more digits to extract?
+ jnz .next_digit ; more digits to extract?
- inc rdi ; move to first digit
+ inc rdi ; move to first digit
.finish:
mov rax, SYS_WRITE
- mov rsi, rdi ; buffer pointer
+ mov rsi, rdi ; buffer pointer
mov rdi, STDOUT
- mov rdx, numberBuffer+15
- sub rdx, rsi ; length
+ mov rdx, number_buffer+15
+ sub rdx, rsi ; length
syscall
ret
-PrintString:
+print_string:
push rcx
push rdx
mov rdx, 0
.count:
cmp byte [rcx+rdx], 0
- je .doneCount
+ je .done_count
inc rdx
jmp .count
-.doneCount:
+.done_count:
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, rcx
diff --git a/aoc-2025/day2.asm b/aoc-2025/day2.asm index dfbfb38..c1ae232 100644 --- a/aoc-2025/day2.asm +++ b/aoc-2025/day2.asm @@ -15,7 +15,7 @@ global _start %define STDOUT 1 section .data - inputPath db "input/day2.txt", 0 + input_path db "input/day2.txt", 0 newline db 10 label1 db "Part 1: ", 0 @@ -23,27 +23,27 @@ section .data section .bss buffer resb 4096 - lineBuffer resb 65536 - lineLen resd 1 + line_buffer resb 65536 + line_len resd 1 sum1 resq 1 sum2 resq 1 - numberBuffer resb 32 ; for printing and NumberToString + number_buffer resb 32 ; for printing and number_to_string section .text _start: mov rax, SYS_OPEN - mov rdi, inputPath + mov rdi, input_path mov rsi, O_RDONLY xor rdx, rdx syscall - mov r12, rax ; file descriptor - mov dword [lineLen], 0 + mov r12, rax ; file descriptor + mov dword [line_len], 0 -ReadLoop: +read_loop: mov rax, SYS_READ mov rdi, r12 mov rsi, buffer @@ -51,80 +51,80 @@ ReadLoop: syscall cmp rax, 0 - jle EOF + jle eof mov rdi, buffer mov rbp, rax -ScanChunk: +scan_chunk: cmp rbp, 0 - je ReadLoop + je read_loop mov al, [rdi] cmp al, 13 - je SkipCR + je skip_cr cmp al, 10 - je EndLine + je end_line - mov edx, [lineLen] + mov edx, [line_len] cmp edx, 65535 - jae SkipStore - mov [lineBuffer+rdx], al + jae skip_store + mov [line_buffer+rdx], al inc edx - mov [lineLen], edx + mov [line_len], edx -SkipStore: +skip_store: inc rdi dec rbp - jmp ScanChunk + jmp scan_chunk -SkipCR: +skip_cr: inc rdi dec rbp - jmp ScanChunk + jmp scan_chunk -EndLine: - mov edx, [lineLen] - mov byte [lineBuffer+rdx], 0 +end_line: + mov edx, [line_len] + mov byte [line_buffer+rdx], 0 cmp edx, 0 - je ClearLine + je clear_line push rdi - mov rsi, lineBuffer - call HandleLine + mov rsi, line_buffer + call handle_line pop rdi -ClearLine: - mov dword [lineLen], 0 +clear_line: + mov dword [line_len], 0 inc rdi dec rbp - jmp ScanChunk + jmp scan_chunk -EOF: +eof: ; process final partial line if needed - mov edx, [lineLen] + mov edx, [line_len] cmp edx, 0 - jle PrintResults + jle print_results - mov byte [lineBuffer+rdx], 0 - mov rsi, lineBuffer - call HandleLine + mov byte [line_buffer+rdx], 0 + mov rsi, line_buffer + call handle_line -PrintResults: +print_results: mov rcx, label1 - call PrintString + call print_string mov rax, [sum1] - call PrintInt64 - call Newline + call print_int64 + call print_newline mov rcx, label2 - call PrintString + call print_string mov rax, [sum2] - call PrintInt64 - call Newline + call print_int64 + call print_newline mov rax, SYS_CLOSE mov rdi, r12 @@ -136,58 +136,58 @@ PrintResults: ; parse "A-B,C-D,..."l, RSI = pointer to line ; uses r13 = current ID, r14 = end of range -HandleLine: -NextRange: +handle_line: +next_range: ; parse start - call ParseInt64 + call parse_int64 mov r13, rax cmp byte [rsi], '-' - jne DoneLine + jne done_line inc rsi ; parse end - call ParseInt64 + call parse_int64 mov r14, rax -RangeLoop: +range_loop: cmp r13, r14 - jg AfterRange + jg after_range ; Save RSI (line pointer) across the checks, - ; because NumberToString / CheckInvalid* use RSI + ; because number_to_string / check_invalid* use RSI push rsi ; Part 1: exact AA mov rax, r13 - call CheckInvalid1 + call check_invalid1 test rax, rax - jz .skipP1 + jz .skip_p1 add qword [sum1], r13 -.skipP1: +.skip_p1: ; Part 2: any repeating block >= 2 mov rax, r13 - call CheckInvalid2 + call check_invalid2 test rax, rax - jz .skipP2 + jz .skip_p2 add qword [sum2], r13 -.skipP2: - pop rsi ; restore line pointer +.skip_p2: + pop rsi ; restore line pointer inc r13 - jmp RangeLoop + jmp range_loop -AfterRange: +after_range: cmp byte [rsi], ',' - jne DoneLine + jne done_line inc rsi - jmp NextRange + jmp next_range -DoneLine: +done_line: ret ; RSI points at decimal digits; stops on first non-digit -ParseInt64: +parse_int64: xor rax, rax .parse: mov dl, [rsi] @@ -206,13 +206,13 @@ ParseInt64: .done: ret -; NumberToString: convert RAX to decimal ASCII, MSB-first +; number_to_string: convert RAX to decimal ASCII, MSB-first ; Output: ; RSI = pointer to first digit ; ECX = length -NumberToString: - mov rdi, numberBuffer+31 - mov byte [rdi], 0 ; terminator (for convenience) +number_to_string: + mov rdi, number_buffer+31 + mov byte [rdi], 0 ; terminator (for convenience) dec rdi cmp rax, 0 @@ -226,41 +226,41 @@ NumberToString: .conv: mov rbx, 10 -.nextDigit: +.next_digit: xor rdx, rdx - div rbx ; RAX = quotient, RDX = remainder + div rbx ; RAX = quotient, RDX = remainder add dl, '0' mov [rdi], dl dec rdi test rax, rax - jnz .nextDigit + jnz .next_digit - inc rdi ; now RDI points to first digit + inc rdi ; now RDI points to first digit mov rsi, rdi - mov rdx, numberBuffer+31 - sub rdx, rsi ; RDX = length + mov rdx, number_buffer+31 + sub rdx, rsi ; RDX = length mov ecx, edx ret -; CheckInvalid1: "AA" pattern +; check_invalid1: "AA" pattern ; RAX = number ; Returns RAX = 1 if digits == A A, else 0 -CheckInvalid1: +check_invalid1: push rbx push rdx - call NumberToString ; RSI=string, ECX=len - mov eax, ecx ; EAX = len + call number_to_string ; RSI=string, ECX=len + mov eax, ecx ; EAX = len cmp eax, 2 jl .no1 test eax, 1 - jnz .no1 ; odd length => cannot be AA + jnz .no1 ; odd length => cannot be AA - shr eax, 1 ; half = len/2 - mov r8d, eax ; half - xor r9d, r9d ; i = 0 + shr eax, 1 ; half = len/2 + mov r8d, eax ; half + xor r9d, r9d ; i = 0 .loop1: cmp r9d, r8d @@ -293,20 +293,20 @@ CheckInvalid1: pop rbx ret -; CheckInvalid2: any repeating block >= 2 +; check_invalid2: any repeating block >= 2 ; RAX = number ; Returns RAX = 1 if string is some A repeated k>=2 times -CheckInvalid2: +check_invalid2: push rbx push rdx - call NumberToString ; RSI=string, ECX=len - mov r11d, ecx ; n = length + call number_to_string ; RSI=string, ECX=len + mov r11d, ecx ; n = length cmp r11d, 2 jb .no2 - mov r8d, 1 ; m = 1 (candidate period) + mov r8d, 1 ; m = 1 (candidate period) .outer: cmp r8d, r11d jge .no2 @@ -314,16 +314,16 @@ CheckInvalid2: ; if n % m != 0 => cannot tile mov eax, r11d xor edx, edx - div r8d ; EAX=q, EDX=r + div r8d ; EAX=q, EDX=r test edx, edx jnz .next_m mov r9d, r11d - sub r9d, r8d ; limit = n - m - xor r10d, r10d ; i = 0 + sub r9d, r8d ; limit = n - m + xor r10d, r10d ; i = 0 .inner: cmp r10d, r9d - jge .yes2 ; all positions checked + jge .yes2 ; all positions checked ; s[i] mov rdx, r10 @@ -352,7 +352,7 @@ CheckInvalid2: pop rbx ret -Newline: +print_newline: mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, newline @@ -360,8 +360,8 @@ Newline: syscall ret -PrintInt64: - mov rdi, numberBuffer+31 +print_int64: + mov rdi, number_buffer+31 mov byte [rdi], 0 dec rdi @@ -386,12 +386,12 @@ PrintInt64: mov rax, SYS_WRITE mov rsi, rdi mov rdi, STDOUT - mov rdx, numberBuffer+31 + mov rdx, number_buffer+31 sub rdx, rsi syscall ret -PrintString: +print_string: push rcx push rdx mov rdx, 0 diff --git a/aoc-2025/day3.asm b/aoc-2025/day3.asm index e547475..c8b8b75 100644 --- a/aoc-2025/day3.asm +++ b/aoc-2025/day3.asm @@ -15,7 +15,7 @@ global _start %define STDOUT 1 section .data - inputPath db "input/day3.txt", 0 + input_path db "input/day3.txt", 0 newline db 10 @@ -24,28 +24,28 @@ section .data section .bss buffer resb 4096 - lineBuffer resb 65536 - lineLen resd 1 + line_buffer resb 65536 + line_len resd 1 sum1 resq 1 sum2 resq 1 - workDigits resb 64 ; stack for greedy subsequence - numberBuffer resb 32 ; for printing + work_digits resb 64 ; stack for greedy subsequence + number_buffer resb 32 ; for printing section .text _start: mov rax, SYS_OPEN - mov rdi, inputPath + mov rdi, input_path mov rsi, O_RDONLY xor rdx, rdx syscall - mov r12, rax ; fd - mov dword [lineLen], 0 + mov r12, rax ; fd + mov dword [line_len], 0 -ReadLoop: +read_loop: mov rax, SYS_READ mov rdi, r12 mov rsi, buffer @@ -53,80 +53,80 @@ ReadLoop: syscall cmp rax, 0 - jle EOF + jle eof mov rdi, buffer mov rbp, rax -ScanChunk: +scan_chunk: cmp rbp, 0 - je ReadLoop + je read_loop mov al, [rdi] cmp al, 13 - je SkipCR + je skip_cr cmp al, 10 - je EndLine + je end_line - mov edx, [lineLen] + mov edx, [line_len] cmp edx, 65535 - jae SkipStore - mov [lineBuffer+rdx], al + jae skip_store + mov [line_buffer+rdx], al inc edx - mov [lineLen], edx + mov [line_len], edx -SkipStore: +skip_store: inc rdi dec rbp - jmp ScanChunk + jmp scan_chunk -SkipCR: +skip_cr: inc rdi dec rbp - jmp ScanChunk + jmp scan_chunk -EndLine: - mov edx, [lineLen] - mov byte [lineBuffer+edx], 0 +end_line: + mov edx, [line_len] + mov byte [line_buffer+edx], 0 cmp edx, 0 - je ClearLine + je clear_line push rdi - mov rsi, lineBuffer - call HandleLine + mov rsi, line_buffer + call handle_line pop rdi -ClearLine: - mov dword [lineLen], 0 +clear_line: + mov dword [line_len], 0 inc rdi dec rbp - jmp ScanChunk + jmp scan_chunk -EOF: +eof: ; possible last partial line - mov edx, [lineLen] + mov edx, [line_len] cmp edx, 0 - jle PrintResults + jle print_results - mov byte [lineBuffer+edx], 0 - mov rsi, lineBuffer - call HandleLine + mov byte [line_buffer+edx], 0 + mov rsi, line_buffer + call handle_line -PrintResults: +print_results: mov rcx, label1 - call PrintString + call print_string mov rax, [sum1] - call PrintInt64 - call Newline + call print_int64 + call print_newline mov rcx, label2 - call PrintString + call print_string mov rax, [sum2] - call PrintInt64 - call Newline + call print_int64 + call print_newline mov rax, SYS_CLOSE mov rdi, r12 @@ -136,34 +136,34 @@ PrintResults: xor rdi, rdi syscall -HandleLine: +handle_line: mov rdi, rsi - xor ecx, ecx ; ECX = 0 -.lengthLoop: + xor ecx, ecx ; ECX = 0 +.length_loop: mov al, [rdi+rcx] cmp al, 0 - je .lengthDone + je .length_done inc ecx - jmp .lengthLoop -.lengthDone: - mov r15d, ecx ; r15d = n + jmp .length_loop +.length_done: + 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 + mov ecx, r15d ; ECX = n + mov edi, 2 ; K = 2 + call get_max_for_k ; RAX = best 2-digit value add qword [sum1], rax ; part 2: k = 12, only if n >= 12 cmp r15d, 12 - jl .skipPart2 + jl .skip_part2 mov ecx, r15d mov edi, 12 - call GetMaxForK ; RAX = best 12-digit value + call get_max_for_k ; RAX = best 12-digit value add qword [sum2], rax -.skipPart2: +.skip_part2: ret ; Greedy lexicographically largest subsequence of length K @@ -175,14 +175,14 @@ HandleLine: ; Output: ; RAX = numeric value of chosen k digits ; Clobbers: R8..R11, EAX, EDX -GetMaxForK: - ; dropsRemaining = n - k +get_max_for_k: + ; drops_remaining = n - k mov eax, ecx sub eax, edi - mov r8d, eax ; r8d = drops + mov r8d, eax ; r8d = drops - xor r9d, r9d ; r9d = stackSize - xor r10d, r10d ; r10d = i + xor r9d, r9d ; r9d = stack_size + xor r10d, r10d ; r10d = i .loop: cmp r10d, ecx @@ -201,7 +201,7 @@ GetMaxForK: mov edx, r9d dec edx mov r11d, edx - mov bl, [workDigits + r11] + mov bl, [work_digits + r11] cmp bl, al jge .push @@ -211,13 +211,13 @@ GetMaxForK: jmp .pop .push: mov r11d, r9d - mov [workDigits + r11], al + mov [work_digits + r11], al inc r9d inc r10d jmp .loop .after_input: - ; trim if stackSize > k + ; trim if stack_size > k .trim: cmp r9d, edi jle .convert @@ -226,12 +226,12 @@ GetMaxForK: .convert: xor rax, rax xor r11d, r11d -.convertLoop: +.convert_loop: cmp r11d, edi jge .done mov rdx, r11 - mov dl, [workDigits + rdx] + mov dl, [work_digits + rdx] sub dl, '0' movzx rdx, dl @@ -239,11 +239,11 @@ GetMaxForK: add rax, rdx inc r11d - jmp .convertLoop + jmp .convert_loop .done: ret -Newline: +print_newline: mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, newline @@ -251,8 +251,8 @@ Newline: syscall ret -PrintInt64: - mov rdi, numberBuffer+31 +print_int64: + mov rdi, number_buffer+31 mov byte [rdi], 0 dec rdi @@ -277,12 +277,12 @@ PrintInt64: mov rax, SYS_WRITE mov rsi, rdi mov rdi, STDOUT - mov rdx, numberBuffer+31 + mov rdx, number_buffer+31 sub rdx, rsi syscall ret -PrintString: +print_string: push rcx push rdx mov rdx, 0 diff --git a/aoc-2025/day4.asm b/aoc-2025/day4.asm index 475f2ef..57867b1 100644 --- a/aoc-2025/day4.asm +++ b/aoc-2025/day4.asm @@ -1,25 +1,325 @@ +; Advent of Code 2025 - Day 4 + bits 64 default rel global _start -%define SYS_EXIT 60 -%define SYS_WRITE 1 +%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 -%define STDOUT 1 +%define RAW_SIZE 4194304 ; 4 MiB scratch for the raw file +%define GRID_SIZE 4194304 ; 4 MiB for the padded grid / mark buffers section .data - message db "Hello Day 4!", 0xA - length equ $-message + input_path db "input/day4.txt", 0 + + newline db 10 + + label1 db "Part 1: ", 0 + label2 db "Part 2: ", 0 + +section .bss + raw resb RAW_SIZE ; raw file bytes + grid resb GRID_SIZE ; padded grid: 1 = roll, 0 = empty + mark resb GRID_SIZE ; per-round removal marks + + raw_len resq 1 + width resq 1 ; real columns per row + height resq 1 ; real rows + stride resq 1 ; width + 2 (padding on both sides) + + part1 resq 1 + part2 resq 1 + + number_buffer resb 32 ; for printing section .text + _start: - mov rax, SYS_WRITE - mov rdi, STDOUT - mov rsi, message - mov rdx, length + mov rax, SYS_OPEN + mov rdi, input_path + mov rsi, O_RDONLY + xor rdx, rdx + syscall + mov r12, rax ; fd + + xor r13, r13 ; bytes read so far +read_loop: + mov rax, SYS_READ + mov rdi, r12 + lea rsi, [raw + r13] + mov rdx, RAW_SIZE + sub rdx, r13 ; remaining capacity + syscall + + cmp rax, 0 + jle read_done + add r13, rax + jmp read_loop +read_done: + mov [raw_len], r13 + + mov rax, SYS_CLOSE + mov rdi, r12 + syscall + + xor rcx, rcx ; column scanner +width_scan: + cmp rcx, [raw_len] + jge width_done + mov al, [raw + rcx] + cmp al, 13 ; CR + je width_done + cmp al, 10 ; LF + je width_done + inc rcx + jmp width_scan +width_done: + mov [width], rcx + add rcx, 2 ; padding on left + right + mov [stride], rcx + + ; real cell (r, c) lives at grid[(r+1)*stride + (c+1)] + mov r10, [raw_len] + xor r8, r8 ; i (raw index) + xor r9, r9 ; r (row, 0-based) + xor r11, r11 ; c (col, 0-based) +fill_loop: + cmp r8, r10 + jge fill_end + mov al, [raw + r8] + inc r8 + + cmp al, 13 ; CR -> ignore + je fill_loop + cmp al, 10 ; LF -> end of line + je fill_newline + + cmp al, '@' + jne fill_next_col ; '.' leaves the zeroed cell alone + + ; grid[(r9+1)*stride + (r11+1)] = 1 + mov rbx, r9 + inc rbx + imul rbx, [stride] + add rbx, r11 + add rbx, 1 + mov byte [grid + rbx], 1 +fill_next_col: + inc r11 + jmp fill_loop +fill_newline: + cmp r11, 0 ; blank line -> skip (e.g. trailing newline) + je fill_loop + inc r9 + xor r11, r11 + jmp fill_loop +fill_end: + cmp r11, 0 ; last line had no trailing newline + je fill_height + inc r9 +fill_height: + mov [height], r9 + + mov r13, 1 ; row = 1..height +p1_row: + cmp r13, [height] + jg p1_done + mov rbx, r13 + imul rbx, [stride] + inc rbx ; idx of (row, col=1) + mov r12, 1 ; col = 1..width +p1_col: + cmp r12, [width] + jg p1_row_next + movzx eax, byte [grid + rbx] + test eax, eax + jz p1_next ; not a roll + mov rdi, rbx + call count_neighbors + cmp rax, 4 + jge p1_next ; 4 or more neighbors -> blocked + inc qword [part1] +p1_next: + inc rbx + inc r12 + jmp p1_col +p1_row_next: + inc r13 + jmp p1_row +p1_done: + +peel_loop: + mov r13, 1 +mark_row: + cmp r13, [height] + jg mark_done + mov rbx, r13 + imul rbx, [stride] + inc rbx + mov r12, 1 +mark_col: + cmp r12, [width] + jg mark_row_next + movzx eax, byte [grid + rbx] + test eax, eax + jz mark_zero ; empty cell + mov rdi, rbx + call count_neighbors + cmp rax, 4 + jl mark_one ; accessible +mark_zero: + mov byte [mark + rbx], 0 + jmp mark_next +mark_one: + mov byte [mark + rbx], 1 +mark_next: + inc rbx + inc r12 + jmp mark_col +mark_row_next: + inc r13 + jmp mark_row +mark_done: + + xor r11, r11 ; removed this round + mov r13, 1 +apply_row: + cmp r13, [height] + jg apply_done + mov rbx, r13 + imul rbx, [stride] + inc rbx + mov r12, 1 +apply_col: + cmp r12, [width] + jg apply_row_next + movzx eax, byte [mark + rbx] + test eax, eax + jz apply_next + mov byte [grid + rbx], 0 + inc r11 +apply_next: + inc rbx + inc r12 + jmp apply_col +apply_row_next: + inc r13 + jmp apply_row +apply_done: + add [part2], r11 + test r11, r11 + jnz peel_loop ; something changed -> another round + +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 + +; count_neighbors: sum of the 8 cells around a padded index +; Input: RDI = grid index +; Output: RAX = number of neighboring rolls (0..8) +; Clobbers: RAX, RCX, RDX, R8 +count_neighbors: + mov rcx, [stride] + xor eax, eax + + mov rdx, rdi + sub rdx, rcx ; row above + movzx r8d, byte [grid + rdx - 1] + add eax, r8d + movzx r8d, byte [grid + rdx] + add eax, r8d + movzx r8d, byte [grid + rdx + 1] + add eax, r8d + + movzx r8d, byte [grid + rdi - 1] ; same row, sides + add eax, r8d + movzx r8d, byte [grid + rdi + 1] + add eax, r8d + + mov rdx, rdi + add rdx, rcx ; row below + movzx r8d, byte [grid + rdx - 1] + add eax, r8d + movzx r8d, byte [grid + rdx] + add eax, r8d + movzx r8d, byte [grid + rdx + 1] + add eax, r8d + ret + +print_newline: + mov rax, SYS_WRITE + mov rdi, STDOUT + mov rsi, newline + mov rdx, 1 + syscall + ret + +print_int64: + mov rdi, number_buffer+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, number_buffer+31 + sub rdx, rsi syscall + ret - mov rax, SYS_EXIT - xor rdi, rdi +print_string: + 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 diff --git a/aoc-2025/day5.asm b/aoc-2025/day5.asm new file mode 100644 index 0000000..4f395a0 --- /dev/null +++ b/aoc-2025/day5.asm @@ -0,0 +1,331 @@ +; Advent of Code 2025 - Day 5 + +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 + +%define RAW_SIZE 1048576 ; 1 MiB scratch for the raw file +%define MAX_RANGES 8192 ; plenty for the ~177 input ranges + +section .data + input_path db "input/day5.txt", 0 + + newline db 10 + + label1 db "Part 1: ", 0 + label2 db "Part 2: ", 0 + +section .bss + raw resb RAW_SIZE + starts resq MAX_RANGES ; range/merged-interval starts + ends resq MAX_RANGES ; range/merged-interval ends + + raw_len resq 1 + n_ranges resq 1 ; ranges parsed in section 1 + n_merged resq 1 ; disjoint intervals after merge + phase resq 1 ; 0 = ranges, 1 = available IDs + + part1 resq 1 + part2 resq 1 + + number_buffer resb 32 + +section .text + +_start: + mov rax, SYS_OPEN + mov rdi, input_path + mov rsi, O_RDONLY + xor rdx, rdx + syscall + mov r12, rax ; fd + + xor r13, r13 +read_loop: + mov rax, SYS_READ + mov rdi, r12 + lea rsi, [raw + r13] + mov rdx, RAW_SIZE + sub rdx, r13 + syscall + cmp rax, 0 + jle read_done + add r13, rax + jmp read_loop +read_done: + mov [raw_len], r13 + + mov rax, SYS_CLOSE + mov rdi, r12 + syscall + + ; RSI = cursor, R14 = end pointer (both preserved across helper calls) + lea rsi, [raw] + mov rax, [raw_len] + lea r14, [raw + rax] + mov qword [phase], 0 + +scan_line: + cmp rsi, r14 + jae scan_done + mov al, [rsi] + cmp al, 10 ; LF -> blank line + je got_blank + cmp al, 13 ; CR -> blank line + je got_blank + + cmp qword [phase], 0 + jne do_avail + + call parse_u64 ; RAX = start + mov rcx, [n_ranges] + mov [starts + rcx*8], rax + inc rsi ; skip '-' + call parse_u64 ; RAX = end + mov rcx, [n_ranges] + mov [ends + rcx*8], rax + inc qword [n_ranges] + jmp skip_eol + +do_avail: + call parse_u64 + mov rdi, rax + call is_fresh ; RAX = 1 if fresh + test rax, rax + jz skip_eol + inc qword [part1] + jmp skip_eol + +got_blank: + ; the blank line separates the two sections + cmp qword [phase], 0 + jne skip_eol + call finalize_ranges ; sort + merge, compute part2 + mov qword [phase], 1 + ; fall through + +skip_eol: + cmp rsi, r14 + jae scan_done + mov al, [rsi] + inc rsi + cmp al, 10 ; consume through the LF + jne skip_eol + jmp scan_line + +scan_done: + ; safety: if there was no blank line, still finalize the ranges + cmp qword [phase], 0 + jne print_results + call finalize_ranges + +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 + +; parse_u64: read decimal digits at [RSI], advancing RSI past them. +; Output: RAX = value. Stops on the first non-digit. Clobbers RAX, RDX. +parse_u64: + xor rax, rax +.digit: + mov dl, [rsi] + cmp dl, '0' + jl .done + cmp dl, '9' + jg .done + sub dl, '0' + movzx rdx, dl + imul rax, rax, 10 + add rax, rdx + inc rsi + jmp .digit +.done: + ret + +; is_fresh: test membership of an ID in the merged intervals. +; Input: RDI = id +; Output: RAX = 1 if the id lies in any interval, else 0 +; Intervals are sorted ascending and disjoint, so we can stop early. +; Clobbers: RAX, RCX +is_fresh: + xor rcx, rcx +.loop: + cmp rcx, [n_merged] + jge .no + mov rax, [starts + rcx*8] + cmp rdi, rax + jl .no ; id below this start -> below all later ones + mov rax, [ends + rcx*8] + cmp rdi, rax + jle .yes ; start <= id <= end + inc rcx + jmp .loop +.no: + xor eax, eax + ret +.yes: + mov eax, 1 + ret + +; finalize_ranges: insertion-sort the ranges by start, merge overlapping / +; touching ones in place, store the disjoint intervals back into starts/ends, +; set n_merged, and accumulate their total size into part2. +; Clobbers: RAX, RCX, RDX, R8, R9, R10, R11, R12, R13 +finalize_ranges: + mov r8, 1 ; i +.sort_i: + cmp r8, [n_ranges] + jge .sorted + mov r10, [starts + r8*8] ; key_s + mov r11, [ends + r8*8] ; key_e + mov r9, r8 + dec r9 ; j = i - 1 +.sort_j: + cmp r9, 0 + jl .sort_place + mov rax, [starts + r9*8] + cmp rax, r10 + jle .sort_place ; starts[j] <= key -> in place + mov rdx, r9 + inc rdx ; j + 1 + mov [starts + rdx*8], rax ; shift start + mov rcx, [ends + r9*8] + mov [ends + rdx*8], rcx ; shift end + dec r9 + jmp .sort_j +.sort_place: + mov rdx, r9 + inc rdx + mov [starts + rdx*8], r10 + mov [ends + rdx*8], r11 + inc r8 + jmp .sort_i +.sorted: + + cmp qword [n_ranges], 0 + je .empty + + mov r10, [starts] ; cur_lo + mov r11, [ends] ; cur_hi + mov r8, 1 ; i + xor r12, r12 ; part2 accumulator + xor r13, r13 ; write index +.merge_loop: + cmp r8, [n_ranges] + jge .flush + mov rax, [starts + r8*8] ; s + mov rcx, [ends + r8*8] ; e + cmp rax, r11 + jg .gap ; s > cur_hi -> disjoint + cmp rcx, r11 ; overlap: cur_hi = max(cur_hi, e) + jle .no_extend + mov r11, rcx +.no_extend: + inc r8 + jmp .merge_loop +.gap: + call .emit + mov r10, rax ; begin new interval + mov r11, rcx + inc r8 + jmp .merge_loop +.flush: + call .emit + mov [n_merged], r13 + mov [part2], r12 + ret +.empty: + mov qword [n_merged], 0 + mov qword [part2], 0 + ret + +; local helper: emit [r10, r11] as merged interval r13, add its size to r12 +.emit: + mov [starts + r13*8], r10 + mov [ends + r13*8], r11 + inc r13 + mov rdx, r11 + sub rdx, r10 + inc rdx ; end - start + 1 + add r12, rdx + ret + +print_newline: + mov rax, SYS_WRITE + mov rdi, STDOUT + mov rsi, newline + mov rdx, 1 + syscall + ret + +print_int64: + mov rdi, number_buffer+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, number_buffer+31 + sub rdx, rsi + syscall + ret + +print_string: + 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 diff --git a/aoc-2025/day6.asm b/aoc-2025/day6.asm new file mode 100644 index 0000000..774ca4c --- /dev/null +++ b/aoc-2025/day6.asm @@ -0,0 +1,419 @@ +; Advent of Code 2025 - Day 6 + +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 + +%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 + + newline db 10 + + 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 + + number_buffer resb 32 + +section .text + +_start: + mov rax, SYS_OPEN + mov rdi, input_path + mov rsi, O_RDONLY + xor rdx, rdx + syscall + mov r12, rax + + xor r13, r13 +read_loop: + mov rax, SYS_READ + mov rdi, r12 + lea rsi, [raw + r13] + mov rdx, RAW_SIZE + sub rdx, r13 + syscall + cmp rax, 0 + jle read_done + add r13, rax + jmp read_loop +read_done: + mov [raw_len], r13 + + mov rax, SYS_CLOSE + mov rdi, r12 + syscall + + ; 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 + +print_newline: + mov rax, SYS_WRITE + mov rdi, STDOUT + mov rsi, newline + mov rdx, 1 + syscall + ret + +print_int64: + mov rdi, number_buffer+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, number_buffer+31 + sub rdx, rsi + syscall + ret + +print_string: + 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 diff --git a/aoc-2025/day7.asm b/aoc-2025/day7.asm new file mode 100644 index 0000000..40d700d --- /dev/null +++ b/aoc-2025/day7.asm @@ -0,0 +1,390 @@ +; Advent of Code 2025 - Day 7 + +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 + +%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 + + newline db 10 + + 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 + + number_buffer resb 32 + +section .text + +_start: + mov rax, SYS_OPEN + mov rdi, input_path + mov rsi, O_RDONLY + xor rdx, rdx + syscall + mov r12, rax + + xor r13, r13 +read_loop: + mov rax, SYS_READ + mov rdi, r12 + lea rsi, [raw + r13] + mov rdx, RAW_SIZE + sub rdx, r13 + syscall + cmp rax, 0 + jle read_done + add r13, rax + jmp read_loop +read_done: + mov [raw_len], r13 + + mov rax, SYS_CLOSE + mov rdi, r12 + syscall + + ; 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 + +print_newline: + mov rax, SYS_WRITE + mov rdi, STDOUT + mov rsi, newline + mov rdx, 1 + syscall + ret + +print_int64: + mov rdi, number_buffer+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, number_buffer+31 + sub rdx, rsi + syscall + ret + +print_string: + 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 diff --git a/aoc-2025/day8.asm b/aoc-2025/day8.asm new file mode 100644 index 0000000..407d0e4 --- /dev/null +++ b/aoc-2025/day8.asm @@ -0,0 +1,431 @@ +; Advent of Code 2025 - Day 8 + +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 + +%define RAW_SIZE 262144 +%define MAXN 1024 +%define MAXE (MAXN * (MAXN - 1) / 2) +%define K_LIMIT 1000 ; part 1 connects the K_LIMIT closest pairs + +section .data + input_path db "input/day8.txt", 0 + + newline db 10 + + label1 db "Part 1: ", 0 + label2 db "Part 2: ", 0 + +section .bss + raw resb RAW_SIZE + x resq MAXN + y resq MAXN + z resq MAXN + + edges resb (MAXE * 16) ; records: [dist2:8][i:4][j:4] + edges2 resb (MAXE * 16) ; radix ping-pong buffer + counts resq 256 + + parent resq MAXN + csize resq MAXN + + raw_len resq 1 + n_boxes resq 1 + m_edges resq 1 + sorted_ptr resq 1 + comp_count resq 1 + + part1 resq 1 + part2 resq 1 + + number_buffer resb 32 + +section .text + +_start: + mov rax, SYS_OPEN + mov rdi, input_path + mov rsi, O_RDONLY + xor rdx, rdx + syscall + mov r12, rax + + xor r13, r13 +read_loop: + mov rax, SYS_READ + mov rdi, r12 + lea rsi, [raw + r13] + mov rdx, RAW_SIZE + sub rdx, r13 + syscall + cmp rax, 0 + jle read_done + add r13, rax + jmp read_loop +read_done: + mov [raw_len], r13 + + mov rax, SYS_CLOSE + mov rdi, r12 + syscall + + ; parse "X,Y,Z" lines into x/y/z, counting boxes + lea rsi, [raw] + mov rax, [raw_len] + lea r14, [raw + rax] ; end pointer + xor r12, r12 ; box index +parse_line: + cmp rsi, r14 + jae parse_done + mov al, [rsi] + cmp al, 10 + je parse_skipnl + cmp al, 13 + je parse_skipnl + call parse_u64 + mov [x + r12*8], rax + inc rsi + call parse_u64 + mov [y + r12*8], rax + inc rsi + call parse_u64 + mov [z + r12*8], rax + inc r12 +parse_eol: + cmp rsi, r14 + jae parse_done + mov al, [rsi] + inc rsi + cmp al, 10 + jne parse_eol + jmp parse_line +parse_skipnl: + inc rsi + jmp parse_line +parse_done: + mov [n_boxes], r12 + + ; build every pairwise edge with squared distance as the key + lea r11, [edges] ; write pointer + xor r12, r12 ; edge count + xor r8, r8 ; i +gen_i: + cmp r8, [n_boxes] + jge gen_done + mov r13, [x + r8*8] + mov r14, [y + r8*8] + mov r15, [z + r8*8] + lea r9, [r8 + 1] ; j = i + 1 +gen_j: + cmp r9, [n_boxes] + jge gen_j_done + mov rax, r13 + sub rax, [x + r9*8] + imul rax, rax + mov rcx, rax + mov rax, r14 + sub rax, [y + r9*8] + imul rax, rax + add rcx, rax + mov rax, r15 + sub rax, [z + r9*8] + imul rax, rax + add rcx, rax ; key = dx^2 + dy^2 + dz^2 + mov [r11], rcx + mov [r11 + 8], r8d + mov [r11 + 12], r9d + add r11, 16 + inc r12 + inc r9 + jmp gen_j +gen_j_done: + inc r8 + jmp gen_i +gen_done: + mov [m_edges], r12 + + ; LSD radix sort by the 5 low bytes of the key (max key < 2^40) + lea r11, [edges] ; src + lea r12, [edges2] ; dst + xor r13, r13 ; byte pass 0..4 +rsort_pass: + cmp r13, 5 + jge rsort_done + lea rdi, [counts] + mov rcx, 256 + xor rax, rax + rep stosq + + xor rcx, rcx ; k +rs_hist: + cmp rcx, [m_edges] + jge rs_hist_done + mov rax, rcx + shl rax, 4 + add rax, r11 + movzx edx, byte [rax + r13] + inc qword [counts + rdx*8] + inc rcx + jmp rs_hist +rs_hist_done: + xor rcx, rcx ; t + xor r8, r8 ; running offset +rs_prefix: + cmp rcx, 256 + jge rs_prefix_done + mov rax, [counts + rcx*8] + mov [counts + rcx*8], r8 + add r8, rax + inc rcx + jmp rs_prefix +rs_prefix_done: + xor rcx, rcx ; k +rs_scatter: + cmp rcx, [m_edges] + jge rs_scatter_done + mov rax, rcx + shl rax, 4 + add rax, r11 ; src record + movzx edx, byte [rax + r13] + mov r9, [counts + rdx*8] + inc qword [counts + rdx*8] + mov r10, r9 + shl r10, 4 + add r10, r12 ; dst slot + mov r8, [rax] + mov [r10], r8 + mov r8, [rax + 8] + mov [r10 + 8], r8 + inc rcx + jmp rs_scatter +rs_scatter_done: + xchg r11, r12 + inc r13 + jmp rsort_pass +rsort_done: + mov [sorted_ptr], r11 + + ; union-find init + xor rcx, rcx +dsu_init: + cmp rcx, [n_boxes] + jge dsu_done + mov [parent + rcx*8], rcx + mov qword [csize + rcx*8], 1 + inc rcx + jmp dsu_init +dsu_done: + mov rax, [n_boxes] + mov [comp_count], rax + mov qword [part2], 0 + + ; Kruskal: one sorted pass drives both parts + mov r11, [sorted_ptr] + xor r15, r15 ; edge index +kloop: + cmp r15, [m_edges] + jge kdone + mov r12, r15 + shl r12, 4 + add r12, r11 ; record pointer + mov r13d, [r12 + 8] ; i + mov r14d, [r12 + 12] ; j + + mov edi, r13d + call find + mov rbx, rax ; root of i + mov edi, r14d + call find ; root of j + + cmp rbx, rax + je k_after ; already connected + + mov rcx, [csize + rbx*8] + mov rdx, [csize + rax*8] + cmp rcx, rdx + jge k_no_swap + xchg rbx, rax ; keep rbx as the larger root +k_no_swap: + mov [parent + rax*8], rbx + mov rcx, [csize + rax*8] + add [csize + rbx*8], rcx + dec qword [comp_count] + + cmp qword [comp_count], 1 + jne k_after + cmp qword [part2], 0 + jne k_after + mov rax, [x + r13*8] + imul rax, [x + r14*8] + mov [part2], rax +k_after: + cmp r15, (K_LIMIT - 1) + jne k_check_break + call compute_part1 +k_check_break: + cmp r15, (K_LIMIT - 1) + jl k_next + cmp qword [part2], 0 + je k_next + jmp kdone +k_next: + inc r15 + jmp kloop +kdone: + +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 + +; find: union-find root of node RDI, with path halving. +; Output: RAX = root. Clobbers RAX, RDX, RDI. +find: +.loop: + mov rax, [parent + rdi*8] + cmp rax, rdi + je .done + mov rdx, [parent + rax*8] + mov [parent + rdi*8], rdx + mov rdi, rdx + jmp .loop +.done: + ret + +; compute_part1: product of the three largest component sizes into part1. +; Clobbers RAX, RCX, R8, R9, R10. +compute_part1: + xor r8, r8 ; largest + xor r9, r9 ; 2nd + xor r10, r10 ; 3rd + xor rcx, rcx +.loop: + cmp rcx, [n_boxes] + jge .done + mov rax, [parent + rcx*8] + cmp rax, rcx + jne .next ; not a root + mov rax, [csize + rcx*8] + cmp rax, r8 + jle .try2 + mov r10, r9 + mov r9, r8 + mov r8, rax + jmp .next +.try2: + cmp rax, r9 + jle .try3 + mov r10, r9 + mov r9, rax + jmp .next +.try3: + cmp rax, r10 + jle .next + mov r10, rax +.next: + inc rcx + jmp .loop +.done: + mov rax, r8 + imul rax, r9 + imul rax, r10 + mov [part1], rax + ret + +; parse_u64: read decimal digits at [RSI], advancing RSI. Clobbers RAX, RDX. +parse_u64: + xor rax, rax +.digit: + mov dl, [rsi] + cmp dl, '0' + jl .done + cmp dl, '9' + jg .done + sub dl, '0' + movzx rdx, dl + imul rax, rax, 10 + add rax, rdx + inc rsi + jmp .digit +.done: + ret + +print_newline: + mov rax, SYS_WRITE + mov rdi, STDOUT + mov rsi, newline + mov rdx, 1 + syscall + ret + +print_int64: + mov rdi, number_buffer+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, number_buffer+31 + sub rdx, rsi + syscall + ret + +print_string: + 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 |
