Compare commits

...

4 Commits

Author SHA1 Message Date
00000340e7 solution: day 25 2025-01-02 22:45:07 +01:00
0000033060 solution: day 24 2025-01-02 22:43:58 +01:00
000003208e chore: run cargo fmt 2024-12-23 19:38:33 +01:00
000003103e solution: day 23 2024-12-23 19:38:23 +01:00
10 changed files with 409 additions and 8 deletions

32
data/examples/23.txt Normal file
View File

@@ -0,0 +1,32 @@
kh-tc
qp-kh
de-cg
ka-co
yn-aq
qp-ub
cg-tb
vc-aq
tb-ka
wh-tc
yn-cg
kh-ub
ta-co
de-co
tc-td
tb-wq
wh-td
ta-ka
td-qp
aq-cg
wq-ub
ub-vc
de-ta
wq-aq
wq-vc
wh-yn
ka-de
kh-ta
co-tc
wh-qp
tb-vc
td-yn

47
data/examples/24.txt Normal file
View File

@@ -0,0 +1,47 @@
x00: 1
x01: 0
x02: 1
x03: 1
x04: 0
y00: 1
y01: 1
y02: 1
y03: 1
y04: 1
ntg XOR fgs -> mjb
y02 OR x01 -> tnw
kwq OR kpj -> z05
x00 OR x03 -> fst
tgd XOR rvg -> z01
vdt OR tnw -> bfw
bfw AND frj -> z10
ffh OR nrd -> bqk
y00 AND y03 -> djm
y03 OR y00 -> psh
bqk OR frj -> z08
tnw OR fst -> frj
gnj AND tgd -> z11
bfw XOR mjb -> z00
x03 OR x00 -> vdt
gnj AND wpb -> z02
x04 AND y00 -> kjc
djm OR pbm -> qhw
nrd AND vdt -> hwm
kjc AND fst -> rvg
y04 OR y02 -> fgs
y01 AND x02 -> pbm
ntg OR kjc -> kwq
psh XOR fgs -> tgd
qhw XOR tgd -> z09
pbm OR djm -> kpj
x03 XOR y03 -> ffh
x00 XOR y04 -> ntg
bfw OR bqk -> z06
nrd XOR fgs -> wpb
frj XOR qhw -> z04
bqk OR frj -> z07
y03 OR x01 -> nrd
hwm AND bqk -> z03
tgd XOR rvg -> z12
tnw OR pbm -> gnj

39
data/examples/25.txt Normal file
View File

@@ -0,0 +1,39 @@
#####
.####
.####
.####
.#.#.
.#...
.....
#####
##.##
.#.##
...##
...#.
...#.
.....
.....
#....
#....
#...#
#.#.#
#.###
#####
.....
.....
#.#..
###..
###.#
###.#
#####
.....
.....
.....
#....
#.#..
#.#.#
#####

View File

@@ -200,10 +200,16 @@ mod tests {
use super::*;
#[test]
fn test_part_one() {
assert_eq!(part_one(&aoc::template::read_file("examples", 15)), Some(10092));
assert_eq!(
part_one(&aoc::template::read_file("examples", 15)),
Some(10092)
);
}
#[test]
fn test_part_two() {
assert_eq!(part_two(&aoc::template::read_file("examples", 15)), Some(9021));
assert_eq!(
part_two(&aoc::template::read_file("examples", 15)),
Some(9021)
);
}
}

View File

@@ -91,4 +91,3 @@ pub fn part_two(input: &str) -> Option<String> {
}
aoc::solution!(18);

View File

@@ -66,6 +66,9 @@ mod tests {
}
#[test]
fn test_part_two() {
assert_eq!(part_two(&aoc::template::read_file("examples", 19)), Some(16));
assert_eq!(
part_two(&aoc::template::read_file("examples", 19)),
Some(16)
);
}
}

88
src/bin/23.rs Normal file
View File

@@ -0,0 +1,88 @@
use std::collections::BTreeSet;
use hashbrown::{HashMap, HashSet};
use itertools::Itertools;
fn parse_graph(input: &str) -> HashMap<&str, BTreeSet<&str>> {
let nodes: HashSet<_> = input.lines().filter_map(|x| x.split_once('-')).collect();
let mut graph: HashMap<_, BTreeSet<_>> = HashMap::new();
for (n1, n2) in nodes.iter().copied() {
graph.entry(n1).or_default().insert(n2);
graph.entry(n2).or_default().insert(n1);
}
graph
}
pub fn part_one(input: &str) -> Option<usize> {
let graph = parse_graph(input);
let mut triples = HashSet::new();
for (n1, neigh) in graph.iter() {
for n2 in neigh.iter().copied() {
for n3 in graph[n2].iter() {
if graph[n3].contains(n1) && n1.starts_with('t') {
let mut triple = [n1, n2, n3];
triple.sort();
triples.insert(triple);
}
}
}
}
triples.len().into()
}
pub fn part_two(input: &str) -> Option<String> {
let graph = parse_graph(input);
let p: BTreeSet<_> = graph.keys().copied().collect();
let r = HashSet::new();
let x = BTreeSet::new();
let mut maximals = HashSet::new();
let mut stack = Vec::new();
stack.push((r, p, x));
while let Some((r, mut p, mut x)) = stack.pop() {
if p.is_empty() && x.is_empty() {
let mut password = r.iter().copied().collect_vec();
password.sort();
maximals.insert(password.join(","));
}
while let Some(pp) = p.pop_last() {
let mut nr = r.clone();
nr.insert(pp);
let np = &p & &graph[pp];
let nx = &x & &graph[pp];
stack.push((nr, np, nx));
x.insert(pp);
}
}
maximals.into_iter().max_by_key(|x| x.len())
}
aoc::solution!(23);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
assert_eq!(part_one(&aoc::template::read_file("examples", 23)), Some(7));
}
#[test]
fn test_part_two() {
assert_eq!(
part_two(&aoc::template::read_file("examples", 23)),
Some("co,de,ka,ta".to_string())
);
}
}

132
src/bin/24.rs Normal file
View File

@@ -0,0 +1,132 @@
use std::collections::VecDeque;
use hashbrown::HashMap;
use itertools::Itertools;
use regex::Regex;
#[derive(Debug, Clone, Copy)]
enum Gate {
And,
Or,
XOr,
}
#[derive(Debug)]
struct LogicGate<'a> {
input_one: &'a str,
input_two: &'a str,
output: &'a str,
gate: Gate,
}
fn parse_input(input: &str) -> (HashMap<&str, bool>, Vec<LogicGate>) {
let (uvals, uevals) = input.split_once("\n\n").unwrap();
let vals: HashMap<_, _> = uvals
.lines()
.map(|x| x.split_once(": ").unwrap())
.map(|(k, v)| (k, v == "1"))
.collect();
let mut logic_gates = Vec::new();
let re = Regex::new(r#"((?:\w|\d){3}) (AND|XOR|OR) ((?:\w|\d){3}) -> ((?:\w|\d){3})"#).unwrap();
for capt in re.captures_iter(uevals) {
let input_one = capt.get(1).unwrap().as_str();
let gate = match capt.get(2).unwrap().as_str() {
"AND" => Gate::And,
"OR" => Gate::Or,
"XOR" => Gate::XOr,
_ => unreachable!(),
};
let input_two = capt.get(3).unwrap().as_str();
let output = capt.get(4).unwrap().as_str();
logic_gates.push(LogicGate {
input_one,
input_two,
output,
gate,
})
}
(vals, logic_gates)
}
pub fn part_one(input: &str) -> Option<usize> {
let (mut vals, logic_gates) = parse_input(input);
let mut queue = VecDeque::from(logic_gates);
while let Some(s) = queue.pop_front() {
if !vals.contains_key(s.input_one) || !vals.contains_key(s.input_two) {
queue.push_back(s);
continue;
}
let v1 = vals[s.input_one];
let v2 = vals[s.input_two];
let o = match s.gate {
Gate::And => v1 & v2,
Gate::Or => v1 | v2,
Gate::XOr => v1 ^ v2,
};
vals.insert(s.output, o);
}
let mut zs = vals
.into_iter()
.filter(|x| x.0.starts_with('z'))
.collect_vec();
zs.sort();
zs.into_iter()
.enumerate()
.filter(|x| x.1 .1)
.map(|(i, _)| 1 << i)
.sum::<usize>()
.into()
}
pub fn part_two(_input: &str) -> Option<String> {
// Used graphviz for this part
// ```rs
// let (_, logic_gates) = parse_input(input);
// println!("digraph A {{");
// for (idx, lg) in logic_gates.iter().enumerate() {
// let LogicGate {
// input_one: i1,
// input_two: i2,
// output: o1,
// gate: g,
// } = lg;
// println!("{i1} -> {g:?}_{idx}");
// println!("{i2} -> {g:?}_{idx}");
// println!("{g:?}_{idx} -> {o1}");
// }
// println!("}}");
// ```
//
// and then pipe to dot
// ```bash
// ... | dot -Tsvg -Kneato > grpah.svg
// ```
//
// i looked for errors in the pattern and found below
// solution for my input
let mut res = ["fkp", "z06", "z11", "ngr", "z31", "mfm", "bpt", "krj"];
res.sort();
res.join(",").to_string().into()
}
aoc::solution!(24);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
assert_eq!(
part_one(&aoc::template::read_file("examples", 24)),
Some(2024)
);
}
}

57
src/bin/25.rs Normal file
View File

@@ -0,0 +1,57 @@
pub fn part_one(input: &str) -> Option<usize> {
let mut keys = Vec::new();
let mut locks = Vec::new();
for key_or_lock in input.split("\n\n") {
let lock = key_or_lock
.lines()
.next()
.unwrap()
.chars()
.all(|x| x == '#');
let mut columns = [0; 5];
for (idx, c) in key_or_lock.lines().flat_map(|x| x.chars().enumerate()) {
if c == '#' {
columns[idx] += 1;
}
}
// remove top or bottom row from count
for c in columns.iter_mut() {
*c -= 1;
}
if lock {
locks.push(columns);
} else {
keys.push(columns);
}
}
let mut count = 0;
for k in keys.iter() {
for l in locks.iter() {
if k.iter().zip(l.iter()).all(|(k, l)| k + l <= 5) {
count += 1;
}
}
}
count.into()
}
pub fn part_two(_input: &str) -> Option<String> {
"Happy christmas!".to_string().into()
}
aoc::solution!(25);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
assert_eq!(part_one(&aoc::template::read_file("examples", 25)), Some(3));
}
}

View File

@@ -1,9 +1,7 @@
mod grid;
mod direction;
mod grid;
mod point;
pub use grid::Grid;
pub use direction::Direction;
pub use grid::Grid;
pub use point::Point;