Compare commits
3 Commits
237ca36381
...
main
Author | SHA1 | Date | |
---|---|---|---|
77fba87ef6
|
|||
8b8ed2a323
|
|||
6efb9e0f83
|
Binary file not shown.
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 8.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 7.1 KiB |
@ -1,6 +1,6 @@
|
||||
<!-- AOC TILES BEGIN -->
|
||||
<h1 align="center">
|
||||
2024 - 45 ⭐ - Rust
|
||||
2024 - 48 ⭐ - Rust
|
||||
</h1>
|
||||
<a href="src/day1.rs">
|
||||
<img src=".aoc_tiles/tiles/2024/01.png" width="161px">
|
||||
@ -71,4 +71,10 @@
|
||||
<a href="src/day23.rs">
|
||||
<img src=".aoc_tiles/tiles/2024/23.png" width="161px">
|
||||
</a>
|
||||
<a href="src/day24.rs">
|
||||
<img src=".aoc_tiles/tiles/2024/24.png" width="161px">
|
||||
</a>
|
||||
<a href="src/day25.rs">
|
||||
<img src=".aoc_tiles/tiles/2024/25.png" width="161px">
|
||||
</a>
|
||||
<!-- AOC TILES END -->
|
||||
|
31
src/day23.rs
31
src/day23.rs
@ -20,7 +20,7 @@ impl Display for Node {
|
||||
|
||||
impl From<[char; 2]> for Node {
|
||||
fn from(value: [char; 2]) -> Self {
|
||||
Node(value)
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,8 +33,8 @@ impl TryFrom<Vec<char>> for Node {
|
||||
}
|
||||
|
||||
struct Network {
|
||||
nodes: Vec<Node>,
|
||||
edges: FxHashMap<Node, Vec<Node>>,
|
||||
nodes: FxHashSet<Node>,
|
||||
edges: FxHashMap<Node, FxHashSet<Node>>,
|
||||
}
|
||||
|
||||
impl Network {
|
||||
@ -56,6 +56,8 @@ impl Network {
|
||||
}
|
||||
sets
|
||||
}
|
||||
// Had to study Wikipedia for this one
|
||||
// https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm
|
||||
fn bron_kerbosch(
|
||||
&self,
|
||||
r: FxHashSet<Node>,
|
||||
@ -65,8 +67,15 @@ impl Network {
|
||||
let mut results = Vec::new();
|
||||
if p.is_empty() && x.is_empty() {
|
||||
return vec![r];
|
||||
} else if p.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
let p_iter = p.clone(); // so we can modify p
|
||||
// choose the pivot with the most neighbours, to minimize the size of p_iter
|
||||
let p_iter = if let Some(pivot) = p.union(&x).max_by(|a, b| self.edges[a].len().cmp(&self.edges[b].len())) {
|
||||
FxHashSet::from_iter(p.difference(self.edges.get(pivot).unwrap()).copied())
|
||||
} else {
|
||||
p.clone()
|
||||
};
|
||||
for node in &p_iter {
|
||||
let mut new_r = r.clone();
|
||||
new_r.insert(*node);
|
||||
@ -92,7 +101,7 @@ impl Network {
|
||||
|
||||
impl From<&str> for Network {
|
||||
fn from(input: &str) -> Self {
|
||||
let mut nodes = Vec::new();
|
||||
let mut nodes = FxHashSet::default();
|
||||
let mut edges = FxHashMap::default();
|
||||
for line in input.lines() {
|
||||
let (node1, node2) = line.split_once('-').unwrap();
|
||||
@ -101,13 +110,13 @@ impl From<&str> for Network {
|
||||
node2.chars().collect_vec().try_into().unwrap(),
|
||||
);
|
||||
if !nodes.contains(&node1) {
|
||||
nodes.push(node1);
|
||||
nodes.insert(node1);
|
||||
}
|
||||
if !nodes.contains(&node2) {
|
||||
nodes.push(node2);
|
||||
nodes.insert(node2);
|
||||
}
|
||||
edges.entry(node1).or_insert(Vec::new()).push(node2);
|
||||
edges.entry(node2).or_insert(Vec::new()).push(node1);
|
||||
edges.entry(node1).or_insert(FxHashSet::default()).insert(node2);
|
||||
edges.entry(node2).or_insert(FxHashSet::default()).insert(node1);
|
||||
}
|
||||
Self { nodes, edges }
|
||||
}
|
||||
@ -120,10 +129,9 @@ fn parse(input: &str) -> Network {
|
||||
#[aoc(day23, part1)]
|
||||
pub fn part1(input: &str) -> i64 {
|
||||
let network = parse(input);
|
||||
// println!("edges: {:?}", network.edges);
|
||||
|
||||
let sets = network.groups_3();
|
||||
let t_count = sets.iter().filter(|set| set.iter().any(|s| s.0[0] == 't')).count();
|
||||
// println!("groups: {:?}", sets);
|
||||
|
||||
t_count as i64
|
||||
}
|
||||
@ -135,7 +143,6 @@ pub fn part2(input: &str) -> String {
|
||||
let largest_set = best_sets.iter().max_by(|a, b| a.len().cmp(&b.len())).unwrap();
|
||||
let mut largest = largest_set.iter().collect_vec();
|
||||
largest.sort();
|
||||
println!("best: {:?}", largest);
|
||||
largest.iter().join(",")
|
||||
}
|
||||
|
||||
|
229
src/day24.rs
Normal file
229
src/day24.rs
Normal file
@ -0,0 +1,229 @@
|
||||
use aoc_runner_derive::aoc;
|
||||
use itertools::Itertools;
|
||||
use nom::And;
|
||||
use regex::Regex;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum Op {
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
Constant,
|
||||
}
|
||||
|
||||
impl From<&str> for Op {
|
||||
fn from(value: &str) -> Self {
|
||||
match value {
|
||||
"AND" => Self::And,
|
||||
"OR" => Self::Or,
|
||||
"XOR" => Self::Xor,
|
||||
s => panic!("invalid operation {}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Gate {
|
||||
op: Op,
|
||||
value: Option<bool>,
|
||||
arguments: [String; 2],
|
||||
}
|
||||
|
||||
impl Gate {
|
||||
fn eval(&self, machine: &GateMachine) -> bool {
|
||||
match self.op {
|
||||
Op::And => machine.val_of(&self.arguments[0]) && machine.val_of(&self.arguments[1]),
|
||||
Op::Or => machine.val_of(&self.arguments[0]) || machine.val_of(&self.arguments[1]),
|
||||
Op::Xor => machine.val_of(&self.arguments[0]) ^ machine.val_of(&self.arguments[1]),
|
||||
Op::Constant => self.value.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GateMachine {
|
||||
gates: FxHashMap<String, Gate>,
|
||||
}
|
||||
|
||||
impl GateMachine {
|
||||
fn val_of(&self, gate: &str) -> bool {
|
||||
println!("gate: {}", gate);
|
||||
if let Some(val) = self.gates[gate].value {
|
||||
val
|
||||
} else {
|
||||
self.gates[gate].eval(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(input: &str) -> GateMachine {
|
||||
let mut gates = FxHashMap::default();
|
||||
for line in input.lines() {
|
||||
println!("{line}");
|
||||
let const_re = Regex::new(r"^([xyz][0-9]{2}): ([01])$").unwrap();
|
||||
let gate_re = Regex::new(r"^([a-z0-9]{3}) (AND|XOR|OR) ([a-z0-9]{3}) -> ([a-z0-9]{3})$").unwrap();
|
||||
|
||||
if let Some(caps) = const_re.captures(line) {
|
||||
println!(" is const: {:?}", caps);
|
||||
gates.insert(
|
||||
caps[1].to_string(),
|
||||
Gate {
|
||||
op: Op::Constant,
|
||||
value: if &caps[2] == "1" { Some(true) } else { Some(false) },
|
||||
arguments: [String::new(), String::new()],
|
||||
},
|
||||
);
|
||||
} else if let Some(caps) = gate_re.captures(line) {
|
||||
println!(" is gate: {:?}", caps);
|
||||
gates.insert(
|
||||
caps[4].to_string(),
|
||||
Gate {
|
||||
op: Op::from(&caps[2]),
|
||||
value: None,
|
||||
arguments: [caps[1].to_string(), caps[3].to_string()],
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
GateMachine { gates }
|
||||
}
|
||||
|
||||
#[aoc(day24, part1)]
|
||||
pub fn part1(input: &str) -> i64 {
|
||||
let machine = parse(input);
|
||||
let z_gates = machine
|
||||
.gates
|
||||
.keys()
|
||||
.filter(|k| k.starts_with('z'))
|
||||
.map(|s| (s, s.split_at(1).1.parse::<usize>().unwrap()));
|
||||
let bit_vals = z_gates
|
||||
.map(|(name, bit)| if machine.val_of(name) { 1 << bit } else { 0 })
|
||||
.fold(0, |accum, val| accum | val);
|
||||
bit_vals
|
||||
}
|
||||
|
||||
#[aoc(day24, part2)]
|
||||
pub fn part2(input: &str) -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
const EXAMPLE1: &str = "x00: 1
|
||||
x01: 1
|
||||
x02: 1
|
||||
y00: 0
|
||||
y01: 1
|
||||
y02: 0
|
||||
|
||||
x00 AND y00 -> z00
|
||||
x01 XOR y01 -> z01x00: 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
|
||||
x02 OR y02 -> z02";
|
||||
|
||||
const EXAMPLE2: &str = "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";
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
assert_eq!(part1(EXAMPLE1), 4);
|
||||
assert_eq!(part1(EXAMPLE2), 2024);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
assert_eq!(part2(EXAMPLE1), 0);
|
||||
}
|
||||
}
|
143
src/day25.rs
Normal file
143
src/day25.rs
Normal file
@ -0,0 +1,143 @@
|
||||
use aoc_runner_derive::aoc;
|
||||
use itertools::Itertools;
|
||||
|
||||
enum LockKey {
|
||||
Lock,
|
||||
Key,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct LockPile {
|
||||
keys: Vec<Vec<usize>>,
|
||||
locks: Vec<Vec<usize>>,
|
||||
}
|
||||
|
||||
fn parse_grid(lines: &Vec<&str>) -> (LockKey, Vec<usize>) {
|
||||
assert_eq!(lines.len(), 7);
|
||||
if lines[0].chars().all(|c| c == '#') {
|
||||
// lock
|
||||
let mut pins = vec![0; 5];
|
||||
for row in 1..lines.len() {
|
||||
let row_s = lines[row];
|
||||
for i in 0..row_s.len() {
|
||||
if row_s.chars().nth(i) == Some('#') {
|
||||
pins[i] = row
|
||||
}
|
||||
}
|
||||
}
|
||||
(LockKey::Lock, pins)
|
||||
} else if lines[6].chars().all(|c| c == '#') {
|
||||
// key
|
||||
let mut pins = vec![5; 5];
|
||||
for row in (1..lines.len()).rev() {
|
||||
let row_s = lines[row];
|
||||
for i in 0..row_s.len() {
|
||||
if row_s.chars().nth(i) == Some('#') {
|
||||
pins[i] = 6 - row
|
||||
}
|
||||
}
|
||||
}
|
||||
(LockKey::Key, pins)
|
||||
} else {
|
||||
panic!("not a lock or a key: {:?}", lines);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(input: &str) -> LockPile {
|
||||
let mut locks = Vec::new();
|
||||
let mut keys = Vec::new();
|
||||
let mut accum: Vec<&str> = Vec::new();
|
||||
for line in input.lines() {
|
||||
if line == "" {
|
||||
let (lk, pins) = parse_grid(&accum);
|
||||
match lk {
|
||||
LockKey::Lock => locks.push(pins),
|
||||
LockKey::Key => keys.push(pins),
|
||||
}
|
||||
accum.clear();
|
||||
} else {
|
||||
accum.push(line);
|
||||
}
|
||||
}
|
||||
if accum.len() != 0 {
|
||||
let (lk, pins) = parse_grid(&accum);
|
||||
match lk {
|
||||
LockKey::Lock => locks.push(pins),
|
||||
LockKey::Key => keys.push(pins),
|
||||
}
|
||||
}
|
||||
LockPile { keys, locks }
|
||||
}
|
||||
|
||||
fn test_lock_key(lock: &Vec<usize>, key: &Vec<usize>) -> bool {
|
||||
!lock.iter().zip(key.iter()).any(|(lp, kp)| lp + kp > 5)
|
||||
}
|
||||
|
||||
#[aoc(day25, part1)]
|
||||
pub fn part1(input: &str) -> i64 {
|
||||
let lockpile = parse(input);
|
||||
|
||||
lockpile
|
||||
.locks
|
||||
.iter()
|
||||
.cartesian_product(lockpile.keys.iter())
|
||||
.filter(|(l, k)| test_lock_key(l, k))
|
||||
.count() as i64
|
||||
}
|
||||
|
||||
#[aoc(day25, part2)]
|
||||
pub fn part2(_input: &str) -> String {
|
||||
"run the other solutions for day 25 part 2!".to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
const EXAMPLE: &str = "#####
|
||||
.####
|
||||
.####
|
||||
.####
|
||||
.#.#.
|
||||
.#...
|
||||
.....
|
||||
|
||||
#####
|
||||
##.##
|
||||
.#.##
|
||||
...##
|
||||
...#.
|
||||
...#.
|
||||
.....
|
||||
|
||||
.....
|
||||
#....
|
||||
#....
|
||||
#...#
|
||||
#.#.#
|
||||
#.###
|
||||
#####
|
||||
|
||||
.....
|
||||
.....
|
||||
#.#..
|
||||
###..
|
||||
###.#
|
||||
###.#
|
||||
#####
|
||||
|
||||
.....
|
||||
.....
|
||||
.....
|
||||
#....
|
||||
#.#..
|
||||
#.#.#
|
||||
#####";
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
assert_eq!(part1(EXAMPLE), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {}
|
||||
}
|
@ -14,6 +14,8 @@ pub mod day20;
|
||||
pub mod day21;
|
||||
pub mod day22;
|
||||
pub mod day23;
|
||||
pub mod day24;
|
||||
pub mod day25;
|
||||
pub mod day3;
|
||||
pub mod day4;
|
||||
pub mod day5;
|
||||
|
Reference in New Issue
Block a user