Compare commits

..

12 Commits

Author SHA1 Message Date
frero 16684fea02 2025/2: parallelize nushell part 1 2026-04-03 22:52:04 +02:00
frero 87457e0a92 2025/2: nushell part 1 2026-04-03 22:48:41 +02:00
frero cf64d5950e merge gaming pc solutions 2026-01-11 15:59:22 +01:00
frero e5a214187a wip 2026-01-11 15:57:03 +01:00
frero 9d8676a109 improve 2016/1/1(uiua) 2025-09-24 09:41:13 +02:00
frero 3b5c6ae52d solve 2016/2 part 1 in uiua 2025-09-24 02:10:10 +02:00
frero 850cfecc67 solve 2016/1 part 2 in uiua 2025-09-24 00:24:41 +02:00
frero d4267d6f51 solve 2016/1 part 1 in uiua 2025-09-24 00:24:30 +02:00
frero b4013642be wip 2025-09-23 00:52:49 +02:00
frero 6225b525d1 grid 2025-09-23 00:52:49 +02:00
frero f78d3083ff 2024/10/odin: solve part 1 2025-09-23 00:52:49 +02:00
frero 7db243be05 2024/9/odin: solve part 1 2025-09-23 00:52:49 +02:00
25 changed files with 974 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
input.txt
input
+37
View File
@@ -0,0 +1,37 @@
# aoc 2016/1
&fras $ input.txt
°/$"_, _" ⍜⇌↘₁
≡◇⊃[⍥¯⊙i ⨂"LR"⊢|⋕↘1] # pre-process
\(⊂⊢⊙⊣⊸⍜∩⊢×) # directions at each token
⬚0/(+⊙/×) # move in direction
+∩⌵°ℂ
$Part₁
# the idea is to represent our position
# as a complex number (2d vector). rotate by
# 90 or -90 degrees when you encounter L or R
# by multiplying by i or -i on the direction
# vector.
# this can be done by folding with the initial
# values i (direction) and 0 (position), pattern-
# matching the next token on L or R and recognizing
# them by ⍩.
# once the direction vector has been rotated
# accordingly, ⍥\+⋕ to add the direction unit vector
# to the position vector n times for token Ln or Rn.
#
# we can see many awesome pieces of functional and
# array oriented code!
&fras $ input.txt
°/$"_, _" ⍜⇌↘₁
∧◇(⍥(⊙⊂⟜⊣\+)⋕ ⍣(
⍩⊙⍜⊢(×i) °(⊂@L)
| ⍩⊙⍜⊢(ׯi) °(⊂@R))
)⊙i_0⊙[]
⌵+°ℂ ⊡⊸(⊢⍖=1⧆)⇌ ◌
$Part₂
# for this part, we only need to keep track of
# each intermediate step (all our positions).
# this by modifying the ⍥-loop to keep a log.
# then we can find the first reoccurring position
# using the new ⧆.
+16
View File
@@ -0,0 +1,16 @@
# aoc 2016/2
&fras "input.txt"
⍜⇌(▽⊸(>0\+≠@\n)) # world's most complicated right-trim
# parse each letter of the puzzle input.
# update position vector.
⊂∧(
⍣(⍩(-i) ◌°.@U
| ⍩(+i) ◌°.@D
| ⍩(-1) ◌°.@L
| ⍩(+1) ◌°.@R
| ⍩(⟜⊂) ◌°.@\n)
⍜°ℂ∩(↥¯1↧1) # clamp vector
)⊙0⊙[]
⍉⊟°ℂ +1 1 # translate
⌝⊥10 ⊡⊙(+1°△3_3) # grab code
$Part₁
+1
View File
@@ -0,0 +1 @@
use flake
+8
View File
@@ -0,0 +1,8 @@
89010123
78121874
87430965
96549874
45678903
32019012
01329801
10456732
+27
View File
@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1755186698,
"narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
+24
View File
@@ -0,0 +1,24 @@
{
description = "advent of code 2024 day 10 in odin";
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
outputs =
{ self, nixpkgs, ... }:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
};
in
{
devShells.${system}.default = pkgs.mkShell {
buildInputs = with pkgs; [
odin
];
shellHook = ''
echo "Entering odin devshell..."
'';
};
};
}
+110
View File
@@ -0,0 +1,110 @@
package aoc2024day10
import "core:fmt"
import "core:os"
import "core:slice"
import "core:strconv"
import "core:strings"
import "core:unicode"
EXAMPLE_INPUT_PATH :: "example.txt"
PUZZLE_INPUT_PATH :: "input.txt"
Grid :: struct($T: typeid) {
data: []T,
width: int,
height: int,
}
gpos :: proc(i: int) -> (row: int, col: int) {
return i / g.width, i % g.width
}
gidx :: proc(row, col: int) -> (i: int) {
return row * g.width + col
}
gidx_safe :: proc(row, col: int) -> (m: Maybe(int)) {
if !(0 <= row && row <= g.height && 0 <= col && col <= g.width) do return nil
return gidx(row, col)
}
gget :: proc(row, col: int) -> (value: int) {
return g.data[gidx(row, col)]
}
gget_safe :: proc(row, col: int) -> (mvalue: Maybe(any)) {
if m := gidx_safe(row, col); m == nil do return nil
else do return g.data[m.(int)]
}
gset :: proc(row, col: int, value: $T) {
g.data[gidx(row, col)] = value
}
// TODO: use enumerated array
gadj_idx :: proc(
row, col: int,
) -> (
north: Maybe(int),
east: Maybe(int),
south: Maybe(int),
west: Maybe(int),
) {
north = gidx_safe(row - 1, col)
east = gidx_safe(row, col + 1)
south = gidx_safe(row + 1, col)
west = gidx_safe(row, col - 1)
return
}
g: Grid(int)
main :: proc() {
path := len(os.args) == 2 ? os.args[1] : EXAMPLE_INPUT_PATH
input := string(
os.read_entire_file_from_filename(path) or_else panic("failed to read input file"),
)
g = parse(input)
fmt.println("part 1:", solve1())
}
parse :: proc(input: string) -> Grid(int) {
data: [dynamic]int
width, height := 0, 0
for line in strings.split_lines(strings.trim_right_space(input)) {
if width == 0 do width = len(line)
for r in line {
digit := strconv._digit_value(r)
append(&data, digit)
}
height += 1
}
return {data[:], width, height}
}
solve1 :: proc() -> (res: int) {
inner :: proc(row, col, cur: int) -> (score: int) {
n, e, s, w := gadj_idx(row, col)
dir: [4]Maybe(int) = {n, e, s, w}
directions: []int = slice.mapper(
slice.filter(dir[:], proc(m: Maybe(int)) -> bool {return m != nil}),
proc(m: Maybe(int)) -> int {return m.(int)},
)
heights: []int = slice.mapper(directions, proc(i: int) -> int {return gget(gpos(i))})
fmt.println(dir, directions, heights)
cache[gidx(row, col)] = score
return
}
@(static) cache: map[int]int
return inner(0, 2, 0)
}
Test :: struct {
hello: int,
method: proc(_: int) -> int,
}
+1
View File
@@ -0,0 +1 @@
2333133121414131402
BIN
View File
Binary file not shown.
+173
View File
@@ -0,0 +1,173 @@
package aoc2024day9
import "core:container/queue"
import "core:fmt"
import "core:os"
import "core:slice"
import "core:strconv"
import "core:unicode"
PUZZLE_INPUT_PATH :: "input.txt"
EXAMPLE_INPUT_PATH :: "example.txt"
main :: proc() {
path := len(os.args) == 2 ? os.args[1] : PUZZLE_INPUT_PATH
input := string(os.read_entire_file_from_filename(path) or_else panic("damn"))
fmt.println("part 1:", part1(input))
fmt.println("part 2:", part2(input))
}
part2 :: proc(input: string) -> int {
mem: [dynamic]int
defer delete(mem)
free: map[int]int // start_index -> free_space_interval_delta
defer delete(free)
filesizes: map[int]int // fileid -> block_count
defer delete(filesizes)
next_fileid := 0
memptr := 0
for r, i in input {
if !unicode.is_digit(r) {continue}
d := strconv._digit_value(r)
if i % 2 == 0 { // files
for j := 0; j < d; j += 1 {
append(&mem, next_fileid)
memptr += 1
filesizes[next_fileid] = j + 1
}
next_fileid += 1
} else { // free
for j := 0; j < d; j += 1 {
append(&mem, -1)
free[memptr - j] = j + 1
memptr += 1
}
}
}
// fmt.println(free)
// fmt.println(filesizes)
used: [dynamic]int
defer delete(used)
#reverse for fid, i in mem {
if fid < 0 || slice.contains(used[:], fid) {continue}
append(&used, fid)
move := false
size := filesizes[fid]
for f, j in mem {
if f >= 0 || !(j in free) {continue} // TODO: scary slow
t := free[j]
if t >= size {
move = true
for k in 0 ..< size {
mem[j + k] = fid
}
free[j + size] = t - size
break
}
}
if move {
for k in 0 ..< size {
mem[i - k] = -2
}
}
for m in mem {
if m < 0 {
fmt.print("x")
} else {
fmt.print(m)
}
}
fmt.println()
}
// for fid := next_fileid - 1; fid > 0; fid -= 1 {
// size := filesizes[fid]
// memptr -= size
// }
// keys := slice.map_keys(free) or_else panic("damn2")
// slice.sort(keys)
// ptr := 0
// #reverse for fileid, i in mem {
// if fileid < 0 {continue}
// cur := mem[memptr - 1]
// target := filesizes[cur]
// for start, j in keys[ptr:] {
// delta := free[start]
// if delta < target {continue}
// end := delta + start
// }
// }
// #reverse for fileid, i in mem {
// f := queue.peek_front(&free)^
// if queue.len(free) <= 0 || f >= len(mem) {break}
// if fileid >= 0 {
// mem[f] = fileid
// queue.pop_front(&free)
// }
// pop(&mem)
// }
sum := 0
for fileid, i in mem {
if fileid < 0 {continue}
sum += fileid * i
}
return sum
}
part1 :: proc(input: string) -> int {
mem: [dynamic]int
defer delete(mem)
free: queue.Queue(int)
queue.init(&free)
defer queue.destroy(&free)
next_fileid := 0
memptr := 0
for r, i in input {
if !unicode.is_digit(r) {continue}
d := strconv._digit_value(r)
if i % 2 == 0 { // files
for j := 0; j < d; j += 1 {
append(&mem, next_fileid)
memptr += 1
}
next_fileid += 1
} else { // free
for j := 0; j < d; j += 1 {
append(&mem, -1)
queue.push_back(&free, memptr)
memptr += 1
}
}
}
#reverse for fileid, i in mem {
f := queue.peek_front(&free)^
if queue.len(free) <= 0 || f >= len(mem) {break}
if fileid >= 0 {
mem[f] = fileid
queue.pop_front(&free)
}
pop(&mem)
}
sum := 0
for fileid, i in mem {
if fileid < 0 {continue}
sum += fileid * i
// fmt.println(fileid, i)
}
return sum
}
+3
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
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
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
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")
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env nu
def part-1 [parsed] {
$parsed
| par-each {
|row| where {|x| into string
| split chars
| take (($in | length) // 2)
| ($in | str join) + ($in | str join)
| try {into int} catch {0}
| $in == $x
}
} | flatten | math sum
}
let input = open input
let parsed = $input
| str trim
| lines
| str join
| split row ','
| split column '-'
| rename l u
| into int l u
| each {|row| $row.l..$row.u}
timeit {print (part-1 $parsed)}
BIN
View File
Binary file not shown.
+76
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
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
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
View File
@@ -0,0 +1,16 @@
.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
+101
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
View File
Binary file not shown.
+20
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
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)))
}