From 86bac31392a76da84817eec020d2b84d099b3cc1 Mon Sep 17 00:00:00 2001 From: mhsn Date: Wed, 18 Mar 2026 21:48:13 +0000 Subject: add other challenges support --- 2024/01/python.py | 14 - 2024/01/raku.raku | 5 - 2024/01/rust/Cargo.lock | 7 - 2024/01/rust/Cargo.toml | 6 - 2024/01/rust/src/main.rs | 31 -- 2024/02/python.py | 24 -- 2024/02/raku.raku | 9 - 2024/02/rust/Cargo.lock | 7 - 2024/02/rust/Cargo.toml | 6 - 2024/02/rust/src/main.rs | 33 --- 2024/03/python.py | 23 -- 2024/03/raku.raku | 17 -- 2024/03/rust/Cargo.lock | 7 - 2024/03/rust/Cargo.toml | 4 - 2024/03/rust/src/main.rs | 68 ----- 2024/04/python.py | 29 -- 2024/04/raku.raku | 8 - 2024/04/rust/Cargo.lock | 7 - 2024/04/rust/Cargo.toml | 4 - 2024/04/rust/src/main.rs | 82 ------ 2024/05/python.py | 30 -- 2024/05/raku.raku | 10 - 2024/05/rust/Cargo.lock | 7 - 2024/05/rust/Cargo.toml | 6 - 2024/05/rust/src/main.rs | 42 --- 2024/06/python.py | 57 ---- 2024/06/rust/Cargo.lock | 7 - 2024/06/rust/Cargo.toml | 4 - 2024/06/rust/src/main.rs | 105 ------- 2024/07/python.py | 37 --- 2024/07/rust/Cargo.lock | 7 - 2024/07/rust/Cargo.toml | 6 - 2024/07/rust/src/main.rs | 71 ----- 2024/08/python.py | 51 ---- 2024/08/rust/Cargo.lock | 7 - 2024/08/rust/Cargo.toml | 6 - 2024/08/rust/src/main.rs | 74 ----- 2024/09/python.py | 62 ---- 2024/09/rust/Cargo.lock | 7 - 2024/09/rust/Cargo.toml | 6 - 2024/09/rust/src/main.rs | 100 ------- 2024/10/python.py | 43 --- 2024/10/rust/Cargo.lock | 7 - 2024/10/rust/Cargo.toml | 6 - 2024/10/rust/src/main.rs | 52 ---- 2024/11/python.py | 30 -- 2024/11/rust/Cargo.lock | 7 - 2024/11/rust/Cargo.toml | 6 - 2024/11/rust/src/main.rs | 43 --- 2024/12/python.py | 49 ---- 2024/13/python.py | 40 --- 2024/14/python.py | 64 ---- 2024/15/python.py | 83 ------ 2024/16/python.py | 31 -- 2024/17/python.py | 68 ----- 2024/18/python.py | 47 --- 2024/19/python.py | 42 --- 2024/20/python.py | 40 --- 2024/21/python.py | 42 --- 2024/22/python.py | 59 ---- 2025/01/c.c | 19 -- 2025/01/python.py | 15 - 2025/01/rust/Cargo.lock | 89 ------ 2025/01/rust/Cargo.toml | 7 - 2025/01/rust/src/main.rs | 25 -- 2025/02/python.py | 33 --- 2025/03/python.py | 21 -- 2025/03/rust/Cargo.lock | 7 - 2025/03/rust/Cargo.toml | 6 - 2025/03/rust/src/main.rs | 42 --- 2025/04/python.py | 36 --- 2025/04/rust/Cargo.lock | 7 - 2025/04/rust/Cargo.toml | 6 - 2025/04/rust/src/main.rs | 66 ----- 2025/05/python.py | 39 --- 2025/05/rust/Cargo.lock | 7 - 2025/05/rust/Cargo.toml | 6 - 2025/05/rust/src/main.rs | 55 ---- 2025/06/python.py | 18 -- 2025/07/python.py | 31 -- 2025/08/python.py | 29 -- 2025/09/python.py | 13 - 2025/09/rust/Cargo.lock | 7 - 2025/09/rust/Cargo.toml | 6 - 2025/09/rust/src/main.rs | 113 -------- 2025/10/rust/Cargo.lock | 155 ---------- 2025/10/rust/Cargo.toml | 8 - 2025/10/rust/src/main.rs | 68 ----- 2025/11/rust/Cargo.lock | 7 - 2025/11/rust/Cargo.toml | 6 - 2025/11/rust/src/main.rs | 84 ------ 2025/12/python.py | 21 -- LICENSE | 674 ------------------------------------------- aoc/2024/01/python.py | 14 + aoc/2024/01/raku.raku | 5 + aoc/2024/01/rust/Cargo.lock | 7 + aoc/2024/01/rust/Cargo.toml | 6 + aoc/2024/01/rust/src/main.rs | 31 ++ aoc/2024/02/python.py | 24 ++ aoc/2024/02/raku.raku | 9 + aoc/2024/02/rust/Cargo.lock | 7 + aoc/2024/02/rust/Cargo.toml | 6 + aoc/2024/02/rust/src/main.rs | 33 +++ aoc/2024/03/python.py | 23 ++ aoc/2024/03/raku.raku | 17 ++ aoc/2024/03/rust/Cargo.lock | 7 + aoc/2024/03/rust/Cargo.toml | 4 + aoc/2024/03/rust/src/main.rs | 68 +++++ aoc/2024/04/python.py | 29 ++ aoc/2024/04/raku.raku | 8 + aoc/2024/04/rust/Cargo.lock | 7 + aoc/2024/04/rust/Cargo.toml | 4 + aoc/2024/04/rust/src/main.rs | 82 ++++++ aoc/2024/05/python.py | 30 ++ aoc/2024/05/raku.raku | 10 + aoc/2024/05/rust/Cargo.lock | 7 + aoc/2024/05/rust/Cargo.toml | 6 + aoc/2024/05/rust/src/main.rs | 42 +++ aoc/2024/06/python.py | 57 ++++ aoc/2024/06/rust/Cargo.lock | 7 + aoc/2024/06/rust/Cargo.toml | 4 + aoc/2024/06/rust/src/main.rs | 105 +++++++ aoc/2024/07/python.py | 37 +++ aoc/2024/07/rust/Cargo.lock | 7 + aoc/2024/07/rust/Cargo.toml | 6 + aoc/2024/07/rust/src/main.rs | 71 +++++ aoc/2024/08/python.py | 51 ++++ aoc/2024/08/rust/Cargo.lock | 7 + aoc/2024/08/rust/Cargo.toml | 6 + aoc/2024/08/rust/src/main.rs | 74 +++++ aoc/2024/09/python.py | 62 ++++ aoc/2024/09/rust/Cargo.lock | 7 + aoc/2024/09/rust/Cargo.toml | 6 + aoc/2024/09/rust/src/main.rs | 100 +++++++ aoc/2024/10/python.py | 43 +++ aoc/2024/10/rust/Cargo.lock | 7 + aoc/2024/10/rust/Cargo.toml | 6 + aoc/2024/10/rust/src/main.rs | 52 ++++ aoc/2024/11/python.py | 30 ++ aoc/2024/11/rust/Cargo.lock | 7 + aoc/2024/11/rust/Cargo.toml | 6 + aoc/2024/11/rust/src/main.rs | 43 +++ aoc/2024/12/python.py | 49 ++++ aoc/2024/13/python.py | 40 +++ aoc/2024/14/python.py | 64 ++++ aoc/2024/15/python.py | 83 ++++++ aoc/2024/16/python.py | 31 ++ aoc/2024/17/python.py | 68 +++++ aoc/2024/18/python.py | 47 +++ aoc/2024/19/python.py | 42 +++ aoc/2024/20/python.py | 40 +++ aoc/2024/21/python.py | 42 +++ aoc/2024/22/python.py | 59 ++++ aoc/2025/01/c.c | 19 ++ aoc/2025/01/python.py | 15 + aoc/2025/01/rust/Cargo.lock | 89 ++++++ aoc/2025/01/rust/Cargo.toml | 7 + aoc/2025/01/rust/src/main.rs | 25 ++ aoc/2025/02/python.py | 33 +++ aoc/2025/03/python.py | 21 ++ aoc/2025/03/rust/Cargo.lock | 7 + aoc/2025/03/rust/Cargo.toml | 6 + aoc/2025/03/rust/src/main.rs | 42 +++ aoc/2025/04/python.py | 36 +++ aoc/2025/04/rust/Cargo.lock | 7 + aoc/2025/04/rust/Cargo.toml | 6 + aoc/2025/04/rust/src/main.rs | 66 +++++ aoc/2025/05/python.py | 39 +++ aoc/2025/05/rust/Cargo.lock | 7 + aoc/2025/05/rust/Cargo.toml | 6 + aoc/2025/05/rust/src/main.rs | 55 ++++ aoc/2025/06/python.py | 18 ++ aoc/2025/07/python.py | 31 ++ aoc/2025/08/python.py | 29 ++ aoc/2025/09/python.py | 13 + aoc/2025/09/rust/Cargo.lock | 7 + aoc/2025/09/rust/Cargo.toml | 6 + aoc/2025/09/rust/src/main.rs | 113 ++++++++ aoc/2025/10/rust/Cargo.lock | 155 ++++++++++ aoc/2025/10/rust/Cargo.toml | 8 + aoc/2025/10/rust/src/main.rs | 68 +++++ aoc/2025/11/rust/Cargo.lock | 7 + aoc/2025/11/rust/Cargo.toml | 6 + aoc/2025/11/rust/src/main.rs | 84 ++++++ aoc/2025/12/python.py | 21 ++ check | 51 ++-- init | 36 ++- template/python.py | 0 188 files changed, 2946 insertions(+), 3623 deletions(-) delete mode 100755 2024/01/python.py delete mode 100755 2024/01/raku.raku delete mode 100644 2024/01/rust/Cargo.lock delete mode 100644 2024/01/rust/Cargo.toml delete mode 100644 2024/01/rust/src/main.rs delete mode 100755 2024/02/python.py delete mode 100755 2024/02/raku.raku delete mode 100644 2024/02/rust/Cargo.lock delete mode 100644 2024/02/rust/Cargo.toml delete mode 100644 2024/02/rust/src/main.rs delete mode 100755 2024/03/python.py delete mode 100755 2024/03/raku.raku delete mode 100644 2024/03/rust/Cargo.lock delete mode 100644 2024/03/rust/Cargo.toml delete mode 100644 2024/03/rust/src/main.rs delete mode 100755 2024/04/python.py delete mode 100755 2024/04/raku.raku delete mode 100644 2024/04/rust/Cargo.lock delete mode 100644 2024/04/rust/Cargo.toml delete mode 100644 2024/04/rust/src/main.rs delete mode 100755 2024/05/python.py delete mode 100755 2024/05/raku.raku delete mode 100644 2024/05/rust/Cargo.lock delete mode 100644 2024/05/rust/Cargo.toml delete mode 100644 2024/05/rust/src/main.rs delete mode 100755 2024/06/python.py delete mode 100644 2024/06/rust/Cargo.lock delete mode 100644 2024/06/rust/Cargo.toml delete mode 100644 2024/06/rust/src/main.rs delete mode 100755 2024/07/python.py delete mode 100644 2024/07/rust/Cargo.lock delete mode 100644 2024/07/rust/Cargo.toml delete mode 100644 2024/07/rust/src/main.rs delete mode 100755 2024/08/python.py delete mode 100644 2024/08/rust/Cargo.lock delete mode 100644 2024/08/rust/Cargo.toml delete mode 100644 2024/08/rust/src/main.rs delete mode 100755 2024/09/python.py delete mode 100644 2024/09/rust/Cargo.lock delete mode 100644 2024/09/rust/Cargo.toml delete mode 100644 2024/09/rust/src/main.rs delete mode 100755 2024/10/python.py delete mode 100644 2024/10/rust/Cargo.lock delete mode 100644 2024/10/rust/Cargo.toml delete mode 100644 2024/10/rust/src/main.rs delete mode 100755 2024/11/python.py delete mode 100644 2024/11/rust/Cargo.lock delete mode 100644 2024/11/rust/Cargo.toml delete mode 100644 2024/11/rust/src/main.rs delete mode 100755 2024/12/python.py delete mode 100755 2024/13/python.py delete mode 100755 2024/14/python.py delete mode 100755 2024/15/python.py delete mode 100755 2024/16/python.py delete mode 100755 2024/17/python.py delete mode 100755 2024/18/python.py delete mode 100755 2024/19/python.py delete mode 100755 2024/20/python.py delete mode 100755 2024/21/python.py delete mode 100755 2024/22/python.py delete mode 100644 2025/01/c.c delete mode 100755 2025/01/python.py delete mode 100644 2025/01/rust/Cargo.lock delete mode 100644 2025/01/rust/Cargo.toml delete mode 100644 2025/01/rust/src/main.rs delete mode 100755 2025/02/python.py delete mode 100755 2025/03/python.py delete mode 100644 2025/03/rust/Cargo.lock delete mode 100644 2025/03/rust/Cargo.toml delete mode 100644 2025/03/rust/src/main.rs delete mode 100755 2025/04/python.py delete mode 100644 2025/04/rust/Cargo.lock delete mode 100644 2025/04/rust/Cargo.toml delete mode 100644 2025/04/rust/src/main.rs delete mode 100755 2025/05/python.py delete mode 100644 2025/05/rust/Cargo.lock delete mode 100644 2025/05/rust/Cargo.toml delete mode 100644 2025/05/rust/src/main.rs delete mode 100755 2025/06/python.py delete mode 100755 2025/07/python.py delete mode 100755 2025/08/python.py delete mode 100755 2025/09/python.py delete mode 100644 2025/09/rust/Cargo.lock delete mode 100644 2025/09/rust/Cargo.toml delete mode 100644 2025/09/rust/src/main.rs delete mode 100644 2025/10/rust/Cargo.lock delete mode 100644 2025/10/rust/Cargo.toml delete mode 100644 2025/10/rust/src/main.rs delete mode 100644 2025/11/rust/Cargo.lock delete mode 100644 2025/11/rust/Cargo.toml delete mode 100644 2025/11/rust/src/main.rs delete mode 100755 2025/12/python.py delete mode 100644 LICENSE create mode 100755 aoc/2024/01/python.py create mode 100755 aoc/2024/01/raku.raku create mode 100644 aoc/2024/01/rust/Cargo.lock create mode 100644 aoc/2024/01/rust/Cargo.toml create mode 100644 aoc/2024/01/rust/src/main.rs create mode 100755 aoc/2024/02/python.py create mode 100755 aoc/2024/02/raku.raku create mode 100644 aoc/2024/02/rust/Cargo.lock create mode 100644 aoc/2024/02/rust/Cargo.toml create mode 100644 aoc/2024/02/rust/src/main.rs create mode 100755 aoc/2024/03/python.py create mode 100755 aoc/2024/03/raku.raku create mode 100644 aoc/2024/03/rust/Cargo.lock create mode 100644 aoc/2024/03/rust/Cargo.toml create mode 100644 aoc/2024/03/rust/src/main.rs create mode 100755 aoc/2024/04/python.py create mode 100755 aoc/2024/04/raku.raku create mode 100644 aoc/2024/04/rust/Cargo.lock create mode 100644 aoc/2024/04/rust/Cargo.toml create mode 100644 aoc/2024/04/rust/src/main.rs create mode 100755 aoc/2024/05/python.py create mode 100755 aoc/2024/05/raku.raku create mode 100644 aoc/2024/05/rust/Cargo.lock create mode 100644 aoc/2024/05/rust/Cargo.toml create mode 100644 aoc/2024/05/rust/src/main.rs create mode 100755 aoc/2024/06/python.py create mode 100644 aoc/2024/06/rust/Cargo.lock create mode 100644 aoc/2024/06/rust/Cargo.toml create mode 100644 aoc/2024/06/rust/src/main.rs create mode 100755 aoc/2024/07/python.py create mode 100644 aoc/2024/07/rust/Cargo.lock create mode 100644 aoc/2024/07/rust/Cargo.toml create mode 100644 aoc/2024/07/rust/src/main.rs create mode 100755 aoc/2024/08/python.py create mode 100644 aoc/2024/08/rust/Cargo.lock create mode 100644 aoc/2024/08/rust/Cargo.toml create mode 100644 aoc/2024/08/rust/src/main.rs create mode 100755 aoc/2024/09/python.py create mode 100644 aoc/2024/09/rust/Cargo.lock create mode 100644 aoc/2024/09/rust/Cargo.toml create mode 100644 aoc/2024/09/rust/src/main.rs create mode 100755 aoc/2024/10/python.py create mode 100644 aoc/2024/10/rust/Cargo.lock create mode 100644 aoc/2024/10/rust/Cargo.toml create mode 100644 aoc/2024/10/rust/src/main.rs create mode 100755 aoc/2024/11/python.py create mode 100644 aoc/2024/11/rust/Cargo.lock create mode 100644 aoc/2024/11/rust/Cargo.toml create mode 100644 aoc/2024/11/rust/src/main.rs create mode 100755 aoc/2024/12/python.py create mode 100755 aoc/2024/13/python.py create mode 100755 aoc/2024/14/python.py create mode 100755 aoc/2024/15/python.py create mode 100755 aoc/2024/16/python.py create mode 100755 aoc/2024/17/python.py create mode 100755 aoc/2024/18/python.py create mode 100755 aoc/2024/19/python.py create mode 100755 aoc/2024/20/python.py create mode 100755 aoc/2024/21/python.py create mode 100755 aoc/2024/22/python.py create mode 100644 aoc/2025/01/c.c create mode 100755 aoc/2025/01/python.py create mode 100644 aoc/2025/01/rust/Cargo.lock create mode 100644 aoc/2025/01/rust/Cargo.toml create mode 100644 aoc/2025/01/rust/src/main.rs create mode 100755 aoc/2025/02/python.py create mode 100755 aoc/2025/03/python.py create mode 100644 aoc/2025/03/rust/Cargo.lock create mode 100644 aoc/2025/03/rust/Cargo.toml create mode 100644 aoc/2025/03/rust/src/main.rs create mode 100755 aoc/2025/04/python.py create mode 100644 aoc/2025/04/rust/Cargo.lock create mode 100644 aoc/2025/04/rust/Cargo.toml create mode 100644 aoc/2025/04/rust/src/main.rs create mode 100755 aoc/2025/05/python.py create mode 100644 aoc/2025/05/rust/Cargo.lock create mode 100644 aoc/2025/05/rust/Cargo.toml create mode 100644 aoc/2025/05/rust/src/main.rs create mode 100755 aoc/2025/06/python.py create mode 100755 aoc/2025/07/python.py create mode 100755 aoc/2025/08/python.py create mode 100755 aoc/2025/09/python.py create mode 100644 aoc/2025/09/rust/Cargo.lock create mode 100644 aoc/2025/09/rust/Cargo.toml create mode 100644 aoc/2025/09/rust/src/main.rs create mode 100644 aoc/2025/10/rust/Cargo.lock create mode 100644 aoc/2025/10/rust/Cargo.toml create mode 100644 aoc/2025/10/rust/src/main.rs create mode 100644 aoc/2025/11/rust/Cargo.lock create mode 100644 aoc/2025/11/rust/Cargo.toml create mode 100644 aoc/2025/11/rust/src/main.rs create mode 100755 aoc/2025/12/python.py mode change 100644 => 100755 template/python.py diff --git a/2024/01/python.py b/2024/01/python.py deleted file mode 100755 index 425f6c7..0000000 --- a/2024/01/python.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -from collections import Counter -from fileinput import input - -L, R = zip(*[[int(n) for n in s.split()] for s in input()]) - -silver = sum(abs(left - right) for left, right in zip(sorted(L), sorted(R))) - -L, R = Counter(L), Counter(R) -gold = sum(n * L[n] * R[n] for n in list(L & R)) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/01/raku.raku b/2024/01/raku.raku deleted file mode 100755 index c4a44e0..0000000 --- a/2024/01/raku.raku +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env raku - -my $ids := ([Z] lines>>.words)>>.sort>>.list; -say "silver: ", ([Z-] $ids)>>.abs.sum; -say "gold: ", ([<<*>>] $ids>>.Bag).kxxv.sum; diff --git a/2024/01/rust/Cargo.lock b/2024/01/rust/Cargo.lock deleted file mode 100644 index 7010c56..0000000 --- a/2024/01/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-01" -version = "0.1.0" diff --git a/2024/01/rust/Cargo.toml b/2024/01/rust/Cargo.toml deleted file mode 100644 index 0e9bfaa..0000000 --- a/2024/01/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2024-01" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/2024/01/rust/src/main.rs b/2024/01/rust/src/main.rs deleted file mode 100644 index c1648cf..0000000 --- a/2024/01/rust/src/main.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::collections::HashMap; -use std::io; - -fn main() -> io::Result<()> { - let (mut ls, mut rs): (Vec, Vec) = io::stdin() - .lines() - .map(|line| { - line.unwrap() - .split_whitespace() - .map(|s| s.parse().unwrap()) - .collect::>() - }) - .map(|xs| (xs[0], xs[1])) - .unzip(); - - ls.sort_unstable(); - rs.sort_unstable(); - - let mut counts = HashMap::new(); - rs.iter().for_each(|&x| { - *counts.entry(x).or_insert(0) += 1; - }); - - let silver: u64 = ls.iter().zip(rs).map(|(x, y)| x.abs_diff(y)).sum(); - let gold: u64 = ls.iter().map(|x| x * counts.get(x).unwrap_or(&0)).sum(); - - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} diff --git a/2024/02/python.py b/2024/02/python.py deleted file mode 100755 index f2c807d..0000000 --- a/2024/02/python.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -reports = [[int(level) for level in report.split()] for report in input()] - - -def incr(xs): - return all(x < y and y - x <= 3 for x, y in zip(xs, xs[1:])) - - -def safe(xs): - return incr(xs) or incr(xs[::-1]) - - -def drops(xs): - return (xs[:idx] + xs[idx + 1 :] for idx, _ in enumerate(xs)) - - -silver = sum(safe(rep) for rep in reports) -gold = sum(any(safe(mod) for mod in drops(rep)) for rep in reports) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/02/raku.raku b/2024/02/raku.raku deleted file mode 100755 index 9b930de..0000000 --- a/2024/02/raku.raku +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env raku - -my @rs = lines>>.words.map(&cache); - -sub incr ($r) { $r.rotor(2=>-1).map({ ([-] $_) (elem) (1..3)}).all }; -sub safe ($r) { so $r.&incr || $r.reverse.&incr }; - -say "silver: ", @rs.map(&safe).sum; -say "gold: ", @rs.map({ $_.combinations($_-1).map(&safe).any.so }).sum; diff --git a/2024/02/rust/Cargo.lock b/2024/02/rust/Cargo.lock deleted file mode 100644 index f3a3299..0000000 --- a/2024/02/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-02" -version = "0.1.0" diff --git a/2024/02/rust/Cargo.toml b/2024/02/rust/Cargo.toml deleted file mode 100644 index 6030837..0000000 --- a/2024/02/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2024-02" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/2024/02/rust/src/main.rs b/2024/02/rust/src/main.rs deleted file mode 100644 index 2007837..0000000 --- a/2024/02/rust/src/main.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![feature(iter_map_windows)] - -use std::io; - -fn main() { - let input: Vec> = io::stdin() - .lines() - .map(|line| { - line.unwrap() - .split_whitespace() - .map(str::parse::) - .collect() - }) - .collect::, _>>() - .unwrap(); - - let silver: usize = input.iter().filter(|&xs| all_safe(xs)).count(); - let gold: usize = input.iter().filter(|&xs| drop_safe(xs)).count(); - println!("silver: {silver}"); - println!("gold: {gold}"); -} - -fn all_safe(xs: &Vec) -> bool { - let mut diffs = xs.iter().map_windows(|&[x, y]| y - x).peekable(); - let dir = diffs.peek().unwrap_or(&1).signum(); - diffs.all(|d| (1..=3).contains(&d.abs()) && d.signum() == dir) -} - -fn drop_safe(xs: &Vec) -> bool { - (0..xs.len()) - .map(|idx| xs.split_at(idx)) - .any(|(left, right)| all_safe(&[left, &right[1..]].concat())) -} diff --git a/2024/03/python.py b/2024/03/python.py deleted file mode 100755 index f456580..0000000 --- a/2024/03/python.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 - -import re -from fileinput import input - -s = "\n".join(input()) - -silver = sum(int(x) * int(y) for x, y in re.findall(r"mul\((\d{1,3}),(\d{1,3})\)", s)) - -gold = 0 -active = True -for g in re.findall(r"(?:mul\((\d{1,3}),(\d{1,3})\))|(don't\(\))|(do\(\))", s): - match g, active: - case (x, y, "", ""), True: - gold += int(x) * int(y) - case (_, _, "don't()", _), _: - active = False - case (_, _, _, "do()"), _: - active = True - - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/03/raku.raku b/2024/03/raku.raku deleted file mode 100755 index 38f040e..0000000 --- a/2024/03/raku.raku +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env raku - -my $p = slurp; - -sub p2 (($on, $tot), ($i, |n)) { - given $i { - when "mul" { return ($on , $tot + [*] $on, |n.list) } - when "do" { return (1 , $tot) } - when "don't" { return (0 , $tot) } - } -}; - -$p ~~ m:g/ mul\((\d ** 1..3)\,(\d ** 1..3)\) /; -say "silver: ", $/.map({ [*] $_.list }).sum; - -$p ~~ m:g/ (mul)\((\d ** 1..3)\,(\d ** 1..3)\) | (do)\(\) | (don\'t)\(\) /; -say "gold: ", ([[&p2]] <1 0>, |$/)[1]; diff --git a/2024/03/rust/Cargo.lock b/2024/03/rust/Cargo.lock deleted file mode 100644 index a7a6f57..0000000 --- a/2024/03/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-03" -version = "0.1.0" diff --git a/2024/03/rust/Cargo.toml b/2024/03/rust/Cargo.toml deleted file mode 100644 index 97ec307..0000000 --- a/2024/03/rust/Cargo.toml +++ /dev/null @@ -1,4 +0,0 @@ -[package] -name = "aoc_2024-03" -version = "0.1.0" -edition = "2021" diff --git a/2024/03/rust/src/main.rs b/2024/03/rust/src/main.rs deleted file mode 100644 index b268463..0000000 --- a/2024/03/rust/src/main.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::io::{self, Read}; - -#[derive(Debug)] -enum Instruction { - Do, - Dont, - Mul(u64, u64), -} - -impl From<&Instruction> for u64 { - fn from(val: &Instruction) -> Self { - match val { - Instruction::Mul(x, y) => x * y, - _ => 0, - } - } -} - -fn main() -> io::Result<()> { - let mut program = String::new(); - io::stdin().read_to_string(&mut program)?; - - let instrs = (0..program.len()) - .filter_map(|idx| { - let next = &program[idx..]; - if next.starts_with("do()") { - Some(Instruction::Do) - } else if next.starts_with("don't()") { - Some(Instruction::Dont) - } else if next.starts_with("mul(") { - let mut first = 0; - let mut curr = 0; - - for ch in next.bytes().skip(4) { - match (ch, curr) { - ((b'0'..=b'9'), _) => curr = curr * 10 + (ch - b'0') as u64, - (_, 0) => return None, - (b',', _) => { - first = curr; - curr = 0; - } - (b')', _) => { - return Some(Instruction::Mul(first, curr)); - } - _ => return None, - }; - } - None - } else { - None - } - }) - .collect::>(); - - let silver: u64 = instrs.iter().map(u64::from).sum(); - let (gold, _) = instrs - .iter() - .fold((0 as u64, true), |(acc, on), instr| match (instr, on) { - (Instruction::Do, _) => (acc, true), - (Instruction::Dont, _) => (acc, false), - (Instruction::Mul(_, _), true) => (acc + u64::from(instr), true), - _ => (acc, on), - }); - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} diff --git a/2024/04/python.py b/2024/04/python.py deleted file mode 100755 index fe5021b..0000000 --- a/2024/04/python.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -grid = { - complex(idx, idy): c - for idy, line in enumerate(input()) - for idx, c in enumerate(line.strip()) -} -dirs = {complex(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1]} - - -def xmas(x, v): - return all(grid.get(x + n * v) == c for n, c in enumerate("XMAS")) - - -def x_mas(x, v): - return ( - grid.get(x) == "A" - and grid.get(x + v) == grid.get(x + 1j * v) == "M" - and grid.get(x - v) == grid.get(x - 1j * v) == "S" - ) - - -silver = sum(xmas(x, v) for x in grid.keys() for v in dirs) -gold = sum(x_mas(x, v) for x in grid.keys() for v in dirs if abs(v) > 1) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/04/raku.raku b/2024/04/raku.raku deleted file mode 100755 index 6055fe4..0000000 --- a/2024/04/raku.raku +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env raku - -my @g = lines.map: *.comb.Array; - -@g.map: *.say; -say "---"; - -say @g[.[0]; .[1] .. .[1]+3] for (^@g X ^@g[0])[^4]; diff --git a/2024/04/rust/Cargo.lock b/2024/04/rust/Cargo.lock deleted file mode 100644 index 832036f..0000000 --- a/2024/04/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-04" -version = "0.1.0" diff --git a/2024/04/rust/Cargo.toml b/2024/04/rust/Cargo.toml deleted file mode 100644 index e872faf..0000000 --- a/2024/04/rust/Cargo.toml +++ /dev/null @@ -1,4 +0,0 @@ -[package] -name = "aoc_2024-04" -version = "0.1.0" -edition = "2021" diff --git a/2024/04/rust/src/main.rs b/2024/04/rust/src/main.rs deleted file mode 100644 index 191e461..0000000 --- a/2024/04/rust/src/main.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::io; - -fn main() -> io::Result<()> { - let grid = io::stdin() - .lines() - .flatten() - .map(|line| line.chars().collect()) - .collect::>>(); - let grid = Grid(grid); - - let silver: usize = silver(&grid); - let gold: usize = gold(&grid); - - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} - -struct Grid(Vec>); - -impl Grid { - fn at(&self, (x, y): (isize, isize)) -> Option<&char> { - self.0 - .get(usize::try_from(y).ok()?)? - .get(usize::try_from(x).ok()?) - } - - fn check<'a>( - &self, - (x, y): (isize, isize), - mut pat: impl Iterator, - ) -> bool { - pat.all(|((dx, dy), ch)| self.at((x + dx, y + dy)).is_some_and(|c| c == ch)) - } - - fn pts(&self) -> impl Iterator + use<'_> { - (0..self.0[0].len()).flat_map(|x| (0..self.0.len()).map(move |y| (x as isize, y as isize))) - } -} - -fn silver(grid: &Grid) -> usize { - let dirs = vec![ - (-1, -1), - (-1, 0), - (-1, 1), - (0, -1), - (0, 1), - (1, -1), - (1, 0), - (1, 1), - ]; - - let xmases: Vec> = dirs - .iter() - .map(|(dx, dy)| { - (0..4) - .map(move |n| (dx * n, dy * n)) - .zip("XMAS".chars()) - .collect() - }) - .collect(); - - grid.pts() - .flat_map(|p| xmases.iter().map(move |xmas| grid.check(p, xmas.iter()))) - .filter(|p| *p) - .count() -} - -fn gold(grid: &Grid) -> usize { - let dirs = vec![(-1, -1), (1, -1), (0, 0), (-1, 1), (1, 1)]; - - let xmases: Vec> = vec!["MMASS", "SMASM", "SSAMM", "MSAMS"] - .iter() - .map(|x| dirs.clone().into_iter().zip(x.chars()).collect()) - .collect(); - - grid.pts() - .flat_map(|p| xmases.iter().map(move |xmas| grid.check(p, xmas.iter()))) - .filter(|p| *p) - .count() -} diff --git a/2024/05/python.py b/2024/05/python.py deleted file mode 100755 index 9e81978..0000000 --- a/2024/05/python.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from functools import cmp_to_key -from itertools import takewhile - -inp = map(str.strip, input()) -ordering = set(takewhile(bool, inp)) -us = list(inp) - - -def cmp(x, y): - return (f"{y}|{x}" in ordering) * 2 - 1 # hehe - - -silver = 0 -gold = 0 - -for u in us: - pre = u.split(",") - post = list(sorted(pre, key=cmp_to_key(cmp))) - - mid = int(post[len(post) // 2]) - if pre == post: - silver += mid - else: - gold += mid - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/05/raku.raku b/2024/05/raku.raku deleted file mode 100755 index a13cf5a..0000000 --- a/2024/05/raku.raku +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env raku - -my (@rs, @us) := slurp.split("\n\n")>>.lines; - -sub mid(@u) { - my @s = @u.sort({ "$^a|$^b" !(elem) @rs }); - return (@u Z== @s).all.so ?? ($_, 0) !! (0, $_) with @s[@s/2]; -} - -(("silver: ", "gold: ") Z~ [Z+] @us>>.split(",").map(&mid)).map(&say); diff --git a/2024/05/rust/Cargo.lock b/2024/05/rust/Cargo.lock deleted file mode 100644 index 5ae963b..0000000 --- a/2024/05/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-05" -version = "0.1.0" diff --git a/2024/05/rust/Cargo.toml b/2024/05/rust/Cargo.toml deleted file mode 100644 index de0fa13..0000000 --- a/2024/05/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2024-05" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/2024/05/rust/src/main.rs b/2024/05/rust/src/main.rs deleted file mode 100644 index 0db788d..0000000 --- a/2024/05/rust/src/main.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![feature(slice_split_once)] - -use std::cmp::Ordering::{Greater, Less}; -use std::collections::HashSet; -use std::io; - -fn main() -> io::Result<()> { - let mut lines = io::stdin().lines().flatten(); - let mut set = HashSet::<(u16, u16)>::new(); - - while let Some(s) = lines.next() { - if let Some((a, b)) = s.split_once('|') { - set.insert((a.parse().unwrap(), b.parse().unwrap())); - } else { - break; - } - } - - let mut silver: usize = 0; - let mut gold: usize = 0; - - for line in lines { - let mut nums: Vec = line.split(',').map(|n| n.parse().unwrap()).collect(); - let mid = nums.len() / 2; - - if nums.is_sorted_by(|&a, &b| set.contains(&(a, b))) { - silver += nums[mid] as usize; - } else { - gold += *nums - .select_nth_unstable_by(mid, |&a, &b| match set.contains(&(a, b)) { - true => Less, - false => Greater, - }) - .1 as usize; - } - } - - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} diff --git a/2024/06/python.py b/2024/06/python.py deleted file mode 100755 index 52b61d0..0000000 --- a/2024/06/python.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -obstacles = set() -seen = set() - -xmax, ymax = 0, 0 -for idy, line in enumerate(input()): - ymax = max(ymax, idy) - for idx, c in enumerate(line.strip()): - xmax = max(xmax, idx) - match c: - case "^": - pos = complex(idx, idy) - dir = 0 - 1j - case "#": - obstacles.add(complex(idx, idy)) - - -def is_loop(pos, obst): - seen_ = set() - dir = 0 - 1j - while 0 <= pos.real <= xmax and 0 <= pos.imag <= ymax: - if (pos, dir) in seen_: - return True - seen_.add((pos, dir)) - if pos + dir in obstacles or pos + dir == obst: - # Rotate cw - dir *= 1j - continue - pos += dir - return False - - -gold = 0 -for idx in range(xmax + 1): - for idy in range(ymax + 1): - if complex(idx, idy) == pos: - continue - else: - gold += is_loop(pos, complex(idx, idy)) - - -while 0 <= pos.real <= xmax and 0 <= pos.imag <= ymax: - seen.add(pos) - if pos + dir in obstacles: - # Rotate cw - dir *= 1j - continue - pos += dir - - -silver = len(seen) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/06/rust/Cargo.lock b/2024/06/rust/Cargo.lock deleted file mode 100644 index 01e64d2..0000000 --- a/2024/06/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-06" -version = "0.1.0" diff --git a/2024/06/rust/Cargo.toml b/2024/06/rust/Cargo.toml deleted file mode 100644 index 01c1304..0000000 --- a/2024/06/rust/Cargo.toml +++ /dev/null @@ -1,4 +0,0 @@ -[package] -name = "aoc_2024-06" -version = "0.1.0" -edition = "2021" diff --git a/2024/06/rust/src/main.rs b/2024/06/rust/src/main.rs deleted file mode 100644 index ca78bcd..0000000 --- a/2024/06/rust/src/main.rs +++ /dev/null @@ -1,105 +0,0 @@ -use std::collections::HashSet; -use std::{collections::HashMap, io}; - -#[derive(Clone)] -enum Cell { - Empty, - Obstacle, -} - -#[derive(Clone)] -enum Direction { - L = 0b1, - R = 0b10, - U = 0b100, - D = 0b1000, -} - -impl Direction { - fn shift(&self, point: (isize, isize)) -> (isize, isize) { - let (x, y) = point; - match self { - Direction::L => (x - 1, y), - Direction::R => (x + 1, y), - Direction::U => (x, y - 1), - Direction::D => (x, y + 1), - } - } - - fn rotate(&self) -> Self { - use Direction::*; - match self { - L => U, - R => D, - U => R, - D => L, - } - } -} - -fn main() -> io::Result<()> { - let mut map = HashMap::new(); - let mut start = None; - io::stdin() - .lines() - .flatten() - .enumerate() - .flat_map(|(y, line)| { - line.chars() - .enumerate() - .map(|(x, ch)| ([x as isize, y as isize], ch)) - .collect::>() - }) - .for_each(|([x, y], ch)| match ch { - '.' => { - map.insert((x, y), Cell::Empty); - } - '^' => { - map.insert((x, y), Cell::Empty); - start = Some((x, y)) - } - '#' => { - map.insert((x, y), Cell::Obstacle); - } - _ => panic!(), - }); - let start = start.unwrap(); - - let visited = path_len(&map, start.clone()).unwrap(); - let silver: usize = visited.len(); - let gold: usize = visited - .iter() - .filter(|&p| { - let mut map = map.clone(); - map.insert(*p, Cell::Obstacle); - path_len(&map, start.clone()).is_none() - }) - .count(); - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} - -fn path_len( - map: &HashMap<(isize, isize), Cell>, - mut pos: (isize, isize), -) -> Option> { - let mut visited = HashMap::new(); - let mut dir = Direction::U; - - loop { - let before = visited.entry(pos).or_insert(0 as u8); - if *before & dir.clone() as u8 > 0 { - return None; - } - *before |= dir.clone() as u8; - - let ahead = dir.shift(pos); - match map.get(&ahead) { - Some(Cell::Empty) => pos = ahead, - Some(Cell::Obstacle) => dir = dir.rotate(), - None => return Some(visited.into_keys().collect()), - }; - } -} diff --git a/2024/07/python.py b/2024/07/python.py deleted file mode 100755 index 008af39..0000000 --- a/2024/07/python.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -lines = [line.strip() for line in input()] - - -def solve(w, acc, rest, gold=False): - if not rest: - return w == acc - if w < acc: - return False - head, *rest = rest - return ( - solve(w, acc + head, rest, gold) - or solve(w, acc * head, rest, gold) - or (gold and solve(w, int(str(acc) + str(head)), rest, gold)) - ) - - -silver = 0 -gold = 0 - -for line in lines: - want, nums = line.split(":") - want = int(want) - nums = [int(n) for n in nums.split()] - head, *rest = nums - - if solve(want, head, rest): - silver += want - if solve(want, head, rest, True): - gold += want - - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/07/rust/Cargo.lock b/2024/07/rust/Cargo.lock deleted file mode 100644 index d1897ed..0000000 --- a/2024/07/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-07" -version = "0.1.0" diff --git a/2024/07/rust/Cargo.toml b/2024/07/rust/Cargo.toml deleted file mode 100644 index c64c1b5..0000000 --- a/2024/07/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2024-07" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/2024/07/rust/src/main.rs b/2024/07/rust/src/main.rs deleted file mode 100644 index df586b1..0000000 --- a/2024/07/rust/src/main.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::io; - -fn main() -> io::Result<()> { - let eqns = io::stdin() - .lines() - .flatten() - .collect::>() - .iter() - .map(|line| line.split_once(": ").unwrap()) - .map(|(ans, nums)| { - ( - ans.parse::().unwrap(), - nums.split_whitespace() - .map(|s| s.parse::().unwrap()) - .collect::>(), - ) - }) - .collect::>(); - - let silver: u64 = eqns.iter().map(crate::silver).sum(); - let gold: u64 = eqns.iter().map(crate::gold).sum(); - - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} - -fn concat(x: &u64, y: &u64) -> u64 { - x * (10u64.pow(y.ilog10() + 1)) + y -} - -fn calibration(want: u64, x: &u64, y: &u64, rest: &[u64], gold: bool) -> bool { - if *x > want { - return false; - } - match rest { - [] => want == x + y || want == x * y || (gold && want == concat(x, y)), - [z, rest @ ..] => { - calibration(want, &(x + y), z, rest, gold) - || calibration(want, &(x * y), z, rest, gold) - || (gold && calibration(want, &concat(x, y), z, rest, gold)) - } - } -} - -fn silver((want, nums): &(u64, Vec)) -> u64 { - match nums.as_slice() { - [x, y, rest @ ..] => { - if calibration(*want, x, y, rest, false) { - *want - } else { - 0 - } - } - _ => 0, - } -} - -fn gold((want, nums): &(u64, Vec)) -> u64 { - match nums.as_slice() { - [x, y, rest @ ..] => { - if calibration(*want, x, y, rest, true) { - *want - } else { - 0 - } - } - _ => 0, - } -} diff --git a/2024/08/python.py b/2024/08/python.py deleted file mode 100755 index 783203b..0000000 --- a/2024/08/python.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 - -from collections import defaultdict -from fileinput import input -from itertools import product - -antennas = defaultdict(set) -x_max, y_max = 0, 0 - -for idy, line in enumerate(input()): - y_max = max(y_max, idy) - for idx, c in enumerate(line.strip()): - x_max = max(x_max, idx) - if c == ".": - continue - - antennas[c].add(complex(idx, idy)) - -nodes = set() -for vs in antennas.values(): - for v1, v2 in product(vs, vs): - if v1 == v2: - continue - vec = v2 - v1 - nodes.add(v1 + 2 * vec) - nodes.add(v2 - 2 * vec) - -nodes = {n for n in nodes if 0 <= n.real <= x_max and 0 <= n.imag <= y_max} - -gold_nodes = set() -for vs in antennas.values(): - for v1, v2 in product(vs, vs): - if v1 == v2: - continue - vec = v2 - v1 - start = v1 - while 0 <= start.real <= x_max and 0 <= start.imag <= y_max: - gold_nodes.add(start) - start += vec - - start = v2 - while 0 <= start.real <= x_max and 0 <= start.imag <= y_max: - gold_nodes.add(start) - start -= vec - - -silver = len(nodes) -gold = len(gold_nodes) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/08/rust/Cargo.lock b/2024/08/rust/Cargo.lock deleted file mode 100644 index e91e374..0000000 --- a/2024/08/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-08" -version = "0.1.0" diff --git a/2024/08/rust/Cargo.toml b/2024/08/rust/Cargo.toml deleted file mode 100644 index bb3b056..0000000 --- a/2024/08/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2024-08" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/2024/08/rust/src/main.rs b/2024/08/rust/src/main.rs deleted file mode 100644 index 4fc3286..0000000 --- a/2024/08/rust/src/main.rs +++ /dev/null @@ -1,74 +0,0 @@ -use std::{ - collections::{HashMap, HashSet}, - io, -}; - -fn main() -> io::Result<()> { - let mut antennae: HashMap> = HashMap::new(); - - let grid = io::stdin() - .lines() - .flatten() - .map(|s| s.chars().collect()) - .collect::>>(); - - let max = grid.first().unwrap().len() as i32; - let may = grid.len() as i32; - grid.iter() - .enumerate() - .flat_map(|(y, row)| { - row.iter() - .enumerate() - .filter(|(_, &c)| c != '.') - .map(move |(x, &c)| (c, (x as i32, y as i32))) - }) - .for_each(|(c, p)| antennae.entry(c).or_default().push(p)); - - let mut silver = HashSet::new(); - let mut gold = HashSet::new(); - for ps in antennae.values() { - for (n, &p) in ps.iter().enumerate() { - for &t in &ps[n+1..] { - antinodes(p, t, (max, may), false).for_each(|n| { - silver.insert(n); - }); - antinodes(p, t, (max, may), true).for_each(|n| { - gold.insert(n); - }); - } - } - } - - let silver = silver.len(); - let gold = gold.len(); - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} - -fn antinodes( - a: (i32, i32), - b: (i32, i32), - max: (i32, i32), - gold: bool, -) -> impl Iterator { - let dx = b.0 - a.0; - let dy = b.1 - a.1; - let in_range = move |(x, y)| (0..max.0).contains(&x) && (0..max.1).contains(&y); - if !gold { - vec![(a.0 - dx, a.1 - dy), (b.0 + dx, b.1 + dy)] - } else { - (0..) - .map(|n| (a.0 - n * dx, a.1 - n * dy)) - .take_while(move |&p| in_range(p)) - .chain( - (0..) - .map(|n| (b.0 + n * dx, b.1 + n * dy)) - .take_while(move |&p| in_range(p)), - ) - .collect() - } - .into_iter() - .filter(move |&p| in_range(p)) -} diff --git a/2024/09/python.py b/2024/09/python.py deleted file mode 100755 index 1cf450e..0000000 --- a/2024/09/python.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -disk = list(input())[0].strip() - -id_ = -1 -blocks = [] -tail = 0 -file = True -for c in disk: - blocks.append([tail, tail + int(c), (id_ := id_ + 1) if file else -1]) - tail += int(c) - file = not file - - -def expand(bs): - return [x for a, b, x in sorted(bs) for _ in range(b - a)] - - -def debug(bs): - print("".join(str(b) if b != -1 else "." for b in expand(bs))) - - -# Silver -expanded = expand(blocks) -tail = len(expanded) - 1 -fill = expanded.index(-1) -while fill < tail: - expanded[fill] = expanded[tail] - expanded[tail] = -1 - while expanded[tail] == -1: - tail -= 1 - while expanded[fill] != -1: - fill += 1 -silver = sum(idx * n for idx, n in enumerate(expanded) if n != -1) - - -# Gold -for move in blocks[::-1]: - print(move) - ma, mb, mx = move - if mx == -1: - continue - mlen = mb - ma - for tidx, to in enumerate(blocks): - ta, tb, tx = to - if ta >= ma: - break - if tx != -1: - continue - if (tlen := tb - ta) < mlen: - continue - move[2] = -1 - to[2] = mx - to[1] = ta + mlen - blocks.insert(tidx + 1, [ta + mlen, tb, -1]) - break -gold = sum(idx * n for idx, n in enumerate(expand(blocks)) if n != -1) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/09/rust/Cargo.lock b/2024/09/rust/Cargo.lock deleted file mode 100644 index 1a4e400..0000000 --- a/2024/09/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-09" -version = "0.1.0" diff --git a/2024/09/rust/Cargo.toml b/2024/09/rust/Cargo.toml deleted file mode 100644 index b440a8b..0000000 --- a/2024/09/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2024-09" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/2024/09/rust/src/main.rs b/2024/09/rust/src/main.rs deleted file mode 100644 index fa7c021..0000000 --- a/2024/09/rust/src/main.rs +++ /dev/null @@ -1,100 +0,0 @@ -#![feature(iter_array_chunks)] - -use std::io; - -fn main() -> io::Result<()> { - let disk_map = io::stdin() - .lines() - .flatten() - .next() - .unwrap() - .chars() - .map(|c| c as u8 - b'0') - .collect(); - - let silver: usize = silver(&disk_map); - let gold: usize = gold(&disk_map); - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} - -fn silver(input: &Vec) -> usize { - let mut blocks = input - .iter() - .chain([0, 0].iter()) // lol - .array_chunks() - .enumerate() - .map(|(n, [&f, &s])| [[Some(n)].repeat(f as usize), [None].repeat(s as usize)]) - .flatten() - .flatten() - .collect::>(); - - let mut l = 0; - let mut r = blocks.len() - 1; - loop { - while blocks[r].is_none() { - r -= 1; - } - while blocks[l].is_some() { - l += 1; - } - if l >= r { - break; - } - let [left, right] = blocks.get_disjoint_mut([l, r]).unwrap(); - left.replace(right.take().unwrap()); - } - - blocks - .iter() - .enumerate() - .map(|(n, id)| n * id.unwrap_or_default()) - .sum() -} - -fn gold(input: &Vec) -> usize { - let mut blocks = input - .iter() - .chain([0, 0].iter()) // lol - .array_chunks() - .enumerate() - .map(|(n, [&f, &s])| [(Some(n), f as usize), (None, s as usize)]) - .flatten() - .collect::>(); - - let mut r = blocks.len(); - while r > 0 { - r -= 1; - let (Some(_), f) = blocks[r] else { - continue; - }; - - // find some empty space and maybe split - let Some(l) = blocks.iter().position(|b| b.0.is_none() && b.1 >= f) else { - continue; - }; - if l > r { - continue; - }; - - let (_, s) = &mut blocks[l]; - - let diff = *s - f; - if diff > 0 { - *s = f; - blocks.insert(l + 1, (None, diff)); - r += 1; - } - blocks.swap(l, r); - } - - blocks - .iter() - .map(|&(id, n)| [id].repeat(n)) - .flatten() - .enumerate() - .map(|(n, id)| n * id.unwrap_or_default()) - .sum() -} diff --git a/2024/10/python.py b/2024/10/python.py deleted file mode 100755 index 88892b6..0000000 --- a/2024/10/python.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -grid = [[int(c) for c in line.strip()] for line in input()] - -starts = { - (idx, idy) for idy, line in enumerate(grid) for idx, n in enumerate(line) if n == 0 -} - -# print(*grid, sep="\n") -# print(starts) - - -def score_trailhead(start, gold): - score = 0 - q = [start] - seen = set() - while q: - x, y = q.pop() - seen.add((x, y)) - - h = grid[y][x] - if h == 9: - score += 1 - continue - for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]: - nx, ny = x + dx, y + dy - if ((nx, ny) in seen and not gold) or not ( - 0 <= nx < len(grid) and 0 <= ny < len(grid[0]) - ): - continue - - if grid[ny][nx] == h + 1: - q.append((nx, ny)) - return score - - -silver = sum(score_trailhead(start, False) for start in starts) -gold = sum(score_trailhead(start, True) for start in starts) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/10/rust/Cargo.lock b/2024/10/rust/Cargo.lock deleted file mode 100644 index de24ddf..0000000 --- a/2024/10/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-10" -version = "0.1.0" diff --git a/2024/10/rust/Cargo.toml b/2024/10/rust/Cargo.toml deleted file mode 100644 index 787d795..0000000 --- a/2024/10/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2024-10" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/2024/10/rust/src/main.rs b/2024/10/rust/src/main.rs deleted file mode 100644 index b5b3825..0000000 --- a/2024/10/rust/src/main.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::collections::HashSet; -use std::io; - -fn main() -> io::Result<()> { - let grid: Vec> = io::stdin() - .lines() - .flatten() - .map(|s| s.chars().map(|c| c.to_digit(10).unwrap() as u8).collect()) - .collect(); - - let starts = grid - .iter() - .enumerate() - .flat_map(|(y, row)| row.iter().enumerate().map(move |(x, d)| (x, y, d))) - .filter_map(|(x, y, d)| (*d == 0).then_some((y, x))) - .collect::>(); - - let silver: usize = starts.iter().map(|&s| trailheads(s, &grid, false)).sum(); - let gold: usize = starts.iter().map(|&s| trailheads(s, &grid, true)).sum(); - - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} - -fn trailheads(start: (usize, usize), grid: &Vec>, count_paths: bool) -> usize { - let mut seen = HashSet::new(); - let mut tot = 0; - let mut q = vec![start]; - - while let Some(curr @ (y, x)) = q.pop() { - seen.insert(curr); - let h = grid[y][x]; - if h == 9 { - tot += 1; - continue; - } - - [ - ((y + 1).min(grid.len() - 1), x), - (y, (x + 1).min(grid[0].len() - 1)), - (y.saturating_sub(1), x), - (y, x.saturating_sub(1)), - ] - .iter() - .filter(|&&(ny, nx)| grid[ny][nx] == h + 1) - .filter(|next| count_paths || !seen.contains(next)) - .for_each(|&n| q.push(n)); - } - tot -} diff --git a/2024/11/python.py b/2024/11/python.py deleted file mode 100755 index 37f658e..0000000 --- a/2024/11/python.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from functools import cache -from math import floor, log - -stones = [int(x) for x in input().readline().split()] - - -@cache -def blink(s, n): - if n == 0: - return 1 - - if s == 0: - return blink(1, n - 1) - - digits = floor(log(s, 10) + 1e-6) + 1 - if digits % 2 == 0: - left, right = divmod(s, 10 ** (digits // 2)) - return blink(left, n - 1) + blink(right, n - 1) - - return blink(s * 2024, n - 1) - - -silver = sum(blink(s, 25) for s in stones) -gold = sum(blink(s, 75) for s in stones) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/11/rust/Cargo.lock b/2024/11/rust/Cargo.lock deleted file mode 100644 index 22c9989..0000000 --- a/2024/11/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2024-11" -version = "0.1.0" diff --git a/2024/11/rust/Cargo.toml b/2024/11/rust/Cargo.toml deleted file mode 100644 index 67185f7..0000000 --- a/2024/11/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2024-11" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/2024/11/rust/src/main.rs b/2024/11/rust/src/main.rs deleted file mode 100644 index e352ec4..0000000 --- a/2024/11/rust/src/main.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::{collections::HashMap, io}; - -fn blink(k @ (s, n): (u64, u64), cache: &mut HashMap<(u64, u64), u64>) -> u64 { - if n == 0 { - return 1; - } - if let Some(v) = cache.get(&k) { - return *v; - } - - // cache this - let v = { - if s == 0 { - return blink((1, n - 1), cache); - } - let digits = s.ilog10() + 1; - let mid = 10u64.pow(digits / 2); - if digits % 2 == 0 { - blink((s / mid, n - 1), cache) + blink((s % mid, n - 1), cache) - } else { - blink((s * 2024, n - 1), cache) - } - }; - - *cache.entry(k).or_insert(v) -} - -fn main() -> io::Result<()> { - let line = io::stdin().lines().flatten().next().unwrap(); - let stones = line - .split_whitespace() - .map(|s| s.parse::().unwrap()) - .collect::>(); - - let mut cache = HashMap::new(); - let silver: u64 = stones.iter().map(|s| blink((*s, 25), &mut cache)).sum(); - let gold: u64 = stones.iter().map(|s| blink((*s, 75), &mut cache)).sum(); - - println!("silver: {silver}"); - println!("gold: {gold}"); - - return Ok(()); -} diff --git a/2024/12/python.py b/2024/12/python.py deleted file mode 100755 index 81761bc..0000000 --- a/2024/12/python.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -grid = { - complex(idx, idy): c - for idy, line in enumerate(input()) - for idx, c in enumerate(line.strip()) -} -xmax = int(max(x.real for x in grid.keys())) -ymax = int(max(x.imag for x in grid.keys())) - -seen = set() - -silver = 0 - -for x in range(xmax + 1): - for y in range(ymax + 1): - c = complex(x, y) - if c in seen: - continue - - # Flood fill - char = grid[c] - perimeter = area = 0 - queue = [c] - while queue: - curr = queue.pop() - if curr in seen: - continue - seen.add(curr) - - for dir in [1, -1, 1j, -1j]: - next_ = curr + dir - if ( - not (0 <= next_.real <= xmax and 0 <= next_.imag <= ymax) - or grid[next_] != char - ): - perimeter += 1 - continue - - queue.append(next_) - area += 1 - silver += perimeter * area - -gold = 0 - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/13/python.py b/2024/13/python.py deleted file mode 100755 index e78e35f..0000000 --- a/2024/13/python.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 - -import re -from fileinput import input -from itertools import batched - -lines = [line.strip() for line in input()] - - -re_button = r"Button [A|B]: X\+(\d+), Y\+(\d+)" -re_prize = r"Prize: X=(\d+), Y=(\d+)" - - -def solve(machine, gold): - m = re.fullmatch( - r"Button A: X\+(\d+), Y\+(\d+)Button B: X\+(\d+), Y\+(\d+)Prize: X=(\d+), Y=(\d+)", - "".join(machine), - ) - # 2x2 matrix solve - ax, ay, bx, by, px, py = map(int, m.groups()) - if gold: - px += 10000000000000 - py += 10000000000000 - det = ax * by - ay * bx - - A = (by * px - bx * py) / det - B = (-ay * px + ax * py) / det - - # Check solutions are ints - if abs(int(A) - A) < 1e-7 and abs(int(B) - B) < 1e-7: - return 3 * int(A) + int(B) - else: - return 0 - - -silver = sum(solve(b, False) for b in batched(lines, 4)) -gold = sum(solve(b, True) for b in batched(lines, 4)) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/14/python.py b/2024/14/python.py deleted file mode 100755 index 2bb6cb4..0000000 --- a/2024/14/python.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python3 - -import re -from fileinput import input -from itertools import groupby -from math import prod - -XMAX, YMAX = 11, 7 # for test -XMAX, YMAX = 101, 103 # for aoc - -robots = [ - re.fullmatch(r"p=(\d+),(\d+) v=(-?\d+),(-?\d+)", line.strip()).groups() - for line in input() -] -robots = [ - (complex(int(px), int(py)), complex(int(vx), int(vy))) for px, py, vx, vy in robots -] - - -def move(p, v, s): - e = p + v * s - return complex(e.real % XMAX, e.imag % YMAX) - - -def quad(x): - return (x.real < XMAX // 2, x.imag < YMAX // 2) - - -def is_quad(x): - return x.real != XMAX // 2 and x.imag != YMAX // 2 - - -def draw(s): - print(f"Seconds passed: {s}") - moved = {move(p, v, s) for p, v in robots} - for x in range(XMAX): - for y in range(YMAX): - print( - "#" if complex(x, y) in moved else " ", - end="", - ) - print() - print("-" * XMAX) - - -moved = groupby( - sorted( - filter(is_quad, (move(p, v, 100) for p, v in robots)), - key=quad, - ), - quad, -) - - -silver = prod(sum(1 for _ in k) for _, k in moved) -gold = 0 - -print("silver:", silver) -print("gold:", gold) - -s = 0 -while s < 10_000: - draw(s) - s += 1 diff --git a/2024/15/python.py b/2024/15/python.py deleted file mode 100755 index 4cfd48c..0000000 --- a/2024/15/python.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from itertools import takewhile - -inp = map(str.strip, input()) - -grid = { - complex(x, y): c - for y, line in enumerate(takewhile(bool, inp)) - for x, c in enumerate(line) -} -grid_gold = {} -for p, c in grid.items(): - p += p.real - match c: - case "#" | ".": - grid_gold[p] = grid_gold[p + 1] = c - case "O": - grid_gold[p] = "[" - grid_gold[p + 1] = "]" - case "@": - grid_gold[p] = "@" - grid_gold[p + 1] = "." - - -moves = "".join(inp) - -bot = next(p for p, c in grid.items() if c == "@") -bot_gold = bot + bot.real - - -def debug(grid): - xmax, ymax = (max(p.real for p in grid.keys()), max(p.imag for p in grid.keys())) - for y in range(int(ymax) + 1): - for x in range(int(xmax) + 1): - print(grid[complex(x, y)], end="") - print() - print() - - -def push(grid, x, v, modify=True): - match grid[x], v: - case ".", _: - return True - case "#", _: - return False - case "[", (1j | -1j) if push(grid, x + v, v, modify) and push( - grid, x + v + 1, v, modify - ): - if modify: - grid[x + v] = grid[x] - grid[x + v + 1] = grid[x + 1] - grid[x] = "." - grid[x + 1] = "." - return True - case "[", (1j | -1j): - return False - # Push other one - case "]", (1j | -1j): - return push(grid, x - 1, v, modify) - case _, _ if push(grid, x + v, v, modify): - if modify: - grid[x + v] = grid[x] - return True - - -dirs = {">": 1, "v": 1j, "<": -1, "^": -1j} -for m in map(dirs.get, moves): - if push(grid, bot, m): - grid[bot] = "." - bot += m - if push(grid_gold, bot_gold, m, modify=False): - push(grid_gold, bot_gold, m, modify=True) - grid_gold[bot_gold] = "." - bot_gold += m - - -silver = int(sum(p.real + 100 * p.imag for p, c in grid.items() if c == "O")) -gold = int(sum(p.real + 100 * p.imag for p, c in grid_gold.items() if c == "[")) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/16/python.py b/2024/16/python.py deleted file mode 100755 index fda3714..0000000 --- a/2024/16/python.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -grid = { - complex(idx, idy): c - for idy, line in enumerate(input()) - for idx, c in enumerate(line.strip()) -} -start = next(p for p, c in grid.items() if c == "S") -end = next(p for p, c in grid.items() if c == "E") - -q = [(0, (start, 1))] -seen = set() -while q: - curr = min(q, key=lambda x: x[0]) - d, (pos, vel) = curr - q.remove(curr) - if (pos, vel) in seen: - continue - if pos == end: - silver = d - break - seen.add((pos, vel)) - - if grid[pos + vel] != "#": - q.append((d + 1, (pos + vel, vel))) - q.append((d + 1000, (pos, vel * 1j))) - q.append((d + 1000, (pos, vel * -1j))) - -print("silver:", silver) diff --git a/2024/17/python.py b/2024/17/python.py deleted file mode 100755 index 9ea7de4..0000000 --- a/2024/17/python.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from itertools import takewhile, zip_longest - -inp = map(str.strip, input()) -regs = [int(r[2]) for r in (line.split() for line in takewhile(bool, inp))] -prog = [int(o) for o in next(inp).split()[1].split(",")] -out = [] - - -def run(prog, ra, rb, rc): - out = [] - ir = 0 - while ir < len(prog): - instr, op = prog[ir], prog[ir + 1] - combo = {4: ra, 5: rb, 6: rc} - cop = combo.get(op, op) - match instr: - case 0: - ra = ra >> cop - case 1: - rb ^= op - case 2: - rb = cop & 0b111 - case 3 if ra: - ir = op - 2 - case 4: - rb ^= rc - case 5: - yield cop & 0b111 - case 6: - rb = ra >> cop - case 7: - rc = ra >> cop - ir += 2 - return out - - -def match(prog, ra): - return ( - got == want - for got, want in zip_longest( - reversed(list(run(prog, ra, 0, 0))), - reversed(prog), - ) - ) - - -def find_a(prog): - q = list(range(8)) - while True: - curr = q.pop(0) - if all(match(prog, curr)): - return curr - - best = sum(match(prog, curr)) - for n in range(8): - ra = (curr << 3) + n - if sum(match(prog, ra)) > best: - q.append(ra) - - -silver = ",".join(map(str, run(prog, *regs))) -gold = find_a(prog) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/18/python.py b/2024/18/python.py deleted file mode 100755 index 1f987c6..0000000 --- a/2024/18/python.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 - -from bisect import bisect_left -from collections import deque -from fileinput import input - -coords = [line.strip().split(",") for line in input()] -grid = {complex(int(x), int(y)): t for t, [x, y] in enumerate(coords)} - - -def solve(size, delay): - q = deque([(0, 0)]) - seen = set() - while q: - curr, t = q.popleft() - if curr in seen: - continue - if curr == complex(size, size): - return t - seen.add(curr) - - for d in [1, -1, 1j, -1j]: - x = curr + d - if not (0 <= x.real <= size and 0 <= x.imag <= size): - continue - if x in grid and grid[x] < delay: - continue - q.append((x, t + 1)) - return None - - -silver = solve(70, 1024) -# silver = solve(6, 12) # test.txt - -gold = ",".join( - coords[ - bisect_left( - list(range(len(grid))), - True, - key=lambda x: solve(70, x) is None, - ) - - 1 - ] -) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/19/python.py b/2024/19/python.py deleted file mode 100755 index efd3272..0000000 --- a/2024/19/python.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from functools import cache -from itertools import takewhile - -inp = map(str.strip, input()) -towels = [t.strip() for t in next(takewhile(bool, inp)).split(",")] -designs = [d for d in inp if d] - -# Construct trie -trie = {} -for towel in towels: - prev = None - curr = trie - for t in towel: - term, succ = curr.setdefault(t, (False, {})) - prev = curr - curr = succ - prev[towel[-1]] = (True, curr) - - -@cache -def steps(design, n=0): - if n == len(design): - return 1 - ways = 0 - curr = trie - for d, s in enumerate(design[n:], start=1): - if s not in curr: - return ways - term, curr = curr[s] - if term: - ways += steps(design, n + d) - return ways - - -silver = sum(map(bool, map(steps, designs))) -gold = sum(map(steps, designs)) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/20/python.py b/2024/20/python.py deleted file mode 100755 index 610f1a3..0000000 --- a/2024/20/python.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -grid = { - complex(idx, idy): c - for idy, line in enumerate(input()) - for idx, c in enumerate(line.strip()) -} -start = next(p for p, c in grid.items() if c == "S") -end = next(p for p, c in grid.items() if c == "E") - -times = {} -q = [(start, 0)] -while q: - curr, t = q.pop() - if curr in times: - continue - times[curr] = t - for d in [1, -1, 1j, -1j]: - x = curr + d - if x not in grid or grid[x] == "#": - continue - q.append((x, t + 1)) - - -def cheat(x, y, d): - dist = int(abs(x.real - y.real) + abs(x.imag - y.imag)) - if dist > d: - return False - saved = times[y] - times[x] - dist - return saved >= 100 - - -silver = sum(cheat(x, y, 2) for x in times.keys() for y in times.keys()) -gold = sum(cheat(x, y, 20) for x in times.keys() for y in times.keys()) - - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/21/python.py b/2024/21/python.py deleted file mode 100755 index 5873d65..0000000 --- a/2024/21/python.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from functools import cache - -seqs = [s.strip() for s in input()] - -numpad = { - "0": {"^": "2", ">": "A"}, - "1": {"^": "4", ">": "2"}, - "2": {"^": "5", ">": "3", "v": "0", "<": "1"}, - "3": {"^": "6", "v": "A", "<": "2"}, - "4": {"^": "7", ">": "5", "v": "1"}, - "5": {"^": "8", ">": "6", "v": "2", "<": "4"}, - "6": {"^": "9", "v": "3", "<": "5"}, - "7": {">": "8", "v": "4"}, - "8": {">": "9", "v": "5", "<": "7"}, - "9": {"v": "6", "<": "8"}, - "A": {"^": "3", "<": "0"}, -} -dirpad = { - "^": {">": "A", "v": "v"}, - ">": {"^": "A", "<": "v"}, - "v": {"^": "^", ">": ">", "<": "<"}, - "<": {">": "v"}, - "A": {"v": ">", "<": "^"}, -} - - -silver = 0 -gold = 0 - - -@cache -def move(a, b, n): - pass - - -print(seqs) - -print("silver:", silver) -print("gold:", gold) diff --git a/2024/22/python.py b/2024/22/python.py deleted file mode 100755 index 98d8898..0000000 --- a/2024/22/python.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 - -from collections import Counter, deque -from fileinput import input -from itertools import islice - -lines = [int(line.strip()) for line in input()] - - -def secrets(secret): - x = secret - while True: - yield x - x ^= x << 6 - x &= 0xFFFFFF - x ^= x >> 5 - x &= 0xFFFFFF - x ^= x << 11 - x &= 0xFFFFFF - - -def prices(it): - for s in it: - yield s % 10 - - -def diff(it): - prev = next(it) - for curr in it: - yield curr, curr - prev - prev = curr - - -def to_seqs(it, n=4): - head = map(lambda x: x[1], islice(it, n - 1)) - q = deque(head, maxlen=n) - for price, diff in it: - q.append(diff) - yield price, tuple(q) - - -def seq_sells(it): - sells = {} - for price, diff in it: - if diff in sells: - continue - sells[diff] = price - return sells - - -best_seqs = Counter() -for x in lines: - best_seqs += seq_sells(to_seqs(islice(diff(prices(secrets(x))), 2000))) - -silver = sum(next(islice(secrets(x), 2000, None)) for x in lines) -gold = best_seqs.most_common(1)[0][1] - -print("silver:", silver) -print("gold:", gold) diff --git a/2025/01/c.c b/2025/01/c.c deleted file mode 100644 index 115ea13..0000000 --- a/2025/01/c.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include -#include - -int main() -{ - char dir; - int64_t n; - int64_t p = 50; - int64_t p1 = 0, p2 = 0; - while (scanf("%c%ld ", &dir, &n) == 2) { - int64_t new = p + (dir == 'R' ? n : -n); - p2 += labs(new) / 100 + (p != 0 && new <= 0); - p = (p = new % 100) >= 0 ? p : p + 100; - p1 += p == 0; - } - printf("silver: %ld\ngold: %ld", p1, p2); - return 0; -} diff --git a/2025/01/python.py b/2025/01/python.py deleted file mode 100755 index d5ff1fa..0000000 --- a/2025/01/python.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from itertools import accumulate - - -def fn(p: tuple[int, int], rot: str) -> tuple[int, int]: - x = p[0] + int(rot[1:]) * (1 if rot[0] == "R" else -1) - return x % 100, abs(x) // 100 + (p[0] and x <= 0) - - -p1, p2 = zip(*list(accumulate(input(), fn, initial=(50, 0)))) - -print(f"silver: {sum(not p for p in p1)}") -print(f"gold: {sum(p2)}") diff --git a/2025/01/rust/Cargo.lock b/2025/01/rust/Cargo.lock deleted file mode 100644 index 15ca0d7..0000000 --- a/2025/01/rust/Cargo.lock +++ /dev/null @@ -1,89 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2025-01" -version = "0.1.0" -dependencies = [ - "num", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] diff --git a/2025/01/rust/Cargo.toml b/2025/01/rust/Cargo.toml deleted file mode 100644 index 901af57..0000000 --- a/2025/01/rust/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "aoc_2025-01" -version = "0.1.0" -edition = "2024" - -[dependencies] -num = { version = "0.4.3", features = ["num-bigint"] } diff --git a/2025/01/rust/src/main.rs b/2025/01/rust/src/main.rs deleted file mode 100644 index 72b718b..0000000 --- a/2025/01/rust/src/main.rs +++ /dev/null @@ -1,25 +0,0 @@ -use num::BigUint; -use std::io; - -fn main() { - let mut curr = 50; - let mut silver: u64 = 0; - let mut gold: BigUint = BigUint::ZERO; - io::stdin() - .lines() - .flatten() - .map(|line| match line.split_at(1) { - ("L", n) => -n.parse::().unwrap(), - (_, n) => n.parse::().unwrap(), - }) - .for_each(|n| { - let prev = curr; - curr += n; - gold += (curr.abs() / 100) as u64 + (prev != 0 && curr <= 0) as u64; - curr = curr.rem_euclid(100); - silver += (curr == 0) as u64; - }); - - println!("silver: {silver}"); - println!("gold: {gold}"); -} diff --git a/2025/02/python.py b/2025/02/python.py deleted file mode 100755 index a3b4d1e..0000000 --- a/2025/02/python.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 - - -from itertools import accumulate -from bisect import bisect_left, bisect_right -from functools import cache - -rs = [(int(a), int(b)) for r in input().split(",") for [a, b] in [r.split("-")]] -N = max(len(str(x)) for r in rs for x in r) - - -@cache -def memo(p2: bool): - ids = sorted( - { - int(str(n) * reps) - for n in range(10 ** (N // 2)) - for reps in range(2, N // len(str(n)) + 1 if p2 else 3) - } - ) - sums = list(accumulate(ids)) - return ids[1:], sums - - -def prefix_sum(a: int, b: int, ids: list[int], sums: list[int]): - return sums[bisect_right(ids, b)] - sums[bisect_left(ids, a)] - - -silver = sum(prefix_sum(*r, *memo(False)) for r in rs) -gold = sum(prefix_sum(*r, *memo(True)) for r in rs) - -print("silver:", silver) -print("gold:", gold) diff --git a/2025/03/python.py b/2025/03/python.py deleted file mode 100755 index b0d4bfd..0000000 --- a/2025/03/python.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -lines = [[int(b) for b in line.strip()] for line in input()] - - -def jolt(bs: list[int], n: int) -> int: - if n == 1: - return max(bs) - n -= 1 - b = max(bs[:-n]) - i = bs.index(b) - return b * (10**n) + jolt(bs[i + 1 :], n) - - -silver = sum(jolt(bs, 2) for bs in lines) -gold = sum(jolt(bs, 12) for bs in lines) - -print("silver:", silver) -print("gold:", gold) diff --git a/2025/03/rust/Cargo.lock b/2025/03/rust/Cargo.lock deleted file mode 100644 index 7f2fe0f..0000000 --- a/2025/03/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2025-03" -version = "0.1.0" diff --git a/2025/03/rust/Cargo.toml b/2025/03/rust/Cargo.toml deleted file mode 100644 index c0441da..0000000 --- a/2025/03/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2025-03" -version = "0.1.0" -edition = "2024" - -[dependencies] diff --git a/2025/03/rust/src/main.rs b/2025/03/rust/src/main.rs deleted file mode 100644 index be0b3e6..0000000 --- a/2025/03/rust/src/main.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::io; - -fn max(bs: &Vec, start: usize, end: usize) -> (u8, usize) { - let mut bests = [None; 10]; - for idx in start..=end { - if bs[idx] == 9 { - return (9, idx); - } - bests[bs[idx] as usize].get_or_insert((bs[idx], idx)); - } - bests.into_iter().flatten().last().unwrap() -} - -fn jolt(bs: &Vec, n: usize) -> u64 { - let mut j: u64 = 0; - let mut start = 0; - for n in (1..=n).rev() { - j *= 10; - let (b, idx) = max(bs, start, bs.len() - n); - j += b as u64; - start = idx + 1; - } - j -} - -fn main() { - let (silver, gold) = io::stdin() - .lines() - .flatten() - .map(|line| { - line.into_bytes() - .iter() - .map(|&x| x - b'0') - .collect::>() - }) - .map(|bs| (jolt(&bs, 2), jolt(&bs, 12))) - .reduce(|(a0, a1), (x0, x1)| (a0 + x0, a1 + x1)) - .unwrap(); - - println!("silver: {silver}"); - println!("gold: {gold}"); -} diff --git a/2025/04/python.py b/2025/04/python.py deleted file mode 100755 index 844c38e..0000000 --- a/2025/04/python.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -g = { - complex(x, y): ch - for y, line in enumerate(input()) - for x, ch in enumerate(line.strip()) -} - - -def accessible(): - return { - p - for p, x in g.items() - if x == "@" - and sum( - 1 - for dx in (-1, 0, 1) - for dy in (-1j, 0j, 1j) - if dx + dy != 0 and g.get(p + dx + dy, ".") == "@" - ) - < 4 - } - - -silver = len(accessible()) -gold = 0 - -while rem := accessible(): - gold += len(rem) - for gone in rem: - g.pop(gone) - -print("silver:", silver) -print("gold:", gold) diff --git a/2025/04/rust/Cargo.lock b/2025/04/rust/Cargo.lock deleted file mode 100644 index 222070d..0000000 --- a/2025/04/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2025-04" -version = "0.1.0" diff --git a/2025/04/rust/Cargo.toml b/2025/04/rust/Cargo.toml deleted file mode 100644 index b29e6d6..0000000 --- a/2025/04/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2025-04" -version = "0.1.0" -edition = "2024" - -[dependencies] diff --git a/2025/04/rust/src/main.rs b/2025/04/rust/src/main.rs deleted file mode 100644 index 3b13140..0000000 --- a/2025/04/rust/src/main.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::{collections::VecDeque, io}; - -fn main() { - let mut grid: Vec>> = io::stdin() - .lines() - .flatten() - .map(|line| line.chars().map(|ch| (ch == '@').then_some(0)).collect()) - .collect(); - - // count neighbours - points(&grid) - .collect::>() - .into_iter() - .for_each(|p @ (x, y)| { - let ns = neighbours(p, &grid).count(); - if let Some(n) = grid[y][x].as_mut() { - *n = ns; - } - }); - - let mut stack = points(&grid) - .filter(|&(x, y)| grid[y][x].is_some_and(|n| n < 4)) - .collect::>(); - let silver = stack.len(); - let mut gold = 0; - - while let Some(p @ (x, y)) = stack.pop_back() { - if grid[y][x].take().is_none() { - continue; - } - gold += 1; - // reduce neighbours' neighbour counts by 1 - neighbours(p, &grid) - .collect::>() - .into_iter() - .for_each(|(nx, ny)| { - if let Some(n) = grid[ny][nx].as_mut() { - *n -= 1; - if *n < 4 { - stack.push_back((nx, ny)) - } - } - }); - } - - println!("silver: {silver}"); - println!("gold: {gold}"); -} - -fn neighbours( - (x, y): (usize, usize), - grid: &Vec>>, -) -> impl Iterator { - let xs = x.saturating_sub(1)..=(x + 1).min(grid.first().unwrap().len() - 1); - let ys = y.saturating_sub(1)..=(y + 1).min(grid.len() - 1); - - xs.flat_map(move |nx| ys.clone().map(move |ny| (nx, ny))) - .filter(move |n| *n != (x, y)) - .filter(|&(nx, ny)| grid.get(ny).and_then(|row| row.get(nx)).unwrap().is_some()) -} - -fn points(grid: &Vec>) -> impl Iterator { - let xs = 0..grid.first().unwrap().len(); - let ys = 0..grid.len(); - xs.flat_map(move |x| ys.clone().map(move |y| (x, y))) -} diff --git a/2025/05/python.py b/2025/05/python.py deleted file mode 100755 index 9977623..0000000 --- a/2025/05/python.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 - -from itertools import takewhile -from fileinput import input - - -inp = map(str.strip, input()) -rs = [tuple(map(int, r.split("-"))) for r in takewhile(bool, inp)] -ids = list(map(int, inp)) - - -def add(a: int, b: int, c: int, d: int) -> tuple[int, int] | None: - if c < a: - return add(c, d, a, b) - if b < c: - return None - return (a, max(b, d)) - - -done = False -while not done: - ms = [] - for r in rs: - for idx, m in enumerate(ms): - if new := add(*r, *m): - ms[idx] = new - break - - else: - ms.append(r) - done = len(rs) == len(ms) - rs = ms - - -silver = sum(1 for i in ids if any(lo <= i <= hi for lo, hi in rs)) -gold = sum(b - a + 1 for a, b in rs) - -print("silver:", silver) -print("gold:", gold) diff --git a/2025/05/rust/Cargo.lock b/2025/05/rust/Cargo.lock deleted file mode 100644 index 0d1bf4e..0000000 --- a/2025/05/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2025-05" -version = "0.1.0" diff --git a/2025/05/rust/Cargo.toml b/2025/05/rust/Cargo.toml deleted file mode 100644 index e85826e..0000000 --- a/2025/05/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2025-05" -version = "0.1.0" -edition = "2024" - -[dependencies] diff --git a/2025/05/rust/src/main.rs b/2025/05/rust/src/main.rs deleted file mode 100644 index cd78338..0000000 --- a/2025/05/rust/src/main.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::io; - -fn main() { - let mut input = io::stdin().lines().flatten().map(|line| line); - let ranges = input.by_ref().take_while(|s| !s.is_empty()).map(|s| { - let (lo, hi) = s.split_once('-').unwrap(); - ( - lo.to_owned().parse().unwrap(), - hi.to_owned().parse().unwrap(), - ) - }); - - let mut merged: Vec<(u64, u64)> = vec![]; - for (mut lo, mut hi) in ranges { - let ldx = merged.partition_point(|&(_, max)| max < lo); - let mut rdx = merged.partition_point(|&(_, max)| max < hi); - - let left = merged.get(ldx); - let right = merged.get(rdx); - - // ldx = merged.len() -> left is none -> insert at end - let Some(&(llo, lhi)) = left else { - merged.push((lo, hi)); - continue; - }; - - if (llo..=lhi).contains(&lo) { - lo = lo.min(llo); // include range start point - } - - // rdx = merged.len() -> right is none -> merge with all - let Some(&(rlo, rhi)) = right else { - merged.drain(ldx..); - merged.push((lo, hi)); - continue; - }; - - if (rlo..=rhi).contains(&hi) { - hi = hi.max(rhi); - rdx += 1; - } - - merged.drain(ldx..rdx); - merged.insert(ldx, (lo, hi)); - } - - let silver = input - .map(|n| n.parse::().unwrap()) - .filter(|id| merged.iter().any(|&(lo, hi)| (lo..=hi).contains(id))) - .count(); - let gold: u64 = merged.iter().map(|(lo, hi)| hi - lo + 1).sum(); - - println!("silver: {silver}"); - println!("gold: {gold}"); -} diff --git a/2025/06/python.py b/2025/06/python.py deleted file mode 100755 index 4c57829..0000000 --- a/2025/06/python.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 - -from math import prod -from fileinput import input -from itertools import takewhile, repeat - -*nums, ops = [line.strip("\n") for line in input()] -ops = [prod if op == "*" else sum for op in ops.split()] - -horizontal = [map(int, row.split()) for row in nums] -silver = sum(op(chunk) for op, chunk in zip(ops, zip(*horizontal))) - -vertical = ("".join(ds).strip() for ds in [*zip(*nums)]) -chunks = repeat(lambda: [*map(int, takewhile(bool, vertical))]) -gold = sum(op(chunk()) for op, chunk in zip(ops, chunks)) - -print("silver:", silver) -print("gold:", gold) diff --git a/2025/07/python.py b/2025/07/python.py deleted file mode 100755 index 639c368..0000000 --- a/2025/07/python.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from functools import cache - -lines = [line.strip() for line in input()] -start = lines[0].index("S") - -silver = 0 -bs = {start} -for line in lines: - for b in bs.copy(): - if line[b] == "^": - silver += 1 - bs -= {b} - bs |= {b - 1, b + 1} - - -@cache -def tls(r: int, c: int) -> int: - if r == len(lines): - return 1 - if lines[r][c] == "^": - return tls(r, c - 1) + tls(r, c + 1) - return tls(r + 1, c) - - -gold = tls(0, start) - -print("silver:", silver) -print("gold:", gold) diff --git a/2025/08/python.py b/2025/08/python.py deleted file mode 100755 index 98a4725..0000000 --- a/2025/08/python.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from math import dist, prod -from operator import itemgetter - -MAX_CONNS = 1000 # test: 10, input: 1000 - -boxes = [[*map(int, line.split(","))] for line in input()] -N = len(boxes) - -js = {n: {n} for n in range(N)} -conns = sorted( - ((x, y) for x in range(N) for y in range(x)), - key=lambda t: dist(*itemgetter(*t)(boxes)), -) - -for n, (x, y) in enumerate(conns): - if n == MAX_CONNS: - lens = {id(j): len(j) for j in js.values()}.values() - print("silver:", prod(sorted(lens, reverse=True)[:3])) - - j = js[x] | js[y] - for b in j: - js[b] = j - - if len(j) == N: - print("gold:", boxes[x][0] * boxes[y][0]) - break diff --git a/2025/09/python.py b/2025/09/python.py deleted file mode 100755 index 6c4df6c..0000000 --- a/2025/09/python.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input - -pts = [[*map(int, line.split(","))] for line in input()] - -silver = max( - (abs(x1 - x2) + 1) * (abs(y1 - y2) + 1) for (x1, y1) in pts for (x2, y2) in pts -) -gold = 0 - -print("silver:", silver) -print("gold:", gold) diff --git a/2025/09/rust/Cargo.lock b/2025/09/rust/Cargo.lock deleted file mode 100644 index 1a33f1f..0000000 --- a/2025/09/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2025-09" -version = "0.1.0" diff --git a/2025/09/rust/Cargo.toml b/2025/09/rust/Cargo.toml deleted file mode 100644 index a713c42..0000000 --- a/2025/09/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2025-09" -version = "0.1.0" -edition = "2024" - -[dependencies] diff --git a/2025/09/rust/src/main.rs b/2025/09/rust/src/main.rs deleted file mode 100644 index 32847e3..0000000 --- a/2025/09/rust/src/main.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::io; - -#[derive(Debug)] -struct Floor { - x_comp: Vec, - y_comp: Vec, -} - -impl Floor { - fn new(pts: Vec<(usize, usize)>) -> (Self, Vec<(usize, usize)>) { - let (mut xs, mut ys): (Vec<_>, Vec<_>) = pts.clone().into_iter().unzip(); - xs.sort_unstable(); - xs.dedup(); - ys.sort_unstable(); - ys.dedup(); - - let pts = pts - .into_iter() - .map(|(x, y)| (xs.binary_search(&x).unwrap(), ys.binary_search(&y).unwrap())) - .collect(); - - ( - Self { - x_comp: xs, - y_comp: ys, - }, - pts, - ) - } - - fn uncomp(&self, (x, y): (usize, usize)) -> (usize, usize) { - (self.x_comp[x], self.y_comp[y]) - } - - fn area(&self, (p1, p2): ((usize, usize), (usize, usize))) -> usize { - let (x1, y1) = self.uncomp(p1); - let (x2, y2) = self.uncomp(p2); - (x1.abs_diff(x2) + 1) * (y1.abs_diff(y2) + 1) - } -} - -fn main() { - let pts = io::stdin() - .lines() - .flatten() - .map(|line| { - let (x, y) = line.split_once(',').unwrap(); - (x.parse().unwrap(), y.parse().unwrap()) - }) - .collect::>(); - - let (floor, pts) = Floor::new(pts); - - let xmax = *pts.iter().map(|(x, _)| x).max().unwrap(); - let ymax = *pts.iter().map(|(_, y)| y).max().unwrap(); - - // some padding so that flood fill works correctly - let mut grid: Vec>> = vec![vec![None; xmax + 3]; ymax + 3]; - - // draw green/red tiles - for pair in [vec![*pts.last().unwrap()], pts.clone()] - .concat() - .windows(2) - { - let (x1, y1) = pair[0]; - let (x2, y2) = pair[1]; - (x1.min(x2)..=x1.max(x2)).for_each(|x| { - (y1.min(y2)..=(y1.max(y2))).for_each(|y| grid[y + 1][x + 1] = Some(true)) - }); - } - - // flood fill from top left - let mut q = vec![(0, 0)]; - while let Some((x, y)) = q.pop() { - grid[y][x] = Some(false); - let ns = vec![ - (x.saturating_sub(1), y), - ((x + 1).min(xmax + 2), y), - (x, y.saturating_sub(1)), - (x, (y + 1).min(ymax + 2)), - ]; - q.extend(ns.into_iter().filter(|&(x, y)| grid[y][x].is_none())); - } - - // replace inside cells with Some(true) and undo the padding - let grid: Vec> = grid - .into_iter() - .skip(1) - .map(|r| r.into_iter().skip(1).map(|c| c.unwrap_or(true)).collect()) - .collect(); - - let mut rectangles = pts - .iter() - .enumerate() - .flat_map(|(idx, p1)| pts.iter().take(idx).map(move |p2| (*p1, *p2))) - .collect::>(); - rectangles.sort_unstable_by_key(|&r| std::cmp::Reverse(floor.area(r))); - - let silver: usize = floor.area(*rectangles.first().unwrap()); - let gold: usize = floor.area( - *rectangles - .iter() - .filter(|&&((x1, y1), (x2, y2))| { - (x1.min(x2)..=x1.max(x2)) - .flat_map(|x| (y1.min(y2)..=y1.max(y2)).map(move |y| (x, y))) - .all(|(x, y)| grid[y][x]) - }) - .next() - .unwrap(), - ); - println!("silver: {silver}"); - println!("gold: {gold}"); -} diff --git a/2025/10/rust/Cargo.lock b/2025/10/rust/Cargo.lock deleted file mode 100644 index fcb9609..0000000 --- a/2025/10/rust/Cargo.lock +++ /dev/null @@ -1,155 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2025-10" -version = "0.1.0" -dependencies = [ - "good_lp", - "itertools", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "good_lp" -version = "1.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "776aa1ba88ac058e78408c17f4dbff826a51ae08ed6642f71ca0edd7fe9383f3" -dependencies = [ - "fnv", - "microlp", -] - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "matrixmultiply" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" -dependencies = [ - "autocfg", - "rawpointer", -] - -[[package]] -name = "microlp" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d1790c73b93164ff65868f63164497cb32339458a9297e17e212d91df62258" -dependencies = [ - "log", - "sprs", -] - -[[package]] -name = "ndarray" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" -dependencies = [ - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "portable-atomic", - "portable-atomic-util", - "rawpointer", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "sprs" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dca58a33be2188d4edc71534f8bafa826e787cc28ca1c47f31be3423f0d6e55" -dependencies = [ - "ndarray", - "num-complex", - "num-traits", - "smallvec", -] diff --git a/2025/10/rust/Cargo.toml b/2025/10/rust/Cargo.toml deleted file mode 100644 index 20ee505..0000000 --- a/2025/10/rust/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "aoc_2025-10" -version = "0.1.0" -edition = "2024" - -[dependencies] -good_lp = { version = "1.14.2", features = ["microlp"], default-features = false } -itertools = "0.14.0" diff --git a/2025/10/rust/src/main.rs b/2025/10/rust/src/main.rs deleted file mode 100644 index b0cd6ed..0000000 --- a/2025/10/rust/src/main.rs +++ /dev/null @@ -1,68 +0,0 @@ -use good_lp::*; -use itertools::Itertools; -use std::io; - -fn main() { - let ms = io::stdin() - .lines() - .flatten() - .map(|line| { - let mut iter = line.split_whitespace(); - let p1 = iter - .next() - .unwrap() - .chars() - .filter_map(|ch| match ch { - '.' => Some(0), - '#' => Some(1), - _ => None, - }) - .collect::>(); - - let mut iter = iter.map(|s| { - s.split(|ch: char| ch.is_ascii_punctuation()) - .filter_map(|n| n.parse().ok()) - .collect::>() - }); - let p2 = iter.next_back().unwrap(); - let bs = iter.collect::>(); - (p1, p2, bs) - }) - .collect::>(); - - let silver: usize = ms.iter().map(|(want, _, bs)| solve_p1(&want, &bs)).sum(); - let gold: usize = ms.iter().map(|(_, want, bs)| solve_p2(&want, &bs)).sum(); - println!("silver: {silver}"); - println!("gold: {gold}"); -} - -fn solve_p1(want: &Vec, bs: &Vec>) -> usize { - bs.into_iter() - .powerset() - .map(|sub| (sub.len(), sub.into_iter().flatten().counts())) - .filter(|(_, counts)| { - want.iter() - .enumerate() - .all(|(n, w)| counts.get(&(n as u32)).unwrap_or(&0) % 2 == *w as usize) - }) - .next() - .unwrap() - .0 -} - -fn solve_p2(want: &Vec, bs: &Vec>) -> usize { - variables! {vars: 0 <= xs[bs.len()] (integer);} - let obj: Expression = xs.iter().sum(); - let mut model = vars.minimise(&obj).using(default_solver); - for (n, w) in want.iter().enumerate() { - let xsum: Expression = bs - .iter() - .enumerate() - .filter(|&(_, b)| b.contains(&(n as u32))) - .map(|(x, _)| xs[x]) - .sum(); - model = model.with(constraint!(xsum == *w)); - } - - model.solve().unwrap().eval(&obj).round() as usize -} diff --git a/2025/11/rust/Cargo.lock b/2025/11/rust/Cargo.lock deleted file mode 100644 index ab53f99..0000000 --- a/2025/11/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aoc_2025-11" -version = "0.1.0" diff --git a/2025/11/rust/Cargo.toml b/2025/11/rust/Cargo.toml deleted file mode 100644 index 9fbcc03..0000000 --- a/2025/11/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "aoc_2025-11" -version = "0.1.0" -edition = "2024" - -[dependencies] diff --git a/2025/11/rust/src/main.rs b/2025/11/rust/src/main.rs deleted file mode 100644 index 522d7ad..0000000 --- a/2025/11/rust/src/main.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::{cell::RefCell, collections::HashMap, io, rc::Rc}; - -#[derive(PartialEq, Eq, Hash, Debug)] -struct Node { - device: String, - dac: bool, - fft: bool, -} - -fn main() { - let adj = io::stdin() - .lines() - .flatten() - .map(|line| { - let (k, v) = line.split_once(": ").unwrap(); - ( - String::from(k), - String::from(v) - .split_whitespace() - .map(String::from) - .collect(), - ) - }) - .collect::>>(); - - let cache = Rc::new(RefCell::new(HashMap::new())); - - let silver = paths_from( - Node { - device: String::from("you"), - dac: true, - fft: true, - }, - &adj, - Rc::clone(&cache), - ); - let gold = paths_from( - Node { - device: String::from("svr"), - dac: false, - fft: false, - }, - &adj, - Rc::clone(&cache), - ); - - println!("silver: {silver}"); - println!("gold: {gold}"); -} - -fn paths_from( - curr: Node, - adj: &HashMap>, - cache: Rc>>, -) -> usize { - if curr.device == "out" { - if curr.dac && curr.fft { - return 1; - } - return 0; - } - - let Some(&v) = cache.borrow().get(&curr) else { - let paths = adj - .get(&curr.device) - .unwrap() - .iter() - .map(|n| { - paths_from( - Node { - device: n.clone(), - dac: curr.dac || curr.device == "dac", - fft: curr.fft || curr.device == "fft", - }, - adj, - Rc::clone(&cache), - ) - }) - .sum(); - cache.borrow_mut().insert(curr, paths); - return paths; - }; - return v; -} diff --git a/2025/12/python.py b/2025/12/python.py deleted file mode 100755 index c3b5158..0000000 --- a/2025/12/python.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 - -from fileinput import input -from itertools import takewhile - - -def check(s: str): - return eval(s.replace(": ", ">=9*(").replace("x", "*").replace(" ", "+") + ")") - - -silver = sum( - map( - check, - takewhile( - bool, - [line.strip() for line in input()][::-1], - ), - ) -) - -print("silver:", silver) diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f288702..0000000 --- a/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/aoc/2024/01/python.py b/aoc/2024/01/python.py new file mode 100755 index 0000000..425f6c7 --- /dev/null +++ b/aoc/2024/01/python.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +from collections import Counter +from fileinput import input + +L, R = zip(*[[int(n) for n in s.split()] for s in input()]) + +silver = sum(abs(left - right) for left, right in zip(sorted(L), sorted(R))) + +L, R = Counter(L), Counter(R) +gold = sum(n * L[n] * R[n] for n in list(L & R)) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/01/raku.raku b/aoc/2024/01/raku.raku new file mode 100755 index 0000000..c4a44e0 --- /dev/null +++ b/aoc/2024/01/raku.raku @@ -0,0 +1,5 @@ +#!/usr/bin/env raku + +my $ids := ([Z] lines>>.words)>>.sort>>.list; +say "silver: ", ([Z-] $ids)>>.abs.sum; +say "gold: ", ([<<*>>] $ids>>.Bag).kxxv.sum; diff --git a/aoc/2024/01/rust/Cargo.lock b/aoc/2024/01/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/01/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/01/rust/Cargo.toml b/aoc/2024/01/rust/Cargo.toml new file mode 100644 index 0000000..88e7b42 --- /dev/null +++ b/aoc/2024/01/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/aoc/2024/01/rust/src/main.rs b/aoc/2024/01/rust/src/main.rs new file mode 100644 index 0000000..c1648cf --- /dev/null +++ b/aoc/2024/01/rust/src/main.rs @@ -0,0 +1,31 @@ +use std::collections::HashMap; +use std::io; + +fn main() -> io::Result<()> { + let (mut ls, mut rs): (Vec, Vec) = io::stdin() + .lines() + .map(|line| { + line.unwrap() + .split_whitespace() + .map(|s| s.parse().unwrap()) + .collect::>() + }) + .map(|xs| (xs[0], xs[1])) + .unzip(); + + ls.sort_unstable(); + rs.sort_unstable(); + + let mut counts = HashMap::new(); + rs.iter().for_each(|&x| { + *counts.entry(x).or_insert(0) += 1; + }); + + let silver: u64 = ls.iter().zip(rs).map(|(x, y)| x.abs_diff(y)).sum(); + let gold: u64 = ls.iter().map(|x| x * counts.get(x).unwrap_or(&0)).sum(); + + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} diff --git a/aoc/2024/02/python.py b/aoc/2024/02/python.py new file mode 100755 index 0000000..f2c807d --- /dev/null +++ b/aoc/2024/02/python.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +from fileinput import input + +reports = [[int(level) for level in report.split()] for report in input()] + + +def incr(xs): + return all(x < y and y - x <= 3 for x, y in zip(xs, xs[1:])) + + +def safe(xs): + return incr(xs) or incr(xs[::-1]) + + +def drops(xs): + return (xs[:idx] + xs[idx + 1 :] for idx, _ in enumerate(xs)) + + +silver = sum(safe(rep) for rep in reports) +gold = sum(any(safe(mod) for mod in drops(rep)) for rep in reports) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/02/raku.raku b/aoc/2024/02/raku.raku new file mode 100755 index 0000000..9b930de --- /dev/null +++ b/aoc/2024/02/raku.raku @@ -0,0 +1,9 @@ +#!/usr/bin/env raku + +my @rs = lines>>.words.map(&cache); + +sub incr ($r) { $r.rotor(2=>-1).map({ ([-] $_) (elem) (1..3)}).all }; +sub safe ($r) { so $r.&incr || $r.reverse.&incr }; + +say "silver: ", @rs.map(&safe).sum; +say "gold: ", @rs.map({ $_.combinations($_-1).map(&safe).any.so }).sum; diff --git a/aoc/2024/02/rust/Cargo.lock b/aoc/2024/02/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/02/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/02/rust/Cargo.toml b/aoc/2024/02/rust/Cargo.toml new file mode 100644 index 0000000..88e7b42 --- /dev/null +++ b/aoc/2024/02/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/aoc/2024/02/rust/src/main.rs b/aoc/2024/02/rust/src/main.rs new file mode 100644 index 0000000..2007837 --- /dev/null +++ b/aoc/2024/02/rust/src/main.rs @@ -0,0 +1,33 @@ +#![feature(iter_map_windows)] + +use std::io; + +fn main() { + let input: Vec> = io::stdin() + .lines() + .map(|line| { + line.unwrap() + .split_whitespace() + .map(str::parse::) + .collect() + }) + .collect::, _>>() + .unwrap(); + + let silver: usize = input.iter().filter(|&xs| all_safe(xs)).count(); + let gold: usize = input.iter().filter(|&xs| drop_safe(xs)).count(); + println!("silver: {silver}"); + println!("gold: {gold}"); +} + +fn all_safe(xs: &Vec) -> bool { + let mut diffs = xs.iter().map_windows(|&[x, y]| y - x).peekable(); + let dir = diffs.peek().unwrap_or(&1).signum(); + diffs.all(|d| (1..=3).contains(&d.abs()) && d.signum() == dir) +} + +fn drop_safe(xs: &Vec) -> bool { + (0..xs.len()) + .map(|idx| xs.split_at(idx)) + .any(|(left, right)| all_safe(&[left, &right[1..]].concat())) +} diff --git a/aoc/2024/03/python.py b/aoc/2024/03/python.py new file mode 100755 index 0000000..f456580 --- /dev/null +++ b/aoc/2024/03/python.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import re +from fileinput import input + +s = "\n".join(input()) + +silver = sum(int(x) * int(y) for x, y in re.findall(r"mul\((\d{1,3}),(\d{1,3})\)", s)) + +gold = 0 +active = True +for g in re.findall(r"(?:mul\((\d{1,3}),(\d{1,3})\))|(don't\(\))|(do\(\))", s): + match g, active: + case (x, y, "", ""), True: + gold += int(x) * int(y) + case (_, _, "don't()", _), _: + active = False + case (_, _, _, "do()"), _: + active = True + + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/03/raku.raku b/aoc/2024/03/raku.raku new file mode 100755 index 0000000..38f040e --- /dev/null +++ b/aoc/2024/03/raku.raku @@ -0,0 +1,17 @@ +#!/usr/bin/env raku + +my $p = slurp; + +sub p2 (($on, $tot), ($i, |n)) { + given $i { + when "mul" { return ($on , $tot + [*] $on, |n.list) } + when "do" { return (1 , $tot) } + when "don't" { return (0 , $tot) } + } +}; + +$p ~~ m:g/ mul\((\d ** 1..3)\,(\d ** 1..3)\) /; +say "silver: ", $/.map({ [*] $_.list }).sum; + +$p ~~ m:g/ (mul)\((\d ** 1..3)\,(\d ** 1..3)\) | (do)\(\) | (don\'t)\(\) /; +say "gold: ", ([[&p2]] <1 0>, |$/)[1]; diff --git a/aoc/2024/03/rust/Cargo.lock b/aoc/2024/03/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/03/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/03/rust/Cargo.toml b/aoc/2024/03/rust/Cargo.toml new file mode 100644 index 0000000..5a7c59b --- /dev/null +++ b/aoc/2024/03/rust/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" diff --git a/aoc/2024/03/rust/src/main.rs b/aoc/2024/03/rust/src/main.rs new file mode 100644 index 0000000..b268463 --- /dev/null +++ b/aoc/2024/03/rust/src/main.rs @@ -0,0 +1,68 @@ +use std::io::{self, Read}; + +#[derive(Debug)] +enum Instruction { + Do, + Dont, + Mul(u64, u64), +} + +impl From<&Instruction> for u64 { + fn from(val: &Instruction) -> Self { + match val { + Instruction::Mul(x, y) => x * y, + _ => 0, + } + } +} + +fn main() -> io::Result<()> { + let mut program = String::new(); + io::stdin().read_to_string(&mut program)?; + + let instrs = (0..program.len()) + .filter_map(|idx| { + let next = &program[idx..]; + if next.starts_with("do()") { + Some(Instruction::Do) + } else if next.starts_with("don't()") { + Some(Instruction::Dont) + } else if next.starts_with("mul(") { + let mut first = 0; + let mut curr = 0; + + for ch in next.bytes().skip(4) { + match (ch, curr) { + ((b'0'..=b'9'), _) => curr = curr * 10 + (ch - b'0') as u64, + (_, 0) => return None, + (b',', _) => { + first = curr; + curr = 0; + } + (b')', _) => { + return Some(Instruction::Mul(first, curr)); + } + _ => return None, + }; + } + None + } else { + None + } + }) + .collect::>(); + + let silver: u64 = instrs.iter().map(u64::from).sum(); + let (gold, _) = instrs + .iter() + .fold((0 as u64, true), |(acc, on), instr| match (instr, on) { + (Instruction::Do, _) => (acc, true), + (Instruction::Dont, _) => (acc, false), + (Instruction::Mul(_, _), true) => (acc + u64::from(instr), true), + _ => (acc, on), + }); + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} diff --git a/aoc/2024/04/python.py b/aoc/2024/04/python.py new file mode 100755 index 0000000..fe5021b --- /dev/null +++ b/aoc/2024/04/python.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +from fileinput import input + +grid = { + complex(idx, idy): c + for idy, line in enumerate(input()) + for idx, c in enumerate(line.strip()) +} +dirs = {complex(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1]} + + +def xmas(x, v): + return all(grid.get(x + n * v) == c for n, c in enumerate("XMAS")) + + +def x_mas(x, v): + return ( + grid.get(x) == "A" + and grid.get(x + v) == grid.get(x + 1j * v) == "M" + and grid.get(x - v) == grid.get(x - 1j * v) == "S" + ) + + +silver = sum(xmas(x, v) for x in grid.keys() for v in dirs) +gold = sum(x_mas(x, v) for x in grid.keys() for v in dirs if abs(v) > 1) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/04/raku.raku b/aoc/2024/04/raku.raku new file mode 100755 index 0000000..6055fe4 --- /dev/null +++ b/aoc/2024/04/raku.raku @@ -0,0 +1,8 @@ +#!/usr/bin/env raku + +my @g = lines.map: *.comb.Array; + +@g.map: *.say; +say "---"; + +say @g[.[0]; .[1] .. .[1]+3] for (^@g X ^@g[0])[^4]; diff --git a/aoc/2024/04/rust/Cargo.lock b/aoc/2024/04/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/04/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/04/rust/Cargo.toml b/aoc/2024/04/rust/Cargo.toml new file mode 100644 index 0000000..5a7c59b --- /dev/null +++ b/aoc/2024/04/rust/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" diff --git a/aoc/2024/04/rust/src/main.rs b/aoc/2024/04/rust/src/main.rs new file mode 100644 index 0000000..191e461 --- /dev/null +++ b/aoc/2024/04/rust/src/main.rs @@ -0,0 +1,82 @@ +use std::io; + +fn main() -> io::Result<()> { + let grid = io::stdin() + .lines() + .flatten() + .map(|line| line.chars().collect()) + .collect::>>(); + let grid = Grid(grid); + + let silver: usize = silver(&grid); + let gold: usize = gold(&grid); + + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} + +struct Grid(Vec>); + +impl Grid { + fn at(&self, (x, y): (isize, isize)) -> Option<&char> { + self.0 + .get(usize::try_from(y).ok()?)? + .get(usize::try_from(x).ok()?) + } + + fn check<'a>( + &self, + (x, y): (isize, isize), + mut pat: impl Iterator, + ) -> bool { + pat.all(|((dx, dy), ch)| self.at((x + dx, y + dy)).is_some_and(|c| c == ch)) + } + + fn pts(&self) -> impl Iterator + use<'_> { + (0..self.0[0].len()).flat_map(|x| (0..self.0.len()).map(move |y| (x as isize, y as isize))) + } +} + +fn silver(grid: &Grid) -> usize { + let dirs = vec![ + (-1, -1), + (-1, 0), + (-1, 1), + (0, -1), + (0, 1), + (1, -1), + (1, 0), + (1, 1), + ]; + + let xmases: Vec> = dirs + .iter() + .map(|(dx, dy)| { + (0..4) + .map(move |n| (dx * n, dy * n)) + .zip("XMAS".chars()) + .collect() + }) + .collect(); + + grid.pts() + .flat_map(|p| xmases.iter().map(move |xmas| grid.check(p, xmas.iter()))) + .filter(|p| *p) + .count() +} + +fn gold(grid: &Grid) -> usize { + let dirs = vec![(-1, -1), (1, -1), (0, 0), (-1, 1), (1, 1)]; + + let xmases: Vec> = vec!["MMASS", "SMASM", "SSAMM", "MSAMS"] + .iter() + .map(|x| dirs.clone().into_iter().zip(x.chars()).collect()) + .collect(); + + grid.pts() + .flat_map(|p| xmases.iter().map(move |xmas| grid.check(p, xmas.iter()))) + .filter(|p| *p) + .count() +} diff --git a/aoc/2024/05/python.py b/aoc/2024/05/python.py new file mode 100755 index 0000000..9e81978 --- /dev/null +++ b/aoc/2024/05/python.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +from fileinput import input +from functools import cmp_to_key +from itertools import takewhile + +inp = map(str.strip, input()) +ordering = set(takewhile(bool, inp)) +us = list(inp) + + +def cmp(x, y): + return (f"{y}|{x}" in ordering) * 2 - 1 # hehe + + +silver = 0 +gold = 0 + +for u in us: + pre = u.split(",") + post = list(sorted(pre, key=cmp_to_key(cmp))) + + mid = int(post[len(post) // 2]) + if pre == post: + silver += mid + else: + gold += mid + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/05/raku.raku b/aoc/2024/05/raku.raku new file mode 100755 index 0000000..a13cf5a --- /dev/null +++ b/aoc/2024/05/raku.raku @@ -0,0 +1,10 @@ +#!/usr/bin/env raku + +my (@rs, @us) := slurp.split("\n\n")>>.lines; + +sub mid(@u) { + my @s = @u.sort({ "$^a|$^b" !(elem) @rs }); + return (@u Z== @s).all.so ?? ($_, 0) !! (0, $_) with @s[@s/2]; +} + +(("silver: ", "gold: ") Z~ [Z+] @us>>.split(",").map(&mid)).map(&say); diff --git a/aoc/2024/05/rust/Cargo.lock b/aoc/2024/05/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/05/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/05/rust/Cargo.toml b/aoc/2024/05/rust/Cargo.toml new file mode 100644 index 0000000..88e7b42 --- /dev/null +++ b/aoc/2024/05/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/aoc/2024/05/rust/src/main.rs b/aoc/2024/05/rust/src/main.rs new file mode 100644 index 0000000..0db788d --- /dev/null +++ b/aoc/2024/05/rust/src/main.rs @@ -0,0 +1,42 @@ +#![feature(slice_split_once)] + +use std::cmp::Ordering::{Greater, Less}; +use std::collections::HashSet; +use std::io; + +fn main() -> io::Result<()> { + let mut lines = io::stdin().lines().flatten(); + let mut set = HashSet::<(u16, u16)>::new(); + + while let Some(s) = lines.next() { + if let Some((a, b)) = s.split_once('|') { + set.insert((a.parse().unwrap(), b.parse().unwrap())); + } else { + break; + } + } + + let mut silver: usize = 0; + let mut gold: usize = 0; + + for line in lines { + let mut nums: Vec = line.split(',').map(|n| n.parse().unwrap()).collect(); + let mid = nums.len() / 2; + + if nums.is_sorted_by(|&a, &b| set.contains(&(a, b))) { + silver += nums[mid] as usize; + } else { + gold += *nums + .select_nth_unstable_by(mid, |&a, &b| match set.contains(&(a, b)) { + true => Less, + false => Greater, + }) + .1 as usize; + } + } + + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} diff --git a/aoc/2024/06/python.py b/aoc/2024/06/python.py new file mode 100755 index 0000000..52b61d0 --- /dev/null +++ b/aoc/2024/06/python.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +from fileinput import input + +obstacles = set() +seen = set() + +xmax, ymax = 0, 0 +for idy, line in enumerate(input()): + ymax = max(ymax, idy) + for idx, c in enumerate(line.strip()): + xmax = max(xmax, idx) + match c: + case "^": + pos = complex(idx, idy) + dir = 0 - 1j + case "#": + obstacles.add(complex(idx, idy)) + + +def is_loop(pos, obst): + seen_ = set() + dir = 0 - 1j + while 0 <= pos.real <= xmax and 0 <= pos.imag <= ymax: + if (pos, dir) in seen_: + return True + seen_.add((pos, dir)) + if pos + dir in obstacles or pos + dir == obst: + # Rotate cw + dir *= 1j + continue + pos += dir + return False + + +gold = 0 +for idx in range(xmax + 1): + for idy in range(ymax + 1): + if complex(idx, idy) == pos: + continue + else: + gold += is_loop(pos, complex(idx, idy)) + + +while 0 <= pos.real <= xmax and 0 <= pos.imag <= ymax: + seen.add(pos) + if pos + dir in obstacles: + # Rotate cw + dir *= 1j + continue + pos += dir + + +silver = len(seen) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/06/rust/Cargo.lock b/aoc/2024/06/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/06/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/06/rust/Cargo.toml b/aoc/2024/06/rust/Cargo.toml new file mode 100644 index 0000000..5a7c59b --- /dev/null +++ b/aoc/2024/06/rust/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" diff --git a/aoc/2024/06/rust/src/main.rs b/aoc/2024/06/rust/src/main.rs new file mode 100644 index 0000000..ca78bcd --- /dev/null +++ b/aoc/2024/06/rust/src/main.rs @@ -0,0 +1,105 @@ +use std::collections::HashSet; +use std::{collections::HashMap, io}; + +#[derive(Clone)] +enum Cell { + Empty, + Obstacle, +} + +#[derive(Clone)] +enum Direction { + L = 0b1, + R = 0b10, + U = 0b100, + D = 0b1000, +} + +impl Direction { + fn shift(&self, point: (isize, isize)) -> (isize, isize) { + let (x, y) = point; + match self { + Direction::L => (x - 1, y), + Direction::R => (x + 1, y), + Direction::U => (x, y - 1), + Direction::D => (x, y + 1), + } + } + + fn rotate(&self) -> Self { + use Direction::*; + match self { + L => U, + R => D, + U => R, + D => L, + } + } +} + +fn main() -> io::Result<()> { + let mut map = HashMap::new(); + let mut start = None; + io::stdin() + .lines() + .flatten() + .enumerate() + .flat_map(|(y, line)| { + line.chars() + .enumerate() + .map(|(x, ch)| ([x as isize, y as isize], ch)) + .collect::>() + }) + .for_each(|([x, y], ch)| match ch { + '.' => { + map.insert((x, y), Cell::Empty); + } + '^' => { + map.insert((x, y), Cell::Empty); + start = Some((x, y)) + } + '#' => { + map.insert((x, y), Cell::Obstacle); + } + _ => panic!(), + }); + let start = start.unwrap(); + + let visited = path_len(&map, start.clone()).unwrap(); + let silver: usize = visited.len(); + let gold: usize = visited + .iter() + .filter(|&p| { + let mut map = map.clone(); + map.insert(*p, Cell::Obstacle); + path_len(&map, start.clone()).is_none() + }) + .count(); + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} + +fn path_len( + map: &HashMap<(isize, isize), Cell>, + mut pos: (isize, isize), +) -> Option> { + let mut visited = HashMap::new(); + let mut dir = Direction::U; + + loop { + let before = visited.entry(pos).or_insert(0 as u8); + if *before & dir.clone() as u8 > 0 { + return None; + } + *before |= dir.clone() as u8; + + let ahead = dir.shift(pos); + match map.get(&ahead) { + Some(Cell::Empty) => pos = ahead, + Some(Cell::Obstacle) => dir = dir.rotate(), + None => return Some(visited.into_keys().collect()), + }; + } +} diff --git a/aoc/2024/07/python.py b/aoc/2024/07/python.py new file mode 100755 index 0000000..008af39 --- /dev/null +++ b/aoc/2024/07/python.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +from fileinput import input + +lines = [line.strip() for line in input()] + + +def solve(w, acc, rest, gold=False): + if not rest: + return w == acc + if w < acc: + return False + head, *rest = rest + return ( + solve(w, acc + head, rest, gold) + or solve(w, acc * head, rest, gold) + or (gold and solve(w, int(str(acc) + str(head)), rest, gold)) + ) + + +silver = 0 +gold = 0 + +for line in lines: + want, nums = line.split(":") + want = int(want) + nums = [int(n) for n in nums.split()] + head, *rest = nums + + if solve(want, head, rest): + silver += want + if solve(want, head, rest, True): + gold += want + + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/07/rust/Cargo.lock b/aoc/2024/07/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/07/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/07/rust/Cargo.toml b/aoc/2024/07/rust/Cargo.toml new file mode 100644 index 0000000..88e7b42 --- /dev/null +++ b/aoc/2024/07/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/aoc/2024/07/rust/src/main.rs b/aoc/2024/07/rust/src/main.rs new file mode 100644 index 0000000..df586b1 --- /dev/null +++ b/aoc/2024/07/rust/src/main.rs @@ -0,0 +1,71 @@ +use std::io; + +fn main() -> io::Result<()> { + let eqns = io::stdin() + .lines() + .flatten() + .collect::>() + .iter() + .map(|line| line.split_once(": ").unwrap()) + .map(|(ans, nums)| { + ( + ans.parse::().unwrap(), + nums.split_whitespace() + .map(|s| s.parse::().unwrap()) + .collect::>(), + ) + }) + .collect::>(); + + let silver: u64 = eqns.iter().map(crate::silver).sum(); + let gold: u64 = eqns.iter().map(crate::gold).sum(); + + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} + +fn concat(x: &u64, y: &u64) -> u64 { + x * (10u64.pow(y.ilog10() + 1)) + y +} + +fn calibration(want: u64, x: &u64, y: &u64, rest: &[u64], gold: bool) -> bool { + if *x > want { + return false; + } + match rest { + [] => want == x + y || want == x * y || (gold && want == concat(x, y)), + [z, rest @ ..] => { + calibration(want, &(x + y), z, rest, gold) + || calibration(want, &(x * y), z, rest, gold) + || (gold && calibration(want, &concat(x, y), z, rest, gold)) + } + } +} + +fn silver((want, nums): &(u64, Vec)) -> u64 { + match nums.as_slice() { + [x, y, rest @ ..] => { + if calibration(*want, x, y, rest, false) { + *want + } else { + 0 + } + } + _ => 0, + } +} + +fn gold((want, nums): &(u64, Vec)) -> u64 { + match nums.as_slice() { + [x, y, rest @ ..] => { + if calibration(*want, x, y, rest, true) { + *want + } else { + 0 + } + } + _ => 0, + } +} diff --git a/aoc/2024/08/python.py b/aoc/2024/08/python.py new file mode 100755 index 0000000..783203b --- /dev/null +++ b/aoc/2024/08/python.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +from collections import defaultdict +from fileinput import input +from itertools import product + +antennas = defaultdict(set) +x_max, y_max = 0, 0 + +for idy, line in enumerate(input()): + y_max = max(y_max, idy) + for idx, c in enumerate(line.strip()): + x_max = max(x_max, idx) + if c == ".": + continue + + antennas[c].add(complex(idx, idy)) + +nodes = set() +for vs in antennas.values(): + for v1, v2 in product(vs, vs): + if v1 == v2: + continue + vec = v2 - v1 + nodes.add(v1 + 2 * vec) + nodes.add(v2 - 2 * vec) + +nodes = {n for n in nodes if 0 <= n.real <= x_max and 0 <= n.imag <= y_max} + +gold_nodes = set() +for vs in antennas.values(): + for v1, v2 in product(vs, vs): + if v1 == v2: + continue + vec = v2 - v1 + start = v1 + while 0 <= start.real <= x_max and 0 <= start.imag <= y_max: + gold_nodes.add(start) + start += vec + + start = v2 + while 0 <= start.real <= x_max and 0 <= start.imag <= y_max: + gold_nodes.add(start) + start -= vec + + +silver = len(nodes) +gold = len(gold_nodes) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/08/rust/Cargo.lock b/aoc/2024/08/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/08/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/08/rust/Cargo.toml b/aoc/2024/08/rust/Cargo.toml new file mode 100644 index 0000000..88e7b42 --- /dev/null +++ b/aoc/2024/08/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/aoc/2024/08/rust/src/main.rs b/aoc/2024/08/rust/src/main.rs new file mode 100644 index 0000000..4fc3286 --- /dev/null +++ b/aoc/2024/08/rust/src/main.rs @@ -0,0 +1,74 @@ +use std::{ + collections::{HashMap, HashSet}, + io, +}; + +fn main() -> io::Result<()> { + let mut antennae: HashMap> = HashMap::new(); + + let grid = io::stdin() + .lines() + .flatten() + .map(|s| s.chars().collect()) + .collect::>>(); + + let max = grid.first().unwrap().len() as i32; + let may = grid.len() as i32; + grid.iter() + .enumerate() + .flat_map(|(y, row)| { + row.iter() + .enumerate() + .filter(|(_, &c)| c != '.') + .map(move |(x, &c)| (c, (x as i32, y as i32))) + }) + .for_each(|(c, p)| antennae.entry(c).or_default().push(p)); + + let mut silver = HashSet::new(); + let mut gold = HashSet::new(); + for ps in antennae.values() { + for (n, &p) in ps.iter().enumerate() { + for &t in &ps[n+1..] { + antinodes(p, t, (max, may), false).for_each(|n| { + silver.insert(n); + }); + antinodes(p, t, (max, may), true).for_each(|n| { + gold.insert(n); + }); + } + } + } + + let silver = silver.len(); + let gold = gold.len(); + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} + +fn antinodes( + a: (i32, i32), + b: (i32, i32), + max: (i32, i32), + gold: bool, +) -> impl Iterator { + let dx = b.0 - a.0; + let dy = b.1 - a.1; + let in_range = move |(x, y)| (0..max.0).contains(&x) && (0..max.1).contains(&y); + if !gold { + vec![(a.0 - dx, a.1 - dy), (b.0 + dx, b.1 + dy)] + } else { + (0..) + .map(|n| (a.0 - n * dx, a.1 - n * dy)) + .take_while(move |&p| in_range(p)) + .chain( + (0..) + .map(|n| (b.0 + n * dx, b.1 + n * dy)) + .take_while(move |&p| in_range(p)), + ) + .collect() + } + .into_iter() + .filter(move |&p| in_range(p)) +} diff --git a/aoc/2024/09/python.py b/aoc/2024/09/python.py new file mode 100755 index 0000000..1cf450e --- /dev/null +++ b/aoc/2024/09/python.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +from fileinput import input + +disk = list(input())[0].strip() + +id_ = -1 +blocks = [] +tail = 0 +file = True +for c in disk: + blocks.append([tail, tail + int(c), (id_ := id_ + 1) if file else -1]) + tail += int(c) + file = not file + + +def expand(bs): + return [x for a, b, x in sorted(bs) for _ in range(b - a)] + + +def debug(bs): + print("".join(str(b) if b != -1 else "." for b in expand(bs))) + + +# Silver +expanded = expand(blocks) +tail = len(expanded) - 1 +fill = expanded.index(-1) +while fill < tail: + expanded[fill] = expanded[tail] + expanded[tail] = -1 + while expanded[tail] == -1: + tail -= 1 + while expanded[fill] != -1: + fill += 1 +silver = sum(idx * n for idx, n in enumerate(expanded) if n != -1) + + +# Gold +for move in blocks[::-1]: + print(move) + ma, mb, mx = move + if mx == -1: + continue + mlen = mb - ma + for tidx, to in enumerate(blocks): + ta, tb, tx = to + if ta >= ma: + break + if tx != -1: + continue + if (tlen := tb - ta) < mlen: + continue + move[2] = -1 + to[2] = mx + to[1] = ta + mlen + blocks.insert(tidx + 1, [ta + mlen, tb, -1]) + break +gold = sum(idx * n for idx, n in enumerate(expand(blocks)) if n != -1) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/09/rust/Cargo.lock b/aoc/2024/09/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/09/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/09/rust/Cargo.toml b/aoc/2024/09/rust/Cargo.toml new file mode 100644 index 0000000..88e7b42 --- /dev/null +++ b/aoc/2024/09/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/aoc/2024/09/rust/src/main.rs b/aoc/2024/09/rust/src/main.rs new file mode 100644 index 0000000..fa7c021 --- /dev/null +++ b/aoc/2024/09/rust/src/main.rs @@ -0,0 +1,100 @@ +#![feature(iter_array_chunks)] + +use std::io; + +fn main() -> io::Result<()> { + let disk_map = io::stdin() + .lines() + .flatten() + .next() + .unwrap() + .chars() + .map(|c| c as u8 - b'0') + .collect(); + + let silver: usize = silver(&disk_map); + let gold: usize = gold(&disk_map); + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} + +fn silver(input: &Vec) -> usize { + let mut blocks = input + .iter() + .chain([0, 0].iter()) // lol + .array_chunks() + .enumerate() + .map(|(n, [&f, &s])| [[Some(n)].repeat(f as usize), [None].repeat(s as usize)]) + .flatten() + .flatten() + .collect::>(); + + let mut l = 0; + let mut r = blocks.len() - 1; + loop { + while blocks[r].is_none() { + r -= 1; + } + while blocks[l].is_some() { + l += 1; + } + if l >= r { + break; + } + let [left, right] = blocks.get_disjoint_mut([l, r]).unwrap(); + left.replace(right.take().unwrap()); + } + + blocks + .iter() + .enumerate() + .map(|(n, id)| n * id.unwrap_or_default()) + .sum() +} + +fn gold(input: &Vec) -> usize { + let mut blocks = input + .iter() + .chain([0, 0].iter()) // lol + .array_chunks() + .enumerate() + .map(|(n, [&f, &s])| [(Some(n), f as usize), (None, s as usize)]) + .flatten() + .collect::>(); + + let mut r = blocks.len(); + while r > 0 { + r -= 1; + let (Some(_), f) = blocks[r] else { + continue; + }; + + // find some empty space and maybe split + let Some(l) = blocks.iter().position(|b| b.0.is_none() && b.1 >= f) else { + continue; + }; + if l > r { + continue; + }; + + let (_, s) = &mut blocks[l]; + + let diff = *s - f; + if diff > 0 { + *s = f; + blocks.insert(l + 1, (None, diff)); + r += 1; + } + blocks.swap(l, r); + } + + blocks + .iter() + .map(|&(id, n)| [id].repeat(n)) + .flatten() + .enumerate() + .map(|(n, id)| n * id.unwrap_or_default()) + .sum() +} diff --git a/aoc/2024/10/python.py b/aoc/2024/10/python.py new file mode 100755 index 0000000..88892b6 --- /dev/null +++ b/aoc/2024/10/python.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +from fileinput import input + +grid = [[int(c) for c in line.strip()] for line in input()] + +starts = { + (idx, idy) for idy, line in enumerate(grid) for idx, n in enumerate(line) if n == 0 +} + +# print(*grid, sep="\n") +# print(starts) + + +def score_trailhead(start, gold): + score = 0 + q = [start] + seen = set() + while q: + x, y = q.pop() + seen.add((x, y)) + + h = grid[y][x] + if h == 9: + score += 1 + continue + for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]: + nx, ny = x + dx, y + dy + if ((nx, ny) in seen and not gold) or not ( + 0 <= nx < len(grid) and 0 <= ny < len(grid[0]) + ): + continue + + if grid[ny][nx] == h + 1: + q.append((nx, ny)) + return score + + +silver = sum(score_trailhead(start, False) for start in starts) +gold = sum(score_trailhead(start, True) for start in starts) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/10/rust/Cargo.lock b/aoc/2024/10/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/10/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/10/rust/Cargo.toml b/aoc/2024/10/rust/Cargo.toml new file mode 100644 index 0000000..88e7b42 --- /dev/null +++ b/aoc/2024/10/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/aoc/2024/10/rust/src/main.rs b/aoc/2024/10/rust/src/main.rs new file mode 100644 index 0000000..b5b3825 --- /dev/null +++ b/aoc/2024/10/rust/src/main.rs @@ -0,0 +1,52 @@ +use std::collections::HashSet; +use std::io; + +fn main() -> io::Result<()> { + let grid: Vec> = io::stdin() + .lines() + .flatten() + .map(|s| s.chars().map(|c| c.to_digit(10).unwrap() as u8).collect()) + .collect(); + + let starts = grid + .iter() + .enumerate() + .flat_map(|(y, row)| row.iter().enumerate().map(move |(x, d)| (x, y, d))) + .filter_map(|(x, y, d)| (*d == 0).then_some((y, x))) + .collect::>(); + + let silver: usize = starts.iter().map(|&s| trailheads(s, &grid, false)).sum(); + let gold: usize = starts.iter().map(|&s| trailheads(s, &grid, true)).sum(); + + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} + +fn trailheads(start: (usize, usize), grid: &Vec>, count_paths: bool) -> usize { + let mut seen = HashSet::new(); + let mut tot = 0; + let mut q = vec![start]; + + while let Some(curr @ (y, x)) = q.pop() { + seen.insert(curr); + let h = grid[y][x]; + if h == 9 { + tot += 1; + continue; + } + + [ + ((y + 1).min(grid.len() - 1), x), + (y, (x + 1).min(grid[0].len() - 1)), + (y.saturating_sub(1), x), + (y, x.saturating_sub(1)), + ] + .iter() + .filter(|&&(ny, nx)| grid[ny][nx] == h + 1) + .filter(|next| count_paths || !seen.contains(next)) + .for_each(|&n| q.push(n)); + } + tot +} diff --git a/aoc/2024/11/python.py b/aoc/2024/11/python.py new file mode 100755 index 0000000..37f658e --- /dev/null +++ b/aoc/2024/11/python.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +from fileinput import input +from functools import cache +from math import floor, log + +stones = [int(x) for x in input().readline().split()] + + +@cache +def blink(s, n): + if n == 0: + return 1 + + if s == 0: + return blink(1, n - 1) + + digits = floor(log(s, 10) + 1e-6) + 1 + if digits % 2 == 0: + left, right = divmod(s, 10 ** (digits // 2)) + return blink(left, n - 1) + blink(right, n - 1) + + return blink(s * 2024, n - 1) + + +silver = sum(blink(s, 25) for s in stones) +gold = sum(blink(s, 75) for s in stones) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/11/rust/Cargo.lock b/aoc/2024/11/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2024/11/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2024/11/rust/Cargo.toml b/aoc/2024/11/rust/Cargo.toml new file mode 100644 index 0000000..88e7b42 --- /dev/null +++ b/aoc/2024/11/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/aoc/2024/11/rust/src/main.rs b/aoc/2024/11/rust/src/main.rs new file mode 100644 index 0000000..e352ec4 --- /dev/null +++ b/aoc/2024/11/rust/src/main.rs @@ -0,0 +1,43 @@ +use std::{collections::HashMap, io}; + +fn blink(k @ (s, n): (u64, u64), cache: &mut HashMap<(u64, u64), u64>) -> u64 { + if n == 0 { + return 1; + } + if let Some(v) = cache.get(&k) { + return *v; + } + + // cache this + let v = { + if s == 0 { + return blink((1, n - 1), cache); + } + let digits = s.ilog10() + 1; + let mid = 10u64.pow(digits / 2); + if digits % 2 == 0 { + blink((s / mid, n - 1), cache) + blink((s % mid, n - 1), cache) + } else { + blink((s * 2024, n - 1), cache) + } + }; + + *cache.entry(k).or_insert(v) +} + +fn main() -> io::Result<()> { + let line = io::stdin().lines().flatten().next().unwrap(); + let stones = line + .split_whitespace() + .map(|s| s.parse::().unwrap()) + .collect::>(); + + let mut cache = HashMap::new(); + let silver: u64 = stones.iter().map(|s| blink((*s, 25), &mut cache)).sum(); + let gold: u64 = stones.iter().map(|s| blink((*s, 75), &mut cache)).sum(); + + println!("silver: {silver}"); + println!("gold: {gold}"); + + return Ok(()); +} diff --git a/aoc/2024/12/python.py b/aoc/2024/12/python.py new file mode 100755 index 0000000..81761bc --- /dev/null +++ b/aoc/2024/12/python.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +from fileinput import input + +grid = { + complex(idx, idy): c + for idy, line in enumerate(input()) + for idx, c in enumerate(line.strip()) +} +xmax = int(max(x.real for x in grid.keys())) +ymax = int(max(x.imag for x in grid.keys())) + +seen = set() + +silver = 0 + +for x in range(xmax + 1): + for y in range(ymax + 1): + c = complex(x, y) + if c in seen: + continue + + # Flood fill + char = grid[c] + perimeter = area = 0 + queue = [c] + while queue: + curr = queue.pop() + if curr in seen: + continue + seen.add(curr) + + for dir in [1, -1, 1j, -1j]: + next_ = curr + dir + if ( + not (0 <= next_.real <= xmax and 0 <= next_.imag <= ymax) + or grid[next_] != char + ): + perimeter += 1 + continue + + queue.append(next_) + area += 1 + silver += perimeter * area + +gold = 0 + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/13/python.py b/aoc/2024/13/python.py new file mode 100755 index 0000000..e78e35f --- /dev/null +++ b/aoc/2024/13/python.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +import re +from fileinput import input +from itertools import batched + +lines = [line.strip() for line in input()] + + +re_button = r"Button [A|B]: X\+(\d+), Y\+(\d+)" +re_prize = r"Prize: X=(\d+), Y=(\d+)" + + +def solve(machine, gold): + m = re.fullmatch( + r"Button A: X\+(\d+), Y\+(\d+)Button B: X\+(\d+), Y\+(\d+)Prize: X=(\d+), Y=(\d+)", + "".join(machine), + ) + # 2x2 matrix solve + ax, ay, bx, by, px, py = map(int, m.groups()) + if gold: + px += 10000000000000 + py += 10000000000000 + det = ax * by - ay * bx + + A = (by * px - bx * py) / det + B = (-ay * px + ax * py) / det + + # Check solutions are ints + if abs(int(A) - A) < 1e-7 and abs(int(B) - B) < 1e-7: + return 3 * int(A) + int(B) + else: + return 0 + + +silver = sum(solve(b, False) for b in batched(lines, 4)) +gold = sum(solve(b, True) for b in batched(lines, 4)) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/14/python.py b/aoc/2024/14/python.py new file mode 100755 index 0000000..2bb6cb4 --- /dev/null +++ b/aoc/2024/14/python.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import re +from fileinput import input +from itertools import groupby +from math import prod + +XMAX, YMAX = 11, 7 # for test +XMAX, YMAX = 101, 103 # for aoc + +robots = [ + re.fullmatch(r"p=(\d+),(\d+) v=(-?\d+),(-?\d+)", line.strip()).groups() + for line in input() +] +robots = [ + (complex(int(px), int(py)), complex(int(vx), int(vy))) for px, py, vx, vy in robots +] + + +def move(p, v, s): + e = p + v * s + return complex(e.real % XMAX, e.imag % YMAX) + + +def quad(x): + return (x.real < XMAX // 2, x.imag < YMAX // 2) + + +def is_quad(x): + return x.real != XMAX // 2 and x.imag != YMAX // 2 + + +def draw(s): + print(f"Seconds passed: {s}") + moved = {move(p, v, s) for p, v in robots} + for x in range(XMAX): + for y in range(YMAX): + print( + "#" if complex(x, y) in moved else " ", + end="", + ) + print() + print("-" * XMAX) + + +moved = groupby( + sorted( + filter(is_quad, (move(p, v, 100) for p, v in robots)), + key=quad, + ), + quad, +) + + +silver = prod(sum(1 for _ in k) for _, k in moved) +gold = 0 + +print("silver:", silver) +print("gold:", gold) + +s = 0 +while s < 10_000: + draw(s) + s += 1 diff --git a/aoc/2024/15/python.py b/aoc/2024/15/python.py new file mode 100755 index 0000000..4cfd48c --- /dev/null +++ b/aoc/2024/15/python.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +from fileinput import input +from itertools import takewhile + +inp = map(str.strip, input()) + +grid = { + complex(x, y): c + for y, line in enumerate(takewhile(bool, inp)) + for x, c in enumerate(line) +} +grid_gold = {} +for p, c in grid.items(): + p += p.real + match c: + case "#" | ".": + grid_gold[p] = grid_gold[p + 1] = c + case "O": + grid_gold[p] = "[" + grid_gold[p + 1] = "]" + case "@": + grid_gold[p] = "@" + grid_gold[p + 1] = "." + + +moves = "".join(inp) + +bot = next(p for p, c in grid.items() if c == "@") +bot_gold = bot + bot.real + + +def debug(grid): + xmax, ymax = (max(p.real for p in grid.keys()), max(p.imag for p in grid.keys())) + for y in range(int(ymax) + 1): + for x in range(int(xmax) + 1): + print(grid[complex(x, y)], end="") + print() + print() + + +def push(grid, x, v, modify=True): + match grid[x], v: + case ".", _: + return True + case "#", _: + return False + case "[", (1j | -1j) if push(grid, x + v, v, modify) and push( + grid, x + v + 1, v, modify + ): + if modify: + grid[x + v] = grid[x] + grid[x + v + 1] = grid[x + 1] + grid[x] = "." + grid[x + 1] = "." + return True + case "[", (1j | -1j): + return False + # Push other one + case "]", (1j | -1j): + return push(grid, x - 1, v, modify) + case _, _ if push(grid, x + v, v, modify): + if modify: + grid[x + v] = grid[x] + return True + + +dirs = {">": 1, "v": 1j, "<": -1, "^": -1j} +for m in map(dirs.get, moves): + if push(grid, bot, m): + grid[bot] = "." + bot += m + if push(grid_gold, bot_gold, m, modify=False): + push(grid_gold, bot_gold, m, modify=True) + grid_gold[bot_gold] = "." + bot_gold += m + + +silver = int(sum(p.real + 100 * p.imag for p, c in grid.items() if c == "O")) +gold = int(sum(p.real + 100 * p.imag for p, c in grid_gold.items() if c == "[")) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/16/python.py b/aoc/2024/16/python.py new file mode 100755 index 0000000..fda3714 --- /dev/null +++ b/aoc/2024/16/python.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +from fileinput import input + +grid = { + complex(idx, idy): c + for idy, line in enumerate(input()) + for idx, c in enumerate(line.strip()) +} +start = next(p for p, c in grid.items() if c == "S") +end = next(p for p, c in grid.items() if c == "E") + +q = [(0, (start, 1))] +seen = set() +while q: + curr = min(q, key=lambda x: x[0]) + d, (pos, vel) = curr + q.remove(curr) + if (pos, vel) in seen: + continue + if pos == end: + silver = d + break + seen.add((pos, vel)) + + if grid[pos + vel] != "#": + q.append((d + 1, (pos + vel, vel))) + q.append((d + 1000, (pos, vel * 1j))) + q.append((d + 1000, (pos, vel * -1j))) + +print("silver:", silver) diff --git a/aoc/2024/17/python.py b/aoc/2024/17/python.py new file mode 100755 index 0000000..9ea7de4 --- /dev/null +++ b/aoc/2024/17/python.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +from fileinput import input +from itertools import takewhile, zip_longest + +inp = map(str.strip, input()) +regs = [int(r[2]) for r in (line.split() for line in takewhile(bool, inp))] +prog = [int(o) for o in next(inp).split()[1].split(",")] +out = [] + + +def run(prog, ra, rb, rc): + out = [] + ir = 0 + while ir < len(prog): + instr, op = prog[ir], prog[ir + 1] + combo = {4: ra, 5: rb, 6: rc} + cop = combo.get(op, op) + match instr: + case 0: + ra = ra >> cop + case 1: + rb ^= op + case 2: + rb = cop & 0b111 + case 3 if ra: + ir = op - 2 + case 4: + rb ^= rc + case 5: + yield cop & 0b111 + case 6: + rb = ra >> cop + case 7: + rc = ra >> cop + ir += 2 + return out + + +def match(prog, ra): + return ( + got == want + for got, want in zip_longest( + reversed(list(run(prog, ra, 0, 0))), + reversed(prog), + ) + ) + + +def find_a(prog): + q = list(range(8)) + while True: + curr = q.pop(0) + if all(match(prog, curr)): + return curr + + best = sum(match(prog, curr)) + for n in range(8): + ra = (curr << 3) + n + if sum(match(prog, ra)) > best: + q.append(ra) + + +silver = ",".join(map(str, run(prog, *regs))) +gold = find_a(prog) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/18/python.py b/aoc/2024/18/python.py new file mode 100755 index 0000000..1f987c6 --- /dev/null +++ b/aoc/2024/18/python.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +from bisect import bisect_left +from collections import deque +from fileinput import input + +coords = [line.strip().split(",") for line in input()] +grid = {complex(int(x), int(y)): t for t, [x, y] in enumerate(coords)} + + +def solve(size, delay): + q = deque([(0, 0)]) + seen = set() + while q: + curr, t = q.popleft() + if curr in seen: + continue + if curr == complex(size, size): + return t + seen.add(curr) + + for d in [1, -1, 1j, -1j]: + x = curr + d + if not (0 <= x.real <= size and 0 <= x.imag <= size): + continue + if x in grid and grid[x] < delay: + continue + q.append((x, t + 1)) + return None + + +silver = solve(70, 1024) +# silver = solve(6, 12) # test.txt + +gold = ",".join( + coords[ + bisect_left( + list(range(len(grid))), + True, + key=lambda x: solve(70, x) is None, + ) + - 1 + ] +) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/19/python.py b/aoc/2024/19/python.py new file mode 100755 index 0000000..efd3272 --- /dev/null +++ b/aoc/2024/19/python.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +from fileinput import input +from functools import cache +from itertools import takewhile + +inp = map(str.strip, input()) +towels = [t.strip() for t in next(takewhile(bool, inp)).split(",")] +designs = [d for d in inp if d] + +# Construct trie +trie = {} +for towel in towels: + prev = None + curr = trie + for t in towel: + term, succ = curr.setdefault(t, (False, {})) + prev = curr + curr = succ + prev[towel[-1]] = (True, curr) + + +@cache +def steps(design, n=0): + if n == len(design): + return 1 + ways = 0 + curr = trie + for d, s in enumerate(design[n:], start=1): + if s not in curr: + return ways + term, curr = curr[s] + if term: + ways += steps(design, n + d) + return ways + + +silver = sum(map(bool, map(steps, designs))) +gold = sum(map(steps, designs)) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/20/python.py b/aoc/2024/20/python.py new file mode 100755 index 0000000..610f1a3 --- /dev/null +++ b/aoc/2024/20/python.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +from fileinput import input + +grid = { + complex(idx, idy): c + for idy, line in enumerate(input()) + for idx, c in enumerate(line.strip()) +} +start = next(p for p, c in grid.items() if c == "S") +end = next(p for p, c in grid.items() if c == "E") + +times = {} +q = [(start, 0)] +while q: + curr, t = q.pop() + if curr in times: + continue + times[curr] = t + for d in [1, -1, 1j, -1j]: + x = curr + d + if x not in grid or grid[x] == "#": + continue + q.append((x, t + 1)) + + +def cheat(x, y, d): + dist = int(abs(x.real - y.real) + abs(x.imag - y.imag)) + if dist > d: + return False + saved = times[y] - times[x] - dist + return saved >= 100 + + +silver = sum(cheat(x, y, 2) for x in times.keys() for y in times.keys()) +gold = sum(cheat(x, y, 20) for x in times.keys() for y in times.keys()) + + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/21/python.py b/aoc/2024/21/python.py new file mode 100755 index 0000000..5873d65 --- /dev/null +++ b/aoc/2024/21/python.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +from fileinput import input +from functools import cache + +seqs = [s.strip() for s in input()] + +numpad = { + "0": {"^": "2", ">": "A"}, + "1": {"^": "4", ">": "2"}, + "2": {"^": "5", ">": "3", "v": "0", "<": "1"}, + "3": {"^": "6", "v": "A", "<": "2"}, + "4": {"^": "7", ">": "5", "v": "1"}, + "5": {"^": "8", ">": "6", "v": "2", "<": "4"}, + "6": {"^": "9", "v": "3", "<": "5"}, + "7": {">": "8", "v": "4"}, + "8": {">": "9", "v": "5", "<": "7"}, + "9": {"v": "6", "<": "8"}, + "A": {"^": "3", "<": "0"}, +} +dirpad = { + "^": {">": "A", "v": "v"}, + ">": {"^": "A", "<": "v"}, + "v": {"^": "^", ">": ">", "<": "<"}, + "<": {">": "v"}, + "A": {"v": ">", "<": "^"}, +} + + +silver = 0 +gold = 0 + + +@cache +def move(a, b, n): + pass + + +print(seqs) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2024/22/python.py b/aoc/2024/22/python.py new file mode 100755 index 0000000..98d8898 --- /dev/null +++ b/aoc/2024/22/python.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +from collections import Counter, deque +from fileinput import input +from itertools import islice + +lines = [int(line.strip()) for line in input()] + + +def secrets(secret): + x = secret + while True: + yield x + x ^= x << 6 + x &= 0xFFFFFF + x ^= x >> 5 + x &= 0xFFFFFF + x ^= x << 11 + x &= 0xFFFFFF + + +def prices(it): + for s in it: + yield s % 10 + + +def diff(it): + prev = next(it) + for curr in it: + yield curr, curr - prev + prev = curr + + +def to_seqs(it, n=4): + head = map(lambda x: x[1], islice(it, n - 1)) + q = deque(head, maxlen=n) + for price, diff in it: + q.append(diff) + yield price, tuple(q) + + +def seq_sells(it): + sells = {} + for price, diff in it: + if diff in sells: + continue + sells[diff] = price + return sells + + +best_seqs = Counter() +for x in lines: + best_seqs += seq_sells(to_seqs(islice(diff(prices(secrets(x))), 2000))) + +silver = sum(next(islice(secrets(x), 2000, None)) for x in lines) +gold = best_seqs.most_common(1)[0][1] + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2025/01/c.c b/aoc/2025/01/c.c new file mode 100644 index 0000000..115ea13 --- /dev/null +++ b/aoc/2025/01/c.c @@ -0,0 +1,19 @@ +#include +#include +#include + +int main() +{ + char dir; + int64_t n; + int64_t p = 50; + int64_t p1 = 0, p2 = 0; + while (scanf("%c%ld ", &dir, &n) == 2) { + int64_t new = p + (dir == 'R' ? n : -n); + p2 += labs(new) / 100 + (p != 0 && new <= 0); + p = (p = new % 100) >= 0 ? p : p + 100; + p1 += p == 0; + } + printf("silver: %ld\ngold: %ld", p1, p2); + return 0; +} diff --git a/aoc/2025/01/python.py b/aoc/2025/01/python.py new file mode 100755 index 0000000..d5ff1fa --- /dev/null +++ b/aoc/2025/01/python.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +from fileinput import input +from itertools import accumulate + + +def fn(p: tuple[int, int], rot: str) -> tuple[int, int]: + x = p[0] + int(rot[1:]) * (1 if rot[0] == "R" else -1) + return x % 100, abs(x) // 100 + (p[0] and x <= 0) + + +p1, p2 = zip(*list(accumulate(input(), fn, initial=(50, 0)))) + +print(f"silver: {sum(not p for p in p1)}") +print(f"gold: {sum(p2)}") diff --git a/aoc/2025/01/rust/Cargo.lock b/aoc/2025/01/rust/Cargo.lock new file mode 100644 index 0000000..8c50f75 --- /dev/null +++ b/aoc/2025/01/rust/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" +dependencies = [ + "num", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] diff --git a/aoc/2025/01/rust/Cargo.toml b/aoc/2025/01/rust/Cargo.toml new file mode 100644 index 0000000..9a6e47e --- /dev/null +++ b/aoc/2025/01/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2024" + +[dependencies] +num = { version = "0.4.3", features = ["num-bigint"] } diff --git a/aoc/2025/01/rust/src/main.rs b/aoc/2025/01/rust/src/main.rs new file mode 100644 index 0000000..72b718b --- /dev/null +++ b/aoc/2025/01/rust/src/main.rs @@ -0,0 +1,25 @@ +use num::BigUint; +use std::io; + +fn main() { + let mut curr = 50; + let mut silver: u64 = 0; + let mut gold: BigUint = BigUint::ZERO; + io::stdin() + .lines() + .flatten() + .map(|line| match line.split_at(1) { + ("L", n) => -n.parse::().unwrap(), + (_, n) => n.parse::().unwrap(), + }) + .for_each(|n| { + let prev = curr; + curr += n; + gold += (curr.abs() / 100) as u64 + (prev != 0 && curr <= 0) as u64; + curr = curr.rem_euclid(100); + silver += (curr == 0) as u64; + }); + + println!("silver: {silver}"); + println!("gold: {gold}"); +} diff --git a/aoc/2025/02/python.py b/aoc/2025/02/python.py new file mode 100755 index 0000000..a3b4d1e --- /dev/null +++ b/aoc/2025/02/python.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + + +from itertools import accumulate +from bisect import bisect_left, bisect_right +from functools import cache + +rs = [(int(a), int(b)) for r in input().split(",") for [a, b] in [r.split("-")]] +N = max(len(str(x)) for r in rs for x in r) + + +@cache +def memo(p2: bool): + ids = sorted( + { + int(str(n) * reps) + for n in range(10 ** (N // 2)) + for reps in range(2, N // len(str(n)) + 1 if p2 else 3) + } + ) + sums = list(accumulate(ids)) + return ids[1:], sums + + +def prefix_sum(a: int, b: int, ids: list[int], sums: list[int]): + return sums[bisect_right(ids, b)] - sums[bisect_left(ids, a)] + + +silver = sum(prefix_sum(*r, *memo(False)) for r in rs) +gold = sum(prefix_sum(*r, *memo(True)) for r in rs) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2025/03/python.py b/aoc/2025/03/python.py new file mode 100755 index 0000000..b0d4bfd --- /dev/null +++ b/aoc/2025/03/python.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +from fileinput import input + +lines = [[int(b) for b in line.strip()] for line in input()] + + +def jolt(bs: list[int], n: int) -> int: + if n == 1: + return max(bs) + n -= 1 + b = max(bs[:-n]) + i = bs.index(b) + return b * (10**n) + jolt(bs[i + 1 :], n) + + +silver = sum(jolt(bs, 2) for bs in lines) +gold = sum(jolt(bs, 12) for bs in lines) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2025/03/rust/Cargo.lock b/aoc/2025/03/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2025/03/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2025/03/rust/Cargo.toml b/aoc/2025/03/rust/Cargo.toml new file mode 100644 index 0000000..26e4e77 --- /dev/null +++ b/aoc/2025/03/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/aoc/2025/03/rust/src/main.rs b/aoc/2025/03/rust/src/main.rs new file mode 100644 index 0000000..be0b3e6 --- /dev/null +++ b/aoc/2025/03/rust/src/main.rs @@ -0,0 +1,42 @@ +use std::io; + +fn max(bs: &Vec, start: usize, end: usize) -> (u8, usize) { + let mut bests = [None; 10]; + for idx in start..=end { + if bs[idx] == 9 { + return (9, idx); + } + bests[bs[idx] as usize].get_or_insert((bs[idx], idx)); + } + bests.into_iter().flatten().last().unwrap() +} + +fn jolt(bs: &Vec, n: usize) -> u64 { + let mut j: u64 = 0; + let mut start = 0; + for n in (1..=n).rev() { + j *= 10; + let (b, idx) = max(bs, start, bs.len() - n); + j += b as u64; + start = idx + 1; + } + j +} + +fn main() { + let (silver, gold) = io::stdin() + .lines() + .flatten() + .map(|line| { + line.into_bytes() + .iter() + .map(|&x| x - b'0') + .collect::>() + }) + .map(|bs| (jolt(&bs, 2), jolt(&bs, 12))) + .reduce(|(a0, a1), (x0, x1)| (a0 + x0, a1 + x1)) + .unwrap(); + + println!("silver: {silver}"); + println!("gold: {gold}"); +} diff --git a/aoc/2025/04/python.py b/aoc/2025/04/python.py new file mode 100755 index 0000000..844c38e --- /dev/null +++ b/aoc/2025/04/python.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +from fileinput import input + +g = { + complex(x, y): ch + for y, line in enumerate(input()) + for x, ch in enumerate(line.strip()) +} + + +def accessible(): + return { + p + for p, x in g.items() + if x == "@" + and sum( + 1 + for dx in (-1, 0, 1) + for dy in (-1j, 0j, 1j) + if dx + dy != 0 and g.get(p + dx + dy, ".") == "@" + ) + < 4 + } + + +silver = len(accessible()) +gold = 0 + +while rem := accessible(): + gold += len(rem) + for gone in rem: + g.pop(gone) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2025/04/rust/Cargo.lock b/aoc/2025/04/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2025/04/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2025/04/rust/Cargo.toml b/aoc/2025/04/rust/Cargo.toml new file mode 100644 index 0000000..26e4e77 --- /dev/null +++ b/aoc/2025/04/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/aoc/2025/04/rust/src/main.rs b/aoc/2025/04/rust/src/main.rs new file mode 100644 index 0000000..3b13140 --- /dev/null +++ b/aoc/2025/04/rust/src/main.rs @@ -0,0 +1,66 @@ +use std::{collections::VecDeque, io}; + +fn main() { + let mut grid: Vec>> = io::stdin() + .lines() + .flatten() + .map(|line| line.chars().map(|ch| (ch == '@').then_some(0)).collect()) + .collect(); + + // count neighbours + points(&grid) + .collect::>() + .into_iter() + .for_each(|p @ (x, y)| { + let ns = neighbours(p, &grid).count(); + if let Some(n) = grid[y][x].as_mut() { + *n = ns; + } + }); + + let mut stack = points(&grid) + .filter(|&(x, y)| grid[y][x].is_some_and(|n| n < 4)) + .collect::>(); + let silver = stack.len(); + let mut gold = 0; + + while let Some(p @ (x, y)) = stack.pop_back() { + if grid[y][x].take().is_none() { + continue; + } + gold += 1; + // reduce neighbours' neighbour counts by 1 + neighbours(p, &grid) + .collect::>() + .into_iter() + .for_each(|(nx, ny)| { + if let Some(n) = grid[ny][nx].as_mut() { + *n -= 1; + if *n < 4 { + stack.push_back((nx, ny)) + } + } + }); + } + + println!("silver: {silver}"); + println!("gold: {gold}"); +} + +fn neighbours( + (x, y): (usize, usize), + grid: &Vec>>, +) -> impl Iterator { + let xs = x.saturating_sub(1)..=(x + 1).min(grid.first().unwrap().len() - 1); + let ys = y.saturating_sub(1)..=(y + 1).min(grid.len() - 1); + + xs.flat_map(move |nx| ys.clone().map(move |ny| (nx, ny))) + .filter(move |n| *n != (x, y)) + .filter(|&(nx, ny)| grid.get(ny).and_then(|row| row.get(nx)).unwrap().is_some()) +} + +fn points(grid: &Vec>) -> impl Iterator { + let xs = 0..grid.first().unwrap().len(); + let ys = 0..grid.len(); + xs.flat_map(move |x| ys.clone().map(move |y| (x, y))) +} diff --git a/aoc/2025/05/python.py b/aoc/2025/05/python.py new file mode 100755 index 0000000..9977623 --- /dev/null +++ b/aoc/2025/05/python.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +from itertools import takewhile +from fileinput import input + + +inp = map(str.strip, input()) +rs = [tuple(map(int, r.split("-"))) for r in takewhile(bool, inp)] +ids = list(map(int, inp)) + + +def add(a: int, b: int, c: int, d: int) -> tuple[int, int] | None: + if c < a: + return add(c, d, a, b) + if b < c: + return None + return (a, max(b, d)) + + +done = False +while not done: + ms = [] + for r in rs: + for idx, m in enumerate(ms): + if new := add(*r, *m): + ms[idx] = new + break + + else: + ms.append(r) + done = len(rs) == len(ms) + rs = ms + + +silver = sum(1 for i in ids if any(lo <= i <= hi for lo, hi in rs)) +gold = sum(b - a + 1 for a, b in rs) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2025/05/rust/Cargo.lock b/aoc/2025/05/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2025/05/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2025/05/rust/Cargo.toml b/aoc/2025/05/rust/Cargo.toml new file mode 100644 index 0000000..26e4e77 --- /dev/null +++ b/aoc/2025/05/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/aoc/2025/05/rust/src/main.rs b/aoc/2025/05/rust/src/main.rs new file mode 100644 index 0000000..cd78338 --- /dev/null +++ b/aoc/2025/05/rust/src/main.rs @@ -0,0 +1,55 @@ +use std::io; + +fn main() { + let mut input = io::stdin().lines().flatten().map(|line| line); + let ranges = input.by_ref().take_while(|s| !s.is_empty()).map(|s| { + let (lo, hi) = s.split_once('-').unwrap(); + ( + lo.to_owned().parse().unwrap(), + hi.to_owned().parse().unwrap(), + ) + }); + + let mut merged: Vec<(u64, u64)> = vec![]; + for (mut lo, mut hi) in ranges { + let ldx = merged.partition_point(|&(_, max)| max < lo); + let mut rdx = merged.partition_point(|&(_, max)| max < hi); + + let left = merged.get(ldx); + let right = merged.get(rdx); + + // ldx = merged.len() -> left is none -> insert at end + let Some(&(llo, lhi)) = left else { + merged.push((lo, hi)); + continue; + }; + + if (llo..=lhi).contains(&lo) { + lo = lo.min(llo); // include range start point + } + + // rdx = merged.len() -> right is none -> merge with all + let Some(&(rlo, rhi)) = right else { + merged.drain(ldx..); + merged.push((lo, hi)); + continue; + }; + + if (rlo..=rhi).contains(&hi) { + hi = hi.max(rhi); + rdx += 1; + } + + merged.drain(ldx..rdx); + merged.insert(ldx, (lo, hi)); + } + + let silver = input + .map(|n| n.parse::().unwrap()) + .filter(|id| merged.iter().any(|&(lo, hi)| (lo..=hi).contains(id))) + .count(); + let gold: u64 = merged.iter().map(|(lo, hi)| hi - lo + 1).sum(); + + println!("silver: {silver}"); + println!("gold: {gold}"); +} diff --git a/aoc/2025/06/python.py b/aoc/2025/06/python.py new file mode 100755 index 0000000..4c57829 --- /dev/null +++ b/aoc/2025/06/python.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +from math import prod +from fileinput import input +from itertools import takewhile, repeat + +*nums, ops = [line.strip("\n") for line in input()] +ops = [prod if op == "*" else sum for op in ops.split()] + +horizontal = [map(int, row.split()) for row in nums] +silver = sum(op(chunk) for op, chunk in zip(ops, zip(*horizontal))) + +vertical = ("".join(ds).strip() for ds in [*zip(*nums)]) +chunks = repeat(lambda: [*map(int, takewhile(bool, vertical))]) +gold = sum(op(chunk()) for op, chunk in zip(ops, chunks)) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2025/07/python.py b/aoc/2025/07/python.py new file mode 100755 index 0000000..639c368 --- /dev/null +++ b/aoc/2025/07/python.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +from fileinput import input +from functools import cache + +lines = [line.strip() for line in input()] +start = lines[0].index("S") + +silver = 0 +bs = {start} +for line in lines: + for b in bs.copy(): + if line[b] == "^": + silver += 1 + bs -= {b} + bs |= {b - 1, b + 1} + + +@cache +def tls(r: int, c: int) -> int: + if r == len(lines): + return 1 + if lines[r][c] == "^": + return tls(r, c - 1) + tls(r, c + 1) + return tls(r + 1, c) + + +gold = tls(0, start) + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2025/08/python.py b/aoc/2025/08/python.py new file mode 100755 index 0000000..98a4725 --- /dev/null +++ b/aoc/2025/08/python.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +from fileinput import input +from math import dist, prod +from operator import itemgetter + +MAX_CONNS = 1000 # test: 10, input: 1000 + +boxes = [[*map(int, line.split(","))] for line in input()] +N = len(boxes) + +js = {n: {n} for n in range(N)} +conns = sorted( + ((x, y) for x in range(N) for y in range(x)), + key=lambda t: dist(*itemgetter(*t)(boxes)), +) + +for n, (x, y) in enumerate(conns): + if n == MAX_CONNS: + lens = {id(j): len(j) for j in js.values()}.values() + print("silver:", prod(sorted(lens, reverse=True)[:3])) + + j = js[x] | js[y] + for b in j: + js[b] = j + + if len(j) == N: + print("gold:", boxes[x][0] * boxes[y][0]) + break diff --git a/aoc/2025/09/python.py b/aoc/2025/09/python.py new file mode 100755 index 0000000..6c4df6c --- /dev/null +++ b/aoc/2025/09/python.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +from fileinput import input + +pts = [[*map(int, line.split(","))] for line in input()] + +silver = max( + (abs(x1 - x2) + 1) * (abs(y1 - y2) + 1) for (x1, y1) in pts for (x2, y2) in pts +) +gold = 0 + +print("silver:", silver) +print("gold:", gold) diff --git a/aoc/2025/09/rust/Cargo.lock b/aoc/2025/09/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2025/09/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2025/09/rust/Cargo.toml b/aoc/2025/09/rust/Cargo.toml new file mode 100644 index 0000000..26e4e77 --- /dev/null +++ b/aoc/2025/09/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/aoc/2025/09/rust/src/main.rs b/aoc/2025/09/rust/src/main.rs new file mode 100644 index 0000000..32847e3 --- /dev/null +++ b/aoc/2025/09/rust/src/main.rs @@ -0,0 +1,113 @@ +use std::io; + +#[derive(Debug)] +struct Floor { + x_comp: Vec, + y_comp: Vec, +} + +impl Floor { + fn new(pts: Vec<(usize, usize)>) -> (Self, Vec<(usize, usize)>) { + let (mut xs, mut ys): (Vec<_>, Vec<_>) = pts.clone().into_iter().unzip(); + xs.sort_unstable(); + xs.dedup(); + ys.sort_unstable(); + ys.dedup(); + + let pts = pts + .into_iter() + .map(|(x, y)| (xs.binary_search(&x).unwrap(), ys.binary_search(&y).unwrap())) + .collect(); + + ( + Self { + x_comp: xs, + y_comp: ys, + }, + pts, + ) + } + + fn uncomp(&self, (x, y): (usize, usize)) -> (usize, usize) { + (self.x_comp[x], self.y_comp[y]) + } + + fn area(&self, (p1, p2): ((usize, usize), (usize, usize))) -> usize { + let (x1, y1) = self.uncomp(p1); + let (x2, y2) = self.uncomp(p2); + (x1.abs_diff(x2) + 1) * (y1.abs_diff(y2) + 1) + } +} + +fn main() { + let pts = io::stdin() + .lines() + .flatten() + .map(|line| { + let (x, y) = line.split_once(',').unwrap(); + (x.parse().unwrap(), y.parse().unwrap()) + }) + .collect::>(); + + let (floor, pts) = Floor::new(pts); + + let xmax = *pts.iter().map(|(x, _)| x).max().unwrap(); + let ymax = *pts.iter().map(|(_, y)| y).max().unwrap(); + + // some padding so that flood fill works correctly + let mut grid: Vec>> = vec![vec![None; xmax + 3]; ymax + 3]; + + // draw green/red tiles + for pair in [vec![*pts.last().unwrap()], pts.clone()] + .concat() + .windows(2) + { + let (x1, y1) = pair[0]; + let (x2, y2) = pair[1]; + (x1.min(x2)..=x1.max(x2)).for_each(|x| { + (y1.min(y2)..=(y1.max(y2))).for_each(|y| grid[y + 1][x + 1] = Some(true)) + }); + } + + // flood fill from top left + let mut q = vec![(0, 0)]; + while let Some((x, y)) = q.pop() { + grid[y][x] = Some(false); + let ns = vec![ + (x.saturating_sub(1), y), + ((x + 1).min(xmax + 2), y), + (x, y.saturating_sub(1)), + (x, (y + 1).min(ymax + 2)), + ]; + q.extend(ns.into_iter().filter(|&(x, y)| grid[y][x].is_none())); + } + + // replace inside cells with Some(true) and undo the padding + let grid: Vec> = grid + .into_iter() + .skip(1) + .map(|r| r.into_iter().skip(1).map(|c| c.unwrap_or(true)).collect()) + .collect(); + + let mut rectangles = pts + .iter() + .enumerate() + .flat_map(|(idx, p1)| pts.iter().take(idx).map(move |p2| (*p1, *p2))) + .collect::>(); + rectangles.sort_unstable_by_key(|&r| std::cmp::Reverse(floor.area(r))); + + let silver: usize = floor.area(*rectangles.first().unwrap()); + let gold: usize = floor.area( + *rectangles + .iter() + .filter(|&&((x1, y1), (x2, y2))| { + (x1.min(x2)..=x1.max(x2)) + .flat_map(|x| (y1.min(y2)..=y1.max(y2)).map(move |y| (x, y))) + .all(|(x, y)| grid[y][x]) + }) + .next() + .unwrap(), + ); + println!("silver: {silver}"); + println!("gold: {gold}"); +} diff --git a/aoc/2025/10/rust/Cargo.lock b/aoc/2025/10/rust/Cargo.lock new file mode 100644 index 0000000..b6a74c9 --- /dev/null +++ b/aoc/2025/10/rust/Cargo.lock @@ -0,0 +1,155 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" +dependencies = [ + "good_lp", + "itertools", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "good_lp" +version = "1.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "776aa1ba88ac058e78408c17f4dbff826a51ae08ed6642f71ca0edd7fe9383f3" +dependencies = [ + "fnv", + "microlp", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "microlp" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d1790c73b93164ff65868f63164497cb32339458a9297e17e212d91df62258" +dependencies = [ + "log", + "sprs", +] + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "sprs" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dca58a33be2188d4edc71534f8bafa826e787cc28ca1c47f31be3423f0d6e55" +dependencies = [ + "ndarray", + "num-complex", + "num-traits", + "smallvec", +] diff --git a/aoc/2025/10/rust/Cargo.toml b/aoc/2025/10/rust/Cargo.toml new file mode 100644 index 0000000..f8128d3 --- /dev/null +++ b/aoc/2025/10/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2024" + +[dependencies] +good_lp = { version = "1.14.2", features = ["microlp"], default-features = false } +itertools = "0.14.0" diff --git a/aoc/2025/10/rust/src/main.rs b/aoc/2025/10/rust/src/main.rs new file mode 100644 index 0000000..b0cd6ed --- /dev/null +++ b/aoc/2025/10/rust/src/main.rs @@ -0,0 +1,68 @@ +use good_lp::*; +use itertools::Itertools; +use std::io; + +fn main() { + let ms = io::stdin() + .lines() + .flatten() + .map(|line| { + let mut iter = line.split_whitespace(); + let p1 = iter + .next() + .unwrap() + .chars() + .filter_map(|ch| match ch { + '.' => Some(0), + '#' => Some(1), + _ => None, + }) + .collect::>(); + + let mut iter = iter.map(|s| { + s.split(|ch: char| ch.is_ascii_punctuation()) + .filter_map(|n| n.parse().ok()) + .collect::>() + }); + let p2 = iter.next_back().unwrap(); + let bs = iter.collect::>(); + (p1, p2, bs) + }) + .collect::>(); + + let silver: usize = ms.iter().map(|(want, _, bs)| solve_p1(&want, &bs)).sum(); + let gold: usize = ms.iter().map(|(_, want, bs)| solve_p2(&want, &bs)).sum(); + println!("silver: {silver}"); + println!("gold: {gold}"); +} + +fn solve_p1(want: &Vec, bs: &Vec>) -> usize { + bs.into_iter() + .powerset() + .map(|sub| (sub.len(), sub.into_iter().flatten().counts())) + .filter(|(_, counts)| { + want.iter() + .enumerate() + .all(|(n, w)| counts.get(&(n as u32)).unwrap_or(&0) % 2 == *w as usize) + }) + .next() + .unwrap() + .0 +} + +fn solve_p2(want: &Vec, bs: &Vec>) -> usize { + variables! {vars: 0 <= xs[bs.len()] (integer);} + let obj: Expression = xs.iter().sum(); + let mut model = vars.minimise(&obj).using(default_solver); + for (n, w) in want.iter().enumerate() { + let xsum: Expression = bs + .iter() + .enumerate() + .filter(|&(_, b)| b.contains(&(n as u32))) + .map(|(x, _)| xs[x]) + .sum(); + model = model.with(constraint!(xsum == *w)); + } + + model.solve().unwrap().eval(&obj).round() as usize +} diff --git a/aoc/2025/11/rust/Cargo.lock b/aoc/2025/11/rust/Cargo.lock new file mode 100644 index 0000000..ac79b17 --- /dev/null +++ b/aoc/2025/11/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "puzzle" +version = "0.1.0" diff --git a/aoc/2025/11/rust/Cargo.toml b/aoc/2025/11/rust/Cargo.toml new file mode 100644 index 0000000..26e4e77 --- /dev/null +++ b/aoc/2025/11/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "puzzle" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/aoc/2025/11/rust/src/main.rs b/aoc/2025/11/rust/src/main.rs new file mode 100644 index 0000000..522d7ad --- /dev/null +++ b/aoc/2025/11/rust/src/main.rs @@ -0,0 +1,84 @@ +use std::{cell::RefCell, collections::HashMap, io, rc::Rc}; + +#[derive(PartialEq, Eq, Hash, Debug)] +struct Node { + device: String, + dac: bool, + fft: bool, +} + +fn main() { + let adj = io::stdin() + .lines() + .flatten() + .map(|line| { + let (k, v) = line.split_once(": ").unwrap(); + ( + String::from(k), + String::from(v) + .split_whitespace() + .map(String::from) + .collect(), + ) + }) + .collect::>>(); + + let cache = Rc::new(RefCell::new(HashMap::new())); + + let silver = paths_from( + Node { + device: String::from("you"), + dac: true, + fft: true, + }, + &adj, + Rc::clone(&cache), + ); + let gold = paths_from( + Node { + device: String::from("svr"), + dac: false, + fft: false, + }, + &adj, + Rc::clone(&cache), + ); + + println!("silver: {silver}"); + println!("gold: {gold}"); +} + +fn paths_from( + curr: Node, + adj: &HashMap>, + cache: Rc>>, +) -> usize { + if curr.device == "out" { + if curr.dac && curr.fft { + return 1; + } + return 0; + } + + let Some(&v) = cache.borrow().get(&curr) else { + let paths = adj + .get(&curr.device) + .unwrap() + .iter() + .map(|n| { + paths_from( + Node { + device: n.clone(), + dac: curr.dac || curr.device == "dac", + fft: curr.fft || curr.device == "fft", + }, + adj, + Rc::clone(&cache), + ) + }) + .sum(); + cache.borrow_mut().insert(curr, paths); + return paths; + }; + return v; +} diff --git a/aoc/2025/12/python.py b/aoc/2025/12/python.py new file mode 100755 index 0000000..c3b5158 --- /dev/null +++ b/aoc/2025/12/python.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +from fileinput import input +from itertools import takewhile + + +def check(s: str): + return eval(s.replace(": ", ">=9*(").replace("x", "*").replace(" ", "+") + ")") + + +silver = sum( + map( + check, + takewhile( + bool, + [line.strip() for line in input()][::-1], + ), + ) +) + +print("silver:", silver) diff --git a/check b/check index 73a35ac..9cf74e6 100755 --- a/check +++ b/check @@ -1,42 +1,41 @@ #!/usr/bin/env sh -usage="usage: check []" -year=${1?$usage} -day=${2?$usage} -lang=${3?$usage} -input=${4?$usage} -bench=$5 +usage="usage: check []" +puzzle=${1?$usage} +lang=${2?$usage} +input=${3?$usage} +bench=$4 # get directory of this script -script=$(readlink -f $0) -script_path=$(dirname $script) +script=$(readlink -f "$0") +script_path=$(dirname "$script") -# find aoc and data paths -aoc_path=$script_path/$year/$day -data_path=$aoc_path/data/$input.txt +# get puzzle and data paths +puzzle_path="$script_path"/"$puzzle" +data_path="$puzzle_path"/data/"$input".txt case $lang in python) - solve=$aoc_path/python.py + solve="$puzzle_path"/python.py ;; raku) - solve=$aoc_path/raku.raku + solve="$puzzle_path"/raku.raku ;; rust) - cargo build --target-dir /tmp/aoc_rust --manifest-path $aoc_path/rust/Cargo.toml - solve=/tmp/aoc_rust/debug/aoc_$year-$day + cargo build --target-dir /tmp/puzzle_rust --manifest-path "$puzzle_path"/rust/Cargo.toml + solve=/tmp/puzzle_rust/debug/puzzle ;; rustc) - cargo build --release --target-dir /tmp/aoc_rust --manifest-path $aoc_path/rust/Cargo.toml - solve=/tmp/aoc_rust/release/aoc_$year-$day + cargo build --release --target-dir /tmp/puzzle_rust --manifest-path "$puzzle_path"/rust/Cargo.toml + solve=/tmp/puzzle_rust/release/puzzle ;; c) - gcc $aoc_path/c.c -Wall -Wextra -Werror -std=c23 -o /tmp/aoc_c - solve=/tmp/aoc_c + gcc "$puzzle_path"/c.c -Wall -Wextra -Werror -std=c23 -o /tmp/puzzle_c + solve=/tmp/puzzle_c ;; cc) - gcc $aoc_path/c.c -Wall -Wextra -Werror -std=c23 -O3 -o /tmp/aoc_c - solve=/tmp/aoc_c + gcc "$puzzle_path"/c.c -Wall -Wextra -Werror -std=c23 -O3 -o /tmp/puzzle_c + solve=/tmp/puzzle_c ;; *) echo "unknown lang: $lang" @@ -44,14 +43,14 @@ cc) ;; esac -result=$(cat $data_path | $solve) -diff=$(echo "$result" | diff $aoc_path/data/$4.ans -) +result=$(cat "$data_path" | $solve) +diff=$(echo "$result" | diff "$puzzle_path"/data/"$3".ans -) code=$? -[ $code -eq 0 ] && echo Solved with $lang! || echo "$diff" +[ $code -eq 0 ] && echo Solved with "$lang"! || echo "$diff" -[ -n "$bench" ] && hyperfine --shell none --input $data_path $solve && exit 0 +[ -n "$bench" ] && hyperfine --shell none --input "$data_path" "$solve" && exit 0 -echo "\n---stdout---" +printf "\n---stdout---\n" echo "$result" exit $code diff --git a/init b/init index 79d8c69..2ba23ec 100755 --- a/init +++ b/init @@ -1,38 +1,36 @@ #!/usr/bin/env sh -usage="usage: init " -year=${1?$usage} -day=${2?$usage} -lang=${3?$usage} +usage="usage: init " +puzzle=${1?$usage} +lang=${2?$usage} # get directory of this script -script=$(readlink -f $0) -script_path=$(dirname $script) +script=$(readlink -f "$0") +script_path=$(dirname "$script") -aoc_path=$script_path/$year/$day +puzzle_path="$script_path"/"$puzzle" -mkdir --parents $aoc_path -touch $aoc_path/puzzle.txt +mkdir --parents "$puzzle_path" +touch "$puzzle_path"/puzzle.txt # data directory -if [ ! -d $aoc_path/data ]; then - mkdir --parents $aoc_path/data - for f in "test" "aoc"; do - touch $aoc_path/data/$f.txt - echo "silver: ???\ngold: ???" >$aoc_path/data/$f.ans - done +if [ ! -d "$puzzle_path"/data ]; then + mkdir "$puzzle_path"/data + + touch "$puzzle_path"/data/test.txt + touch "$puzzle_path"/data/test.ans fi case $lang in python) - cp $script_path/template/python.py $aoc_path + cp "$script_path"/template/python.py "$puzzle_path" ;; rust) - cargo new --vcs none --name aoc_$year-$day $aoc_path/rust - cp $script_path/template/main.rs $aoc_path/rust/src/main.rs + cargo new --vcs none --name puzzle "$puzzle_path"/rust + cp "$script_path"/template/main.rs "$puzzle_path"/rust/src/main.rs ;; *) - echo unknown lang: $lang + echo unknown lang: "$lang" exit 1 ;; esac diff --git a/template/python.py b/template/python.py old mode 100644 new mode 100755 -- cgit v1.2.3