add other days
This commit is contained in:
parent
b4877b5cac
commit
1fc6832960
10 changed files with 482 additions and 3 deletions
12
day08.scm
12
day08.scm
|
@ -1,7 +1,9 @@
|
||||||
(import (chicken io))
|
(import (chicken io))
|
||||||
(import (chicken string))
|
(import (chicken string))
|
||||||
(import (chicken format))
|
(import (chicken format))
|
||||||
|
(import srfi-113)
|
||||||
(import srfi-1)
|
(import srfi-1)
|
||||||
|
(import srfi-128)
|
||||||
|
|
||||||
(define (summap a b) (foldl + 0 (map a b)))
|
(define (summap a b) (foldl + 0 (map a b)))
|
||||||
|
|
||||||
|
@ -11,6 +13,7 @@
|
||||||
(let ((halves (string-split line "|")))
|
(let ((halves (string-split line "|")))
|
||||||
(map string-split halves)))
|
(map string-split halves)))
|
||||||
|
|
||||||
|
;; PART 1
|
||||||
(define (is-1478 pattern)
|
(define (is-1478 pattern)
|
||||||
(let ((len (string-length pattern)))
|
(let ((len (string-length pattern)))
|
||||||
(not (or (eq? len 5) (eq? len 6)))))
|
(not (or (eq? len 5) (eq? len 6)))))
|
||||||
|
@ -19,6 +22,9 @@
|
||||||
(let-values (((patterns output) (apply values parsed)))
|
(let-values (((patterns output) (apply values parsed)))
|
||||||
(count is-1478 output)))
|
(count is-1478 output)))
|
||||||
|
|
||||||
(let* ((lines (read-lines))
|
(define lines (read-lines))
|
||||||
(separated (map split-line lines)))
|
(define parsed-lines (map split-line lines))
|
||||||
(displayln (summap count-1478 separated)))
|
|
||||||
|
(let ((part1 (summap count-1478 parsed-lines)))
|
||||||
|
(display "part1: ")
|
||||||
|
(displayln part1))
|
||||||
|
|
59
day08_2.py
Normal file
59
day08_2.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import fileinput
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
lines = list(fileinput.input())
|
||||||
|
|
||||||
|
t = time.time_ns()
|
||||||
|
|
||||||
|
part2 = 0
|
||||||
|
for line in lines:
|
||||||
|
poss = {}
|
||||||
|
|
||||||
|
digits, output = (l.split() for l in str(line).split(" | "))
|
||||||
|
|
||||||
|
one = set(next(digit for digit in digits if len(digit) == 2))
|
||||||
|
four = set(next(digit for digit in digits if len(digit) == 4))
|
||||||
|
|
||||||
|
for digit in digits:
|
||||||
|
digit = "".join(sorted(digit))
|
||||||
|
digit_set = set(digit)
|
||||||
|
|
||||||
|
overlap_one = len(digit_set & one)
|
||||||
|
overlap_four = len(digit_set & four)
|
||||||
|
|
||||||
|
if len(digit) == 2: # 1
|
||||||
|
poss[digit] = 1
|
||||||
|
elif len(digit) == 3: # 7
|
||||||
|
poss[digit] = 7
|
||||||
|
elif len(digit) == 4: # 4
|
||||||
|
poss[digit] = 4
|
||||||
|
elif len(digit) == 5: # 2, 3, 5, 6
|
||||||
|
if overlap_four == 2:
|
||||||
|
poss[digit] = 2
|
||||||
|
elif overlap_one == 1:
|
||||||
|
poss[digit] = 5
|
||||||
|
else:
|
||||||
|
poss[digit] = 3
|
||||||
|
elif len(digit) == 6: # 0, 6, 9
|
||||||
|
if overlap_four == 4:
|
||||||
|
poss[digit] = 9
|
||||||
|
elif overlap_one == 2:
|
||||||
|
poss[digit] = 0
|
||||||
|
else:
|
||||||
|
poss[digit] = 6
|
||||||
|
elif len(digit) == 7:
|
||||||
|
poss[digit] = 8
|
||||||
|
|
||||||
|
result = 0
|
||||||
|
for digit in output:
|
||||||
|
digit = "".join(sorted(digit))
|
||||||
|
result = (result * 10) + poss[digit]
|
||||||
|
|
||||||
|
part2 += result
|
||||||
|
|
||||||
|
t2 = time.time_ns()
|
||||||
|
print(part2)
|
||||||
|
print(t2 - t, "ns")
|
||||||
|
print((t2 - t) // 1000, "µs")
|
45
day09.py
Normal file
45
day09.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import fileinput
|
||||||
|
import heapq
|
||||||
|
from typing import Generator, Tuple
|
||||||
|
|
||||||
|
heightmap = []
|
||||||
|
for line in fileinput.input():
|
||||||
|
heightmap.append([int(c) for c in line.strip()])
|
||||||
|
|
||||||
|
def neighborhood(x: int, y: int) -> Generator[Tuple[int, int], None, None]:
|
||||||
|
global heightmap
|
||||||
|
if x > 0:
|
||||||
|
yield (x - 1, y)
|
||||||
|
if x < len(heightmap[0]) - 1:
|
||||||
|
yield (x + 1, y)
|
||||||
|
if y > 0:
|
||||||
|
yield (x, y - 1)
|
||||||
|
if y < len(heightmap) - 1:
|
||||||
|
yield (x, y + 1)
|
||||||
|
|
||||||
|
lowpoints = list()
|
||||||
|
for y, row in enumerate(heightmap):
|
||||||
|
for x, height in enumerate(row):
|
||||||
|
if height < min(heightmap[y_][x_] for x_, y_ in neighborhood(x, y)):
|
||||||
|
lowpoints.append((x, y))
|
||||||
|
|
||||||
|
print("part 1:", sum(1 + heightmap[y][x] for x, y in lowpoints))
|
||||||
|
|
||||||
|
basins = []
|
||||||
|
for lowpoint in lowpoints:
|
||||||
|
stack = [lowpoint]
|
||||||
|
visited = set()
|
||||||
|
while stack:
|
||||||
|
x, y = stack.pop()
|
||||||
|
if (x, y) in visited or heightmap[y][x] == 9:
|
||||||
|
continue
|
||||||
|
visited.add((x, y))
|
||||||
|
|
||||||
|
for neighbor in neighborhood(x, y):
|
||||||
|
stack.append(neighbor)
|
||||||
|
|
||||||
|
heapq.heappush(basins, len(visited))
|
||||||
|
|
||||||
|
a, b, c, *_ = heapq.nlargest(3, basins)
|
||||||
|
print("part 2:", a * b * c)
|
41
day10.py
Normal file
41
day10.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import fileinput
|
||||||
|
from collections import deque
|
||||||
|
from timeit import timeit
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
lines = list(fileinput.input())
|
||||||
|
|
||||||
|
opposites = {"[": "]", "(": ")", "{": "}", "<": ">"}
|
||||||
|
part1_points = {")": 3, "]": 57, "}": 1197, ">": 25137}
|
||||||
|
part2_points = {"(": 1, "[": 2, "{": 3, "<": 4}
|
||||||
|
|
||||||
|
def main() -> Tuple[int, int]:
|
||||||
|
part1 = 0
|
||||||
|
part2_scores = []
|
||||||
|
|
||||||
|
for line_ in lines:
|
||||||
|
line = str(line_).strip()
|
||||||
|
stack = deque()
|
||||||
|
for c in line:
|
||||||
|
if c in "[({<":
|
||||||
|
stack.appendleft(c)
|
||||||
|
elif opposites[stack[0]] != c:
|
||||||
|
part1 += part1_points[c]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
stack.popleft()
|
||||||
|
else:
|
||||||
|
score = 0
|
||||||
|
for c in stack:
|
||||||
|
score = score * 5 + part2_points[c]
|
||||||
|
part2_scores.append(score)
|
||||||
|
|
||||||
|
part2_scores.sort()
|
||||||
|
part2 = part2_scores[len(part2_scores) // 2]
|
||||||
|
|
||||||
|
return (part1, part2)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(main())
|
||||||
|
print(f"{timeit(main, number=1000):.3f} ms")
|
69
day11.py
Normal file
69
day11.py
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import fileinput
|
||||||
|
from pprint import pprint
|
||||||
|
from typing import List, Tuple, Any, Set, Generator
|
||||||
|
from timeit import timeit
|
||||||
|
|
||||||
|
|
||||||
|
lines = list(fileinput.input())
|
||||||
|
|
||||||
|
|
||||||
|
def neighborhood(
|
||||||
|
m: List[List[int]], x: int, y: int
|
||||||
|
) -> Generator[Tuple[int, int], None, None]:
|
||||||
|
h = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1))
|
||||||
|
yield from (
|
||||||
|
(x_ + x, y_ + y)
|
||||||
|
for x_, y_ in h
|
||||||
|
if 0 <= x_ + x < len(m[0]) and 0 <= y_ + y < len(m)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def step(field):
|
||||||
|
for y in range(len(field)):
|
||||||
|
for x in range(len(field[y])):
|
||||||
|
field[y][x] += 1
|
||||||
|
|
||||||
|
flash_queue = [
|
||||||
|
(x, y)
|
||||||
|
for y in range(len(field))
|
||||||
|
for x in range(len(field[y]))
|
||||||
|
if field[y][x] > 9
|
||||||
|
]
|
||||||
|
|
||||||
|
flashed = set()
|
||||||
|
while flash_queue:
|
||||||
|
x, y = flash_queue.pop()
|
||||||
|
if (x, y) in flashed:
|
||||||
|
continue
|
||||||
|
flashed.add((x, y))
|
||||||
|
|
||||||
|
for x_, y_ in neighborhood(field, x, y):
|
||||||
|
field[y_][x_] += 1
|
||||||
|
if field[y_][x_] > 9 and (x_, y_) not in flashed:
|
||||||
|
flash_queue.append((x_, y_))
|
||||||
|
|
||||||
|
for x, y in flashed:
|
||||||
|
field[y][x] = 0
|
||||||
|
|
||||||
|
return len(flashed)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> Tuple[int, int]:
|
||||||
|
field = [[int(c) for c in line.strip()] for line in lines]
|
||||||
|
len_ = len(field) * len(field[0])
|
||||||
|
|
||||||
|
part1 = 0
|
||||||
|
part2 = 0
|
||||||
|
for part2 in range(100):
|
||||||
|
part1 += step(field)
|
||||||
|
|
||||||
|
while step(field) != len_ and sum(sum(row) for row in field) != 0:
|
||||||
|
part2 += 1
|
||||||
|
|
||||||
|
return part1, part2 + 2
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(main())
|
||||||
|
print(f"{timeit(main, number=100) * 10:.3f} ms")
|
64
day12.py
Normal file
64
day12.py
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import fileinput
|
||||||
|
from timeit import timeit
|
||||||
|
from typing import FrozenSet, List, Optional, Tuple, Union
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
lines = list(fileinput.input())
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# parse
|
||||||
|
graph = defaultdict(list)
|
||||||
|
for line in lines:
|
||||||
|
fro, to = str(line).strip().split("-")
|
||||||
|
graph[fro].append(to)
|
||||||
|
graph[to].append(fro)
|
||||||
|
|
||||||
|
# part 1
|
||||||
|
stack: List[Tuple[str, FrozenSet[str]]] = [("start", frozenset())]
|
||||||
|
part1 = 0
|
||||||
|
while stack:
|
||||||
|
pos, visited = stack.pop()
|
||||||
|
if pos.islower() and pos in visited:
|
||||||
|
continue
|
||||||
|
visited = visited | {pos}
|
||||||
|
|
||||||
|
if pos == "end":
|
||||||
|
part1 += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
for next_pos in graph[pos]:
|
||||||
|
stack.append((next_pos, visited))
|
||||||
|
|
||||||
|
stack2: List[Tuple[str, FrozenSet[str], Optional[str]]] = [
|
||||||
|
("start", frozenset(), None)
|
||||||
|
]
|
||||||
|
part2 = 0
|
||||||
|
while stack2:
|
||||||
|
pos, visited, doubled = stack2.pop()
|
||||||
|
|
||||||
|
if pos.islower() and pos in visited:
|
||||||
|
if doubled is None:
|
||||||
|
stack2.append((pos, visited, pos))
|
||||||
|
continue
|
||||||
|
if doubled != pos:
|
||||||
|
continue
|
||||||
|
doubled = ""
|
||||||
|
|
||||||
|
visited = visited | {pos}
|
||||||
|
|
||||||
|
if pos == "end":
|
||||||
|
part2 += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
for next_pos in graph[pos]:
|
||||||
|
if next_pos != "start":
|
||||||
|
stack2.append((next_pos, visited, doubled))
|
||||||
|
|
||||||
|
return part1, part2
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(main())
|
||||||
|
print(f"{timeit(main, number=20) * 50:.3f} ms")
|
62
day13.py
Normal file
62
day13.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import fileinput
|
||||||
|
from pprint import pprint
|
||||||
|
from timeit import timeit
|
||||||
|
|
||||||
|
lines = list(fileinput.input())
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
h = 0
|
||||||
|
w = 0
|
||||||
|
|
||||||
|
dots = set()
|
||||||
|
folds = []
|
||||||
|
part1 = 0
|
||||||
|
for line in lines:
|
||||||
|
line = str(line)
|
||||||
|
if line[0].isdigit():
|
||||||
|
x, y = (int(n) for n in line.split(","))
|
||||||
|
h = max(x + 1, h)
|
||||||
|
w = max(y + 1, w)
|
||||||
|
dots.add((x, y))
|
||||||
|
elif line[0] == "f":
|
||||||
|
c, n = line.split("=")
|
||||||
|
folds.append((c[-1], int(n)))
|
||||||
|
|
||||||
|
for dir, pos in folds:
|
||||||
|
folded = set()
|
||||||
|
if dir == "y":
|
||||||
|
for x, y in dots:
|
||||||
|
if y > pos:
|
||||||
|
y2 = 2 * pos - y
|
||||||
|
folded.add((x, y2))
|
||||||
|
else:
|
||||||
|
folded.add((x, y))
|
||||||
|
else:
|
||||||
|
for x, y in dots:
|
||||||
|
if x > pos:
|
||||||
|
x2 = 2 * pos - x
|
||||||
|
folded.add((x2, y))
|
||||||
|
else:
|
||||||
|
folded.add((x, y))
|
||||||
|
dots = folded
|
||||||
|
|
||||||
|
if part1 == 0:
|
||||||
|
part1 = len(dots)
|
||||||
|
|
||||||
|
xs, ys = zip(*dots)
|
||||||
|
sheet = [[" "] * (max(xs) + 1) for _ in range(max(ys) + 1)]
|
||||||
|
for x, y in dots:
|
||||||
|
sheet[y][x] = "#"
|
||||||
|
|
||||||
|
return part1, ["".join(row).replace("#", "█") for row in sheet]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
a, b = main()
|
||||||
|
print("part 1:", a)
|
||||||
|
print("part 2:")
|
||||||
|
print("\n".join(b))
|
||||||
|
|
||||||
|
print(f"{timeit(main, number=1000):.3f} ms")
|
25
rust/Cargo.lock
generated
Normal file
25
rust/Cargo.lock
generated
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aoc_rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"fxhash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fxhash"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
9
rust/Cargo.toml
Normal file
9
rust/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "aoc_rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
fxhash = "0.2.1"
|
99
rust/src/main.rs
Normal file
99
rust/src/main.rs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
use std::io::BufRead;
|
||||||
|
use std::time::Instant;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut graph = [0usize; 32];
|
||||||
|
let stdin = std::io::stdin();
|
||||||
|
let lines = stdin.lock().lines();
|
||||||
|
|
||||||
|
let mut nodes = HashMap::new();
|
||||||
|
let mut is_small = 0u32;
|
||||||
|
|
||||||
|
let instant = Instant::now();
|
||||||
|
for line in lines {
|
||||||
|
let line = line.unwrap();
|
||||||
|
let split = line.split("-").collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let next_a = nodes.len();
|
||||||
|
let a = *nodes.entry(split[0].to_string()).or_insert(next_a);
|
||||||
|
|
||||||
|
let next_b = nodes.len();
|
||||||
|
let b = *nodes.entry(split[1].to_string()).or_insert(next_b);
|
||||||
|
|
||||||
|
graph[a] |= 1 << b;
|
||||||
|
graph[b] |= 1 << a;
|
||||||
|
|
||||||
|
if split[0].find(char::is_uppercase).is_none() {
|
||||||
|
is_small |= 1 << a;
|
||||||
|
}
|
||||||
|
if split[1].find(char::is_uppercase).is_none() {
|
||||||
|
is_small |= 1 << b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let start = nodes["start"];
|
||||||
|
let end = nodes["end"];
|
||||||
|
|
||||||
|
let mut stack = vec![(start, 0u32)];
|
||||||
|
let mut part1 = 0;
|
||||||
|
while stack.len() != 0 {
|
||||||
|
let (pos, visited) = stack.pop().unwrap();
|
||||||
|
let pos_mask = 1 << pos;
|
||||||
|
if (is_small & visited) & pos_mask != 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if pos == end {
|
||||||
|
part1 += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut next = graph[pos];
|
||||||
|
while next != 0 {
|
||||||
|
let next_pos = next.trailing_zeros();
|
||||||
|
stack.push((next_pos as usize, visited | pos_mask));
|
||||||
|
next &= !(1 << next_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
|
||||||
|
enum Doubled {
|
||||||
|
None,
|
||||||
|
Done,
|
||||||
|
Some(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stack = vec![(start, 0u32, Doubled::None)];
|
||||||
|
let mut part2 = 0;
|
||||||
|
while stack.len() != 0 {
|
||||||
|
let (pos, visited, mut doubled) = stack.pop().unwrap();
|
||||||
|
let pos_mask = 1 << pos;
|
||||||
|
if (is_small & visited) & pos_mask != 0 {
|
||||||
|
if doubled == Doubled::None {
|
||||||
|
stack.push((pos, visited, Doubled::Some(pos)));
|
||||||
|
continue;
|
||||||
|
} else if doubled != Doubled::Some(pos) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
doubled = Doubled::Done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pos == end {
|
||||||
|
part2 += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut next = graph[pos] & !(1 << start);
|
||||||
|
while next != 0 {
|
||||||
|
let next_pos = next.trailing_zeros();
|
||||||
|
stack.push((next_pos as usize, visited | pos_mask, doubled));
|
||||||
|
next &= !(1 << next_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let elapsed = instant.elapsed();
|
||||||
|
dbg!(part1, part2, elapsed);
|
||||||
|
}
|
Loading…
Reference in a new issue