diff --git a/aoc2020/aoc2020_bench/benches/aoc2020_bench.rs b/aoc2020/aoc2020_bench/benches/aoc2020_bench.rs index f10e1ce..b83d30a 100644 --- a/aoc2020/aoc2020_bench/benches/aoc2020_bench.rs +++ b/aoc2020/aoc2020_bench/benches/aoc2020_bench.rs @@ -20,6 +20,7 @@ use aoc2020::day17; use aoc2020::day18; use aoc2020::day19; use aoc2020::day21; +use aoc2020::day22; fn aoc2020_all(c: &mut Criterion) { c.bench_function("day01", |b| b.iter(|| day01::run().unwrap())); @@ -42,6 +43,7 @@ fn aoc2020_all(c: &mut Criterion) { c.bench_function("day18", |b| b.iter(|| day18::run().unwrap())); c.bench_function("day19", |b| b.iter(|| day19::run().unwrap())); c.bench_function("day21", |b| b.iter(|| day21::run().unwrap())); + c.bench_function("day22", |b| b.iter(|| day22::run().unwrap())); } criterion_group! { diff --git a/aoc2020/input/day22.txt b/aoc2020/input/day22.txt new file mode 100644 index 0000000..fbad1be --- /dev/null +++ b/aoc2020/input/day22.txt @@ -0,0 +1,53 @@ +Player 1: +43 +36 +13 +11 +20 +25 +37 +38 +4 +18 +1 +8 +27 +23 +7 +22 +10 +5 +50 +40 +45 +26 +15 +32 +33 + +Player 2: +21 +29 +12 +28 +46 +9 +44 +6 +16 +39 +19 +24 +17 +14 +47 +48 +42 +34 +31 +3 +41 +35 +2 +30 +49 diff --git a/aoc2020/input/day22_provided.txt b/aoc2020/input/day22_provided.txt new file mode 100644 index 0000000..391cd24 --- /dev/null +++ b/aoc2020/input/day22_provided.txt @@ -0,0 +1,13 @@ +Player 1: +9 +2 +6 +3 +1 + +Player 2: +5 +8 +4 +7 +10 diff --git a/aoc2020/src/day22.rs b/aoc2020/src/day22.rs new file mode 100644 index 0000000..c5e99d2 --- /dev/null +++ b/aoc2020/src/day22.rs @@ -0,0 +1,95 @@ +use std::cmp::Ordering; +use std::collections::VecDeque; +use std::fmt::Write; + +use anyhow::{Context, Result}; + +const INPUT: &str = include_str!("../input/day22.txt"); + +pub fn run() -> Result { + let mut res = String::with_capacity(128); + + writeln!(res, "part 1: {}", part1(INPUT)?)?; + + Ok(res) +} + +fn play_game<'a>(deck_a: &'a mut Deck, deck_b: &'a mut Deck) -> &'a Deck { + while !(deck_a.0.is_empty() || deck_b.0.is_empty()) { + let card_a = deck_a.0.pop_front().unwrap(); + let card_b = deck_b.0.pop_front().unwrap(); + + match card_a.cmp(&card_b) { + Ordering::Greater => { + deck_a.0.push_back(card_a); + deck_a.0.push_back(card_b); + } + Ordering::Less => { + deck_b.0.push_back(card_b); + deck_b.0.push_back(card_a); + } + Ordering::Equal => unreachable!(), + } + } + + if deck_a.0.is_empty() { + deck_b + } else { + deck_a + } +} + +fn part1(input: &str) -> Result { + let mut decks = input.split("\n\n"); + + let mut deck_a: Deck = decks.next().context("couldn't get first deck")?.parse()?; + let mut deck_b: Deck = decks.next().context("couldn't get second deck")?.parse()?; + + let winning_deck = play_game(&mut deck_a, &mut deck_b); + + Ok(winning_deck + .0 + .iter() + .rev() + .enumerate() + .map(|(i, card)| card * (i as u64 + 1)) + .sum()) +} + +struct Deck(VecDeque); + +impl Deck {} + +impl std::str::FromStr for Deck { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let mut lines = s.lines(); + + // `Player N:` + lines.next().context("couldn't skip first line")?; + + let deck = lines + .map(|line| line.parse().map_err(anyhow::Error::new)) + .collect::>()?; + + Ok(Self(deck)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const PROVIDED: &str = include_str!("../input/day22_provided.txt"); + + #[test] + fn part1_provided() { + assert_eq!(part1(PROVIDED).unwrap(), 306); + } + + #[test] + fn part1_real() { + assert_eq!(part1(INPUT).unwrap(), 30780); + } +} diff --git a/aoc2020/src/lib.rs b/aoc2020/src/lib.rs index 65e5593..54841ba 100644 --- a/aoc2020/src/lib.rs +++ b/aoc2020/src/lib.rs @@ -20,3 +20,4 @@ pub mod day17; pub mod day18; pub mod day19; pub mod day21; +pub mod day22; diff --git a/aoc2020/src/main.rs b/aoc2020/src/main.rs index f5192b3..1629aff 100644 --- a/aoc2020/src/main.rs +++ b/aoc2020/src/main.rs @@ -22,6 +22,7 @@ use aoc2020::day17; use aoc2020::day18; use aoc2020::day19; use aoc2020::day21; +use aoc2020::day22; fn main() -> Result<()> { let days: &[DayFunc] = &[ @@ -45,6 +46,7 @@ fn main() -> Result<()> { day18::run, day19::run, day21::run, + day22::run, ]; aoc::run(days)