Skip to content

Commit

Permalink
Year 2018 Day 5
Browse files Browse the repository at this point in the history
  • Loading branch information
maneatingape committed Jul 20, 2024
1 parent 7e06d83 commit 035ee9d
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
| 2 | [Inventory Management System](https://adventofcode.com/2018/day/2) | [Source](src/year2018/day02.rs) | 77 |
| 3 | [No Matter How You Slice It](https://adventofcode.com/2018/day/3) | [Source](src/year2018/day03.rs) | 56 |
| 4 | [Repose Record](https://adventofcode.com/2018/day/4) | [Source](src/year2018/day04.rs) | 46 |
| 5 | [Alchemical Reduction](https://adventofcode.com/2018/day/5) | [Source](src/year2018/day05.rs) | 353 |

## 2017

Expand Down
1 change: 1 addition & 0 deletions benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ mod year2018 {
benchmark!(year2018, day02);
benchmark!(year2018, day03);
benchmark!(year2018, day04);
benchmark!(year2018, day05);
}

mod year2019 {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ pub mod year2018 {
pub mod day02;
pub mod day03;
pub mod day04;
pub mod day05;
}

/// # Rescue Santa from deep space with a solar system adventure.
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ fn year2018() -> Vec<Solution> {
solution!(year2018, day02),
solution!(year2018, day03),
solution!(year2018, day04),
solution!(year2018, day05),
]
}

Expand Down
65 changes: 65 additions & 0 deletions src/year2018/day05.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! # Alchemical Reduction
//!
//! ## Part One
//!
//! This problem is similar to checking if a parentheses expression is balanced or not.
//! We use a similar approach, maintaining a stack of unreacted polymer units. Each unit from the
//! polymer is compared to the head of the stack using bitwise logic. Lowercase and uppercase ASCII
//! codes for the same lettter are always are 32 apart, which can be checked very quickly using
//! bitwise XOR. For example:
//!
//! ```none
//! A = 65 = 01000001
//! a = 97 = 01100001
//! A ^ a = 32 = 00100000
//! ```
//!
//! If two units are the same type but opposite polarity then they are popped from the stack.
//!
//! ## Part Two
//!
//! An important optimization is to use the already reacted polymer from part one. This is
//! approximately 20% of the size of the raw input. Then this smaller polymer is filtered
//! further for each of the 26 kinds of unit.
pub fn parse(input: &str) -> Vec<u8> {
collapse(input.trim().bytes())
}

pub fn part1(input: &[u8]) -> usize {
input.len()
}

pub fn part2(input: &[u8]) -> usize {
(b'a'..=b'z')
.map(|kind| collapse(input.iter().copied().filter(|&b| b | 32 != kind)).len())
.min()
.unwrap()
}

fn collapse(polymer: impl Iterator<Item = u8>) -> Vec<u8> {
// It's faster to keep the head of the stack in a dedicated variable. 0 is used as a special
// sentinel kind to indicate an empty stack as it will never match with any unit kind.
let mut head = 0;
let mut stack = Vec::with_capacity(10_000);

for unit in polymer {
// Uppercase and lowercase ASCII are always 32 apart.
if head ^ unit == 32 {
// The head reacts with the unit to annihilate each other so replace with the next unit
// from the stack.
head = stack.pop().unwrap_or(0);
} else {
// Don't push sentinel values.
if head != 0 {
stack.push(head);
}
head = unit;
}
}

if head != 0 {
stack.push(head);
}

stack
}
1 change: 1 addition & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ mod year2018 {
mod day02_test;
mod day03_test;
mod day04_test;
mod day05_test;
}

mod year2019 {
Expand Down
15 changes: 15 additions & 0 deletions tests/year2018/day05_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use aoc::year2018::day05::*;

const EXAMPLE: &str = "dabAcCaCBAcCcaDA";

#[test]
fn part1_test() {
let input = parse(EXAMPLE);
assert_eq!(part1(&input), 10);
}

#[test]
fn part2_test() {
let input = parse(EXAMPLE);
assert_eq!(part2(&input), 4);
}

0 comments on commit 035ee9d

Please sign in to comment.