mirror of
https://github.com/fredrikr79/advent_of_code.git
synced 2026-04-26 03:26:10 +02:00
Compare commits
1 Commits
main
..
f495d64ba8
| Author | SHA1 | Date | |
|---|---|---|---|
| f495d64ba8 |
@@ -1,2 +0,0 @@
|
|||||||
input.txt
|
|
||||||
input
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# 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 ⧆.
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# 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 +0,0 @@
|
|||||||
use flake
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
89010123
|
|
||||||
78121874
|
|
||||||
87430965
|
|
||||||
96549874
|
|
||||||
45678903
|
|
||||||
32019012
|
|
||||||
01329801
|
|
||||||
10456732
|
|
||||||
Generated
-27
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
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..."
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
2333133121414131402
|
|
||||||
Binary file not shown.
@@ -1,173 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
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]).
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
% [.##.] (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.
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
# 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")
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# 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")
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#!/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)}
|
|
||||||
Binary file not shown.
@@ -1,76 +0,0 @@
|
|||||||
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)
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
.......S.......
|
|
||||||
...............
|
|
||||||
.......^.......
|
|
||||||
...............
|
|
||||||
......^.^......
|
|
||||||
...............
|
|
||||||
.....^.^.^.....
|
|
||||||
...............
|
|
||||||
....^.^...^....
|
|
||||||
...............
|
|
||||||
...^.^...^.^...
|
|
||||||
...............
|
|
||||||
..^...^.....^..
|
|
||||||
...............
|
|
||||||
.^.^.^.^.^...^.
|
|
||||||
...............
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -1,20 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
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)))
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user