diff options
Diffstat (limited to 'aoc-2025')
| -rw-r--r-- | aoc-2025/day1.asm | 314 | ||||
| -rw-r--r-- | aoc-2025/day2.asm | 410 | ||||
| -rw-r--r-- | aoc-2025/day3.asm | 301 | ||||
| -rw-r--r-- | aoc-2025/day4.asm | 25 |
4 files changed, 1050 insertions, 0 deletions
diff --git a/aoc-2025/day1.asm b/aoc-2025/day1.asm new file mode 100644 index 0000000..8ba8f0e --- /dev/null +++ b/aoc-2025/day1.asm @@ -0,0 +1,314 @@ +; Advent of Code 2025 - Day 1
+
+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/day1.txt", 0
+ newline db 10
+
+ label1 db "Password 1: ", 0
+ label2 db "Password 2: ", 0
+
+ angle1 dd 50
+ angle2 dd 50
+
+ password1 dd 0
+ password2 dd 0
+
+section .bss
+ buffer resb 4096
+ lineBuffer resb 256
+ numberBuffer resb 16
+ lineLen resd 1
+
+section .text
+
+_start:
+ ; open file
+ mov rax, SYS_OPEN
+ mov rdi, inputPath
+ mov rsi, O_RDONLY
+ xor rdx, rdx
+ syscall
+
+ mov r12, rax ; fd in R12
+ mov dword [lineLen], 0 ; no chars in current line yet
+
+ReadLoop:
+ ; read up to 4096 bytes
+ mov rax, SYS_READ
+ mov rdi, r12
+ mov rsi, buffer
+ mov rdx, 4096
+ syscall
+
+ cmp rax, 0
+ jle EOF ; <=0 -> EOF or error
+
+ mov rdi, buffer ; scan pointer
+ mov rbp, rax ; bytes remaining in this chunk
+
+ScanChunk:
+ cmp rbp, 0
+ je ReadLoop ; chunk done, read next
+
+ mov al, [rdi]
+
+ ; windows can be a fucking bitch
+ ; handle (CR) -> 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 NULL
+ jae SkipStore ; ignore extra characters if too long
+ mov [lineBuffer+rdx], al
+ inc edx
+ mov [lineLen], edx
+
+SkipStore:
+ inc rdi
+ dec rbp
+ jmp ScanChunk
+
+SkipCR:
+ inc rdi
+ dec rbp
+ jmp ScanChunk
+
+EndOfLine:
+ ; terminate current line
+ mov edx, [lineLen]
+ mov byte [lineBuffer+rdx], 0
+
+ ; if line isn't empty, process it
+ cmp edx, 0
+ je LineDone
+
+ push rdi
+ mov rsi, lineBuffer
+ call HandleLine
+ pop rdi
+
+LineDone:
+ mov dword [lineLen], 0 ; reset line length
+ inc rdi
+ dec rbp
+ 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 PrintResults
+ mov byte [lineBuffer+rdx], 0
+
+ mov rsi, lineBuffer
+ call HandleLine
+
+PrintResults:
+ mov rcx, label1
+ call PrintString
+ mov eax, [password1]
+ call PrintInt
+
+ ; newline
+ mov rax, SYS_WRITE
+ mov rdi, STDOUT
+ mov rsi, newline
+ mov rdx, 1
+ syscall
+
+ mov rcx, label2
+ call PrintString
+ mov eax, [password2]
+ call PrintInt
+
+ ; new linhe
+ mov rax, SYS_WRITE
+ mov rdi, STDOUT
+ mov rsi, newline
+ mov rdx, 1
+ syscall
+
+ mov rax, SYS_CLOSE
+ mov rdi, r12
+ syscall
+ mov rax, SYS_EXIT
+ xor rdi, rdi
+ syscall
+
+; Handle one line: RSI -> "L123" or "R45"
+HandleLine:
+ mov al, [rsi]
+ 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 rsi ; skip 'L' or 'R'
+ call ParseInt ; EAX = steps
+ mov ecx, eax
+
+; Part 1
+P1_Start:
+ mov eax, ecx
+ imul eax, ebx
+ add eax, [angle1]
+ call NormalizeAngle
+ mov [angle1], eax
+ cmp eax, 0
+ jne P2_Start
+ mov rdi, password1
+ mov edx, [rdi]
+ inc edx
+ mov [rdi], edx
+
+; Part 2
+P2_Start:
+ mov rdi, password2
+.loop:
+ test ecx, ecx
+ jle P2_Exit
+ dec ecx
+
+ mov eax, [angle2]
+ call UpdateAngleCount
+ mov [angle2], eax
+
+ jmp .loop
+P2_Exit:
+ ret
+
+; normalize eax to 0..99
+NormalizeAngle:
+ cmp eax, 0
+ jl .add
+ cmp eax, 100
+ jl .done
+ sub eax, 100
+ jmp NormalizeAngle
+.add:
+ add eax, 100
+ jmp NormalizeAngle
+.done:
+ ret
+
+; eax = angle, ebx = direction, rdi = password counter addr
+UpdateAngleCount:
+ add eax, ebx
+ call NormalizeAngle
+
+ cmp eax, 0
+ jne .done
+ mov edx, [rdi]
+ inc edx
+ mov [rdi], edx
+.done:
+ ret
+
+; parse ASCII integer into EAX
+ParseInt:
+ xor eax, eax ; result = 0
+.parseLoop:
+ mov dl, [rsi]
+ 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 rsi
+ jmp .parseLoop
+.done:
+ ret
+
+PrintInt:
+ mov edi, numberBuffer+15 ; write digits from the end
+ mov byte [rdi], 0 ; terminator
+ dec rdi
+
+ cmp eax, 0
+ jne .convert
+ mov byte [rdi], '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 ; if < 0, q=0, r=edx
+ jb .lastDigit
+.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 [rdi], dl ; store digit
+ dec rdi
+ mov eax, ecx ; eax = quotient
+ test eax, eax
+ jnz .nextDigit ; more digits to extract?
+
+ inc rdi ; move to first digit
+.finish:
+ mov rax, SYS_WRITE
+ mov rsi, rdi ; buffer pointer
+ mov rdi, STDOUT
+ mov rdx, numberBuffer+15
+ sub rdx, rsi ; length
+ syscall
+ ret
+
+PrintString:
+ push rcx
+ push rdx
+ mov rdx, 0
+.count:
+ cmp byte [rcx+rdx], 0
+ je .doneCount
+ inc rdx
+ jmp .count
+.doneCount:
+ mov rax, SYS_WRITE
+ mov rdi, STDOUT
+ mov rsi, rcx
+ syscall
+
+ pop rdx
+ pop rcx
+ ret
diff --git a/aoc-2025/day2.asm b/aoc-2025/day2.asm new file mode 100644 index 0000000..dfbfb38 --- /dev/null +++ b/aoc-2025/day2.asm @@ -0,0 +1,410 @@ +; Advent of Code 2025 – Day 2 + +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/day2.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 + + numberBuffer resb 32 ; for printing and NumberToString + +section .text + +_start: + mov rax, SYS_OPEN + mov rdi, inputPath + mov rsi, O_RDONLY + xor rdx, rdx + syscall + + mov r12, rax ; file descriptor + 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+rdx], 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: + ; process final partial line if needed + mov edx, [lineLen] + cmp edx, 0 + jle PrintResults + + mov byte [lineBuffer+rdx], 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 + +; parse "A-B,C-D,..."l, RSI = pointer to line +; uses r13 = current ID, r14 = end of range +HandleLine: +NextRange: + ; parse start + call ParseInt64 + mov r13, rax + + cmp byte [rsi], '-' + jne DoneLine + inc rsi + + ; parse end + call ParseInt64 + mov r14, rax + +RangeLoop: + cmp r13, r14 + jg AfterRange + + ; Save RSI (line pointer) across the checks, + ; because NumberToString / CheckInvalid* use RSI + push rsi + + ; Part 1: exact AA + mov rax, r13 + call CheckInvalid1 + test rax, rax + jz .skipP1 + add qword [sum1], r13 +.skipP1: + ; Part 2: any repeating block >= 2 + mov rax, r13 + call CheckInvalid2 + test rax, rax + jz .skipP2 + add qword [sum2], r13 +.skipP2: + pop rsi ; restore line pointer + + inc r13 + jmp RangeLoop + +AfterRange: + cmp byte [rsi], ',' + jne DoneLine + inc rsi + jmp NextRange + +DoneLine: + ret + +; RSI points at decimal digits; stops on first non-digit +ParseInt64: + xor rax, rax +.parse: + 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 .parse +.done: + ret + +; NumberToString: 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) + dec rdi + + cmp rax, 0 + jne .conv + + ; handle zero + mov byte [rdi], '0' + mov rsi, rdi + mov ecx, 1 + ret + +.conv: + mov rbx, 10 +.nextDigit: + xor rdx, rdx + div rbx ; RAX = quotient, RDX = remainder + add dl, '0' + mov [rdi], dl + dec rdi + test rax, rax + jnz .nextDigit + + inc rdi ; now RDI points to first digit + mov rsi, rdi + mov rdx, numberBuffer+31 + sub rdx, rsi ; RDX = length + mov ecx, edx + ret + +; CheckInvalid1: "AA" pattern +; RAX = number +; Returns RAX = 1 if digits == A A, else 0 +CheckInvalid1: + push rbx + push rdx + + call NumberToString ; RSI=string, ECX=len + mov eax, ecx ; EAX = len + + cmp eax, 2 + jl .no1 + + test eax, 1 + jnz .no1 ; odd length => cannot be AA + + shr eax, 1 ; half = len/2 + mov r8d, eax ; half + xor r9d, r9d ; i = 0 + +.loop1: + cmp r9d, r8d + jge .yes1 + + ; s[i] + mov rdx, r9 + movzx eax, byte [rsi + rdx] + + ; s[i+half] + mov rdx, r9 + add rdx, r8 + movzx ebx, byte [rsi + rdx] + + cmp eax, ebx + jne .no1 + + inc r9d + jmp .loop1 + +.yes1: + mov rax, 1 + jmp .ret1 + +.no1: + xor rax, rax + +.ret1: + pop rdx + pop rbx + ret + +; CheckInvalid2: any repeating block >= 2 +; RAX = number +; Returns RAX = 1 if string is some A repeated k>=2 times +CheckInvalid2: + push rbx + push rdx + + call NumberToString ; RSI=string, ECX=len + mov r11d, ecx ; n = length + + cmp r11d, 2 + jb .no2 + + mov r8d, 1 ; m = 1 (candidate period) +.outer: + cmp r8d, r11d + jge .no2 + + ; if n % m != 0 => cannot tile + mov eax, r11d + xor edx, edx + 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 +.inner: + cmp r10d, r9d + jge .yes2 ; all positions checked + + ; s[i] + mov rdx, r10 + movzx eax, byte [rsi + rdx] + + ; s[i+m] + mov rdx, r10 + add rdx, r8 + movzx ebx, byte [rsi + rdx] + + cmp eax, ebx + jne .next_m + + inc r10d + jmp .inner +.yes2: + mov rax, 1 + jmp .ret2 +.next_m: + inc r8d + jmp .outer +.no2: + xor rax, rax +.ret2: + pop rdx + pop rbx + 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 diff --git a/aoc-2025/day3.asm b/aoc-2025/day3.asm new file mode 100644 index 0000000..e547475 --- /dev/null +++ b/aoc-2025/day3.asm @@ -0,0 +1,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 diff --git a/aoc-2025/day4.asm b/aoc-2025/day4.asm new file mode 100644 index 0000000..475f2ef --- /dev/null +++ b/aoc-2025/day4.asm @@ -0,0 +1,25 @@ +bits 64 +default rel + +global _start + +%define SYS_EXIT 60 +%define SYS_WRITE 1 + +%define STDOUT 1 + +section .data + message db "Hello Day 4!", 0xA + length equ $-message + +section .text +_start: + mov rax, SYS_WRITE + mov rdi, STDOUT + mov rsi, message + mov rdx, length + syscall + + mov rax, SYS_EXIT + xor rdi, rdi + syscall |
