This commit is contained in:
2025-12-08 17:02:44 +01:00
parent 9d8676a109
commit e5a214187a
13 changed files with 549 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
input([0,1,1,0], [[3], [1,3], [2], [2,3], [0,2], [0,1]], [3,5,4,7]).
input([0,0,0,1,0], [[0,2,3,4], [2,3], [0,4], [0,1,2], [1,2,3,4]], [7,5,12,7,2]).
input([0,1,1,1,0,1], [[0,1,2,3,4], [0,3,4], [0,1,2,4,5], [1,2]], [10,11,11,5,10,5]).

46
2025/10/prolog/main.pl Normal file
View File

@@ -0,0 +1,46 @@
% [.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
% [...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
% [.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}
% -> 2 + 3 + 2 = 7
:- consult('example.pl').
% Keep your toggle functions
toggle(Ls, [], Ls).
toggle(Ls, [I|Is], Out) :-
nth0(I, Ls, V), flip(V, F), set_nth0(I, Ls, F, T), toggle(T, Is, Out).
flip(0, 1). flip(1, 0).
set_nth0(0, [_|Rs], V, [V|Rs]).
set_nth0(N, [R|Rs], V, [R|Ts]) :- N > 0, N1 is N-1, set_nth0(N1, Rs, V, Ts).
% Simple iterative deepening - no visited states needed
solve(L, _, [], 0) :- maplist(=(1), L).
solve(L, Wires, [W|Rest], D) :-
D > 0, member(W, Wires),
toggle(L, W, L1),
D1 is D - 1,
solve(L1, Wires, Rest, D1).
% Find minimal solution
min_solve(L, Wires, Steps) :-
between(0, 6, Depth), % Limit depth to 6
length(Steps, Depth),
solve(L, Wires, Steps, Depth).
solve_all :-
findall([L,W], input(L,W,_), Inputs),
maplist(solve_one, Inputs, Lengths),
sum_list(Lengths, Total),
format('Total: ~w~n', [Total]).
solve_one([L,W], MinLen) :-
find_min_depth(L, W, MinDepth),
MinLen = MinDepth.
find_min_depth(L, Wires, MinDepth) :-
between(0, 6, Depth),
length(Steps, Depth),
solve(L, Wires, Steps, Depth), !,
MinDepth = Depth.

40
2025/11/uiua/alt.ua Normal file
View File

@@ -0,0 +1,40 @@
# day 11
Parse ← (
⊜(∩□⊙(⊜∘⊸≠@ )°$"_: _")⊸≠@\n
∧(insert°□°⊟)⊙[]⍉⊟
)
Go‼ ← ⊙◌path(0°□⍣get|≍^1)^0
Part₁ ← ⧻Go‼"you" "out"
# Part₂ ← ⧻⊚≡◇(↧∩/↥⌕□"fft"⤙⌕□"dac"≡□)Go‼"svr" "out"
Win‼ ← (
⊃Go‼^0 "out" Go‼"svr" ^0
+⊃(×⊙/+⧻|×⊙⧻/+)∩≡◇(/↥≡/↥⌕^1)
)
Part₂ ← ↥⊃Win‼"fft" "dac" Win‼"dac" "fft"
⍤⤙≍ 5 Part₁ Parse $ aaa: you hhh
$ you: bbb ccc
$ bbb: ddd eee
$ ccc: ddd eee fff
$ ddd: ggg
$ eee: out
$ fff: out
$ ggg: out
$ hhh: ccc fff iii
$ iii: out
⍤⤙≍ 2 Part₂ Parse $ svr: aaa bbb
$ aaa: fft
$ fft: ccc
$ bbb: tty
$ tty: ccc
$ ccc: ddd eee
$ ddd: hub
$ hub: fff
$ eee: dac
$ dac: fff
$ fff: ggg hhh
$ ggg: out
$ hhh: out
⍜now(Part₂ Parse &fras "input")

36
2025/11/uiua/main.ua Normal file
View File

@@ -0,0 +1,36 @@
# day 11
Parse ← (
⊜(∩□⊙(⊜∘⊸≠@ )°$"_: _")⊸≠@\n
∧(insert°□°⊟)⊙[]⍉⊟
)
Go‼ ← ⊙◌path(0°□memoget|≍^1)^0
Part₁ ← ⧻Go‼"you" "out"
Part₂ ← ⧻⊚≡◇(↧∩/↥⌕□"fft"⤙⌕□"dac"≡□)Go‼"svr" "out"
⍤⤙≍ 5 Part₁ Parse $ aaa: you hhh
$ you: bbb ccc
$ bbb: ddd eee
$ ccc: ddd eee fff
$ ddd: ggg
$ eee: out
$ fff: out
$ ggg: out
$ hhh: ccc fff iii
$ iii: out
⍤⤙≍ 2 Part₂ Parse $ svr: aaa bbb
$ aaa: fft
$ fft: ccc
$ bbb: tty
$ tty: ccc
$ ccc: ddd eee
$ ddd: hub
$ hub: fff
$ eee: dac
$ dac: fff
$ fff: ggg hhh
$ ggg: out
$ hhh: out
⍜now(Part₂ Parse &fras "input")

BIN
2025/2/odin/main Executable file

Binary file not shown.

76
2025/2/odin/main.odin Normal file
View File

@@ -0,0 +1,76 @@
package day2
import "core:fmt"
import "core:math"
import "core:strconv"
import "core:strings"
EXAMPLE_INPUT :: "11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124"
RANGE_COUNT :: 11
Data :: [RANGE_COUNT][2]int
// split input string into an array of each range end point
parse :: proc(input: string, allocator := context.allocator) -> (data: ^Data, ok: bool) {
defer free_all(context.temp_allocator)
data = new(Data, allocator)
ranges, err := strings.split_n(input, ",", RANGE_COUNT, context.temp_allocator)
if err != .None do return nil, false
for range, i in ranges {
if i > RANGE_COUNT do break
endpoints, err := strings.split_n(range, "-", 2, context.temp_allocator)
if err != .None do return nil, false
for j := 0; j < 2; j += 1 do data[i][j] = strconv.parse_int(endpoints[j]) or_return
}
return data, true
}
part_1 :: proc(data: ^Data) -> (sum: int) {
defer free_all(context.temp_allocator)
sum = 0
for range in data {
start := range[0]
end := range[1]
start_digit_count := int(math.log10(f32(start))) + 1
end_digit_count := int(math.log10(f32(end))) + 1
if start_digit_count == end_digit_count && start_digit_count % 2 != 0 do continue
if start_digit_count % 2 != 0 {
start = end
start_digit_count = end_digit_count
}
if end_digit_count % 2 != 0 {
end = start
end_digit_count = start_digit_count
}
for j := strconv.atoi(string(start)[:start_digit_count / 2 + 1]);
j < strconv.atoi(string(end)[:end_digit_count / 2 + 1]);
j += 1 {}
start_str := make([]u8, start_digit_count, context.temp_allocator)
strconv.itoa(start_str, start)
for i := 0; i < start_digit_count; i += 1 {
if i >= start_digit_count / 2 {
start_str[i] = start_str[i % (start_digit_count / 2)]
}
}
end_str := make([]u8, end_digit_count, context.temp_allocator)
strconv.itoa(end_str, end)
for i := 0; i < end_digit_count; i += 1 {
if i >= end_digit_count / 2 {
end_str[i] = end_str[i % (end_digit_count / 2)]
}
}
fmt.println(start, end, strconv.atoi(string(start_str)), strconv.atoi(string(end_str)))
}
return
}
main :: proc() {
data, ok := parse(EXAMPLE_INPUT)
if !ok do panic("failed to parse")
defer free(data)
part_1(data)
fmt.println(data)
}

141
2025/3/odin/main.odin Normal file
View File

@@ -0,0 +1,141 @@
package day3
import "core:fmt"
import "core:mem"
import "core:os"
import "core:strings"
import "core:time"
PUZZLE_INPUT :: `
987654321111111
811111111111119
234234234234278
818181911112111
`
Data_Is_Empty_Error :: distinct struct{}
Data_Is_Ragged_Error :: distinct struct {
line: int,
}
Illegal_Token_Error :: distinct struct {
line, col: int,
token: rune,
}
Parsing_Error :: union {
mem.Allocator_Error,
Illegal_Token_Error,
Data_Is_Ragged_Error,
Data_Is_Empty_Error,
}
Grid :: struct {
data: []int,
rows, cols: int,
}
parse :: proc(input: string, allocator := context.allocator) -> (grid: Grid, err: Parsing_Error) {
context.allocator = context.temp_allocator
defer context.allocator = allocator
lines := strings.split_lines(strings.trim_space(input)) or_return
if lines[0] == "" do return {}, Data_Is_Empty_Error{}
rows := len(lines)
cols := len(strings.trim_space(lines[0]))
data := make([dynamic]int, 0, rows * cols, allocator) or_return
for line, row in lines {
clean_line := strings.trim_space(line)
if len(clean_line) != cols do return {}, Data_Is_Ragged_Error{row}
for char, col in clean_line {
digit := int(char - '0')
if digit < 0 || digit > 9 do return {}, Illegal_Token_Error{row, col, char}
append(&data, digit) or_return
}
}
return Grid{data[:], rows, cols}, nil
}
remove_digits :: proc(
row: []int,
k: int,
allocator := context.allocator,
) -> (
output: []int,
err: mem.Allocator_Error,
) {
stack := make([dynamic]int, 0, len(row) - k, allocator) or_return
dels := k
for digit in row {
for len(stack) > 0 && digit > stack[len(stack) - 1] && dels > 0 {
pop(&stack)
dels -= 1
}
append(&stack, digit) or_return
}
return stack[:], .None
}
process :: proc(row: []int, n: int) -> (output: int, err: mem.Allocator_Error) {
digits := remove_digits(row, len(row) - n) or_return
for digit in digits[:n] {
output = 10 * output + digit
}
return
}
solve :: proc(grid: Grid, n: int) -> (solution: int, err: mem.Allocator_Error) {
context.allocator = context.temp_allocator
bank_solutions := make([]int, grid.rows) or_return
for row in 0 ..< grid.rows {
row_data := grid.data[row * grid.cols:(row + 1) * grid.cols]
bank_solutions[row] = process(row_data, n) or_return
}
for bank in bank_solutions do solution += bank
return
}
part_1 :: proc(grid: Grid) -> (solution: int, err: mem.Allocator_Error) {
return solve(grid, 2)
}
part_2 :: proc(grid: Grid) -> (solution: int, err: mem.Allocator_Error) {
return solve(grid, 12)
}
main :: proc() {
time_start := time.now()
input := string(os.read_entire_file("input") or_else panic("failed to read input"))
time_read := time.since(time_start)
data, parsing_error := parse(input, context.temp_allocator)
defer free_all(context.temp_allocator)
if parsing_error != nil do fmt.panicf("failed to parse: %v\n", parsing_error)
time_parse := time.since(time_start) - time_read
fmt.println("part 1: ", part_1(data) or_else panic("part 1 failed"))
time_solve_1 := time.since(time_start) - time_read - time_parse
fmt.println("part 2: ", part_2(data) or_else panic("part 2 failed"))
time_solve_2 := time.since(time_start) - time_read - time_parse - time_solve_1
time_total := time.since(time_start)
fmt.println("performance benchmarks [ms]:")
fmt.println("total\tread\tparse\tpart 1\tpart 2")
fmt.printf(
"%.3f\t%.3f\t%.3f\t%.3f\t%.3f\n",
time.duration_milliseconds(time_total),
time.duration_milliseconds(time_read),
time.duration_milliseconds(time_parse),
time.duration_milliseconds(time_solve_1),
time.duration_milliseconds(time_solve_2),
)
}

20
2025/5/uiua/main.ua Normal file
View File

@@ -0,0 +1,20 @@
Parse ← (
∩(⊜□⊸≠@\n)°$"_\n\n_"
⊃(⍉⊟≡◇(∩⋕°$"_-_")|⋅≡◇⋕)
)
Part₁ ← ⧻⊚/↥⊞(↧≤⤙⊙≤°⊟)
Part₂ ← ⧻◴/◇⊂⍚/⍜-(⇡+1)
⍤⤙≍ 3_14 ⊃[Part₁|Part₂] Parse $ 3-5
$ 10-14
$ 16-20
$ 12-18
$
$ 1
$ 5
$ 8
$ 11
$ 17
$ 32
Part₂ Parse &fras "input.txt"

16
2025/7/odin/example Normal file
View File

@@ -0,0 +1,16 @@
.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............

101
2025/7/odin/main.odin Normal file
View File

@@ -0,0 +1,101 @@
package day7
import "core:fmt"
import "core:slice"
import "core:strings"
import "core:time"
PUZZLE_INPUT: string : #load("input")
Pos :: distinct struct {
row: int,
col: int,
}
Parsed_Data :: struct {
lines: []string,
rows, cols: int,
start: Pos,
}
not_empty_line :: proc(line: string) -> (output: bool) {
output = true
for char in line do output &&= char == '.'
return !output
}
parse :: proc(input: string) -> (output: Parsed_Data) {
lines := strings.split_lines(input)
output.start = {0, strings.index(lines[0], "S")}
output.lines = slice.filter(lines, not_empty_line)
output.rows = len(output.lines)
output.cols = len(output.lines[0])
return
}
solve_part_1 :: proc(data: Parsed_Data) -> (output: int) {
beams := make(map[Pos]bool, context.temp_allocator)
hit := make(map[Pos]bool, context.temp_allocator)
defer free_all(context.temp_allocator)
beams[data.start] = true
for line, row in data.lines {
for char, col in line {
for pos, exists in beams {
if exists && char == '^' && pos == {row - 1, col} {
beams[{row, col + 1}] = true
beams[{row, col - 1}] = true
hit[{row, col}] = true
} else if pos == {row - 1, col} {
beams[{row, col}] = true
}
}
}
}
return len(hit)
}
solve_part_2 :: proc(data: Parsed_Data) -> (output: int) {
memo := make(map[Pos]int)
defer delete(memo)
count_timelines :: proc(lines: []string, row, col: int, memo: ^map[Pos]int) -> int {
pos := Pos{row, col}
// Check memo first
if cached, exists := memo[pos]; exists {
return cached
}
// Bounds check
if row >= len(lines) || col < 0 || col >= len(lines[0]) {
memo[pos] = 1
return 1
}
char := lines[row][col]
result: int
if char == '^' {
left := count_timelines(lines, row + 1, col - 1, memo)
right := count_timelines(lines, row + 1, col + 1, memo)
result = left + right
} else {
result = count_timelines(lines, row + 1, col, memo)
}
memo[pos] = result
return result
}
return count_timelines(data.lines, data.start.row, data.start.col, &memo)
}
main :: proc() {
start := time.now()
data := parse(PUZZLE_INPUT)
fmt.println("part 1 solution:", solve_part_1(data))
fmt.println("part 2 solution:", solve_part_2(data))
total := time.since(start)
fmt.println("total time taken:", total)
}

BIN
2025/8/debug_build Executable file

Binary file not shown.

20
2025/8/example Normal file
View File

@@ -0,0 +1,20 @@
162,817,812
57,618,57
906,360,560
592,479,940
352,342,300
466,668,158
542,29,236
431,825,988
739,650,466
52,470,668
216,146,977
819,987,18
117,168,530
805,96,715
346,949,466
970,615,88
941,993,340
862,61,35
984,92,344
425,690,689

50
2025/8/main.odin Normal file
View File

@@ -0,0 +1,50 @@
package main
import "core:fmt"
import "core:slice"
import "core:strconv"
import "core:strings"
PUZZLE_INPUT: string : #load("example")
Pos :: distinct struct {
x, y, z: int,
}
parse :: proc(input: string) -> (output: []Pos) {
lines := strings.split_lines(input)
output = make([]Pos, len(lines))
digits := make([dynamic]int, context.temp_allocator)
defer free_all(context.temp_allocator)
nums: [3]int
for line, row in lines {
for num, i in strings.split(line, ",") do nums[i], _ = strconv.parse_int(num)
output[row] = Pos{nums[0], nums[1], nums[2]}
}
return
}
solve :: proc(data: []Pos) -> (output: int) {
context.allocator = context.temp_allocator
distances := make([]int, len(data) * len(data))
for p1, row in data {
for p2, col in data {
d := Pos{p1.x - p2.x, p1.y - p2.y, p1.z - p2.z}
distance := d.x * d.x + d.y * d.y + d.z * d.z
distances[row * len(data) + col] = distance == 0 ? 1e9 : distance // TODO: triangle
}
}
fmt.println(distances)
shortest := make([]int, len(data))
for i in 0 ..< len(data) {
row := distances[i * len(data):(i + 1) * len(data)]
shortest[i] = slice.min_index(row)
}
fmt.println(shortest)
return
}
main :: proc() {
fmt.println(solve(parse(PUZZLE_INPUT)))
}