Skip to content

Commit

Permalink
[2021] Complete day 12 and 14 part b
Browse files Browse the repository at this point in the history
  • Loading branch information
connorslade committed Nov 27, 2024
1 parent 2275dce commit 2d0bcb3
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 43 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ aoc_2024 = { path = "aoc_2024" }
clap = { version = "4.0.29", features = ["derive"] }
chrono = "0.4.31"
anyhow = "1.0.75"


[profile.release]
overflow-checks = true
incremental = true
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,7 @@ Thank you to [Eric Wastl](http://was.tl) for running this incredible yearly even
- [Day 09: Smoke Basin](aoc_2021/src/day_09.rs)
- [Day 10: Syntax Scoring](aoc_2021/src/day_10.rs)
- [Day 11: Dumbo Octopus](aoc_2021/src/day_11.rs)
- [Day 12: Passage Pathing](aoc_2021/src/day_12.rs)
- [Day 13: Transparent Origami](aoc_2021/src/day_13.rs)
- [Day 14: Extended Polymerization](aoc_2021/src/day_14.rs)
- [Day 15: Chiton](aoc_2021/src/day_15.rs)
62 changes: 46 additions & 16 deletions aoc_2021/src/day_12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,56 @@ solution!("Passage Pathing", 12);

fn part_a(input: &str) -> Answer {
let graph = parse(input);
paths_a(&graph, graph.start, HashSet::new()).into()
}

fn part_b(_input: &str) -> Answer {
Answer::Unimplemented
}
fn paths(graph: &ParseResult, at: NodeIndex, mut visited: HashSet<NodeIndex>) -> usize {
if at == graph.end {
return 1;
}

if !visited.insert(at) && graph.graph[at].cave_type != Type::Big {
return 0;
}

fn paths_a(graph: &ParseResult, at: NodeIndex, mut visited: HashSet<NodeIndex>) -> usize {
if at == graph.end {
return 1;
graph
.graph
.neighbors(at)
.map(|child| paths(graph, child, visited.clone()))
.sum()
}

if !visited.insert(at) && graph.graph[at].cave_type != Type::Big {
return 0;
paths(&graph, graph.start, HashSet::new()).into()
}

fn part_b(input: &str) -> Answer {
let graph = parse(input);

fn paths(
graph: &ParseResult,
at: NodeIndex,
mut visited: HashSet<NodeIndex>,
mut small_twice: bool,
) -> usize {
if at == graph.end {
return 1;
}

let cave = graph.graph[at].cave_type;
if !visited.insert(at) && cave != Type::Big {
if !small_twice && cave == Type::Small {
small_twice = true;
} else {
return 0;
}
}

graph
.graph
.neighbors(at)
.map(|child| paths(graph, child, visited.clone(), small_twice))
.sum()
}

graph
.graph
.neighbors(at)
.map(|child| paths_a(graph, child, visited.clone()))
.sum()
paths(&graph, graph.start, HashSet::new(), false).into()
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -130,6 +159,7 @@ mod test {

#[test]
fn part_b() {
assert_eq!(super::part_b(CASE), ().into()); // 36
assert_eq!(super::part_b(CASE), 36.into());
assert_eq!(super::part_b(CASE_2), 103.into());
}
}
94 changes: 67 additions & 27 deletions aoc_2021/src/day_14.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,13 @@ fn part_a(input: &str) -> Answer {
process(input, 10).into()
}

// TODO: work with counts of units instead of the units themselves
fn part_b(input: &str) -> Answer {
let mut _polymer = Polymer::parse(input);
Answer::Unimplemented
process(input, 40).into()
}

fn process(raw: &str, steps: usize) -> usize {
let mut polymer = Polymer::parse(raw);
(0..steps).for_each(|_| polymer.step());

let (min, max) = polymer.min_max();
max - min
fn process(raw: &str, steps: usize) -> u64 {
let counts = Polymer::parse(raw).process(steps);
counts.iter().max().unwrap() - counts.iter().filter(|&&x| x != 0).min().unwrap()
}

#[derive(Debug)]
Expand All @@ -29,29 +24,38 @@ struct Polymer {
}

impl Polymer {
fn step(&mut self) {
let mut next = Vec::new();
for i in self.units.windows(2) {
next.push(i[0]);
fn process(&mut self, steps: usize) -> [u64; 26] {
fn index(unit: char) -> usize {
unit as usize - 'A' as usize
}

if let Some(i) = self.key.get(i) {
next.push(*i);
}
let mut pairs = HashMap::<_, u64>::new();
let mut counts = [0; 26];

counts[index(*self.units.last().unwrap())] += 1;
for units in self.units.windows(2) {
counts[index(units[0])] += 1;
*pairs.entry([units[0], units[1]]).or_default() += 1;
}

next.push(*self.units.last().unwrap());
self.units = next;
}
// AB -> C
// (A, B) -> (A, C), (C, B)
// C += 1
for _ in 0..steps {
let mut new_pairs = HashMap::new();

fn min_max(&self) -> (usize, usize) {
let mut out = HashMap::new();
self.units
.iter()
.for_each(|i| *out.entry(*i).or_insert(0) += 1);
for (pair, count) in pairs.iter() {
let mapping = self.key[pair];

*new_pairs.entry([pair[0], mapping]).or_default() += count;
*new_pairs.entry([mapping, pair[1]]).or_default() += count;
counts[index(mapping)] += count;
}

pairs = new_pairs;
}

let mut out = out.into_iter().collect::<Vec<_>>();
out.sort_by(|a, b| a.1.cmp(&b.1));
(out[0].1, out[out.len() - 1].1)
counts
}

fn parse(raw: &str) -> Self {
Expand All @@ -73,3 +77,39 @@ impl Polymer {
}
}
}

#[cfg(test)]
mod test {
use indoc::indoc;

const CASE: &str = indoc! {"
NNCB
CH -> B
HH -> N
CB -> H
NH -> C
HB -> C
HC -> B
HN -> C
NN -> C
BH -> H
NC -> B
NB -> B
BN -> B
BB -> N
BC -> B
CC -> N
CN -> C
"};

#[test]
fn part_a() {
assert_eq!(super::part_a(CASE), 1588.into());
}

#[test]
fn part_b() {
assert_eq!(super::part_b(CASE), 2188189693529_u64.into());
}
}

0 comments on commit 2d0bcb3

Please sign in to comment.