From 5a055b3fb194ef9186bd8b163481706af553a1bd Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Tue, 22 Dec 2020 09:11:27 +0100 Subject: [PATCH] Implementation day 22. --- 2020/benches/days.rs | 2 +- 2020/inputs/22.txt | 53 ++++++++++++++++++++ 2020/samples/22.txt | 13 +++++ 2020/src/day22.rs | 114 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 2020/inputs/22.txt create mode 100644 2020/samples/22.txt diff --git a/2020/benches/days.rs b/2020/benches/days.rs index eed6a9e..4f10991 100644 --- a/2020/benches/days.rs +++ b/2020/benches/days.rs @@ -7,7 +7,7 @@ use criterion::criterion_main; use criterion::BenchmarkId; use criterion::Criterion; -const DAYS_IMPLEMENTED: usize = 20; +const DAYS_IMPLEMENTED: usize = 22; fn read_input(day: usize) -> Vec { let input_path = format!("inputs/{:02}.txt", day); diff --git a/2020/inputs/22.txt b/2020/inputs/22.txt new file mode 100644 index 0000000..546ae56 --- /dev/null +++ b/2020/inputs/22.txt @@ -0,0 +1,53 @@ +Player 1: +26 +14 +6 +34 +37 +9 +17 +39 +4 +5 +1 +8 +49 +16 +18 +47 +20 +31 +23 +19 +35 +41 +28 +15 +44 + +Player 2: +7 +2 +10 +25 +29 +46 +40 +45 +11 +50 +42 +24 +38 +13 +36 +22 +33 +3 +43 +21 +48 +30 +32 +12 +27 diff --git a/2020/samples/22.txt b/2020/samples/22.txt new file mode 100644 index 0000000..391cd24 --- /dev/null +++ b/2020/samples/22.txt @@ -0,0 +1,13 @@ +Player 1: +9 +2 +6 +3 +1 + +Player 2: +5 +8 +4 +7 +10 diff --git a/2020/src/day22.rs b/2020/src/day22.rs index f51a2b2..5d448b4 100644 --- a/2020/src/day22.rs +++ b/2020/src/day22.rs @@ -1,12 +1,122 @@ +use std::collections::HashSet; +use std::collections::VecDeque; use std::io::Read; +use crate::common::Lines; use crate::Solution; +type Deck = VecDeque; + +fn read_input(input: &mut dyn Read) -> (Deck, Deck) { + let mut lines = Lines::new(input).skip(1); + + let mut player1 = VecDeque::new(); + + while let Some(line) = lines.next() { + if line.is_empty() { + break; + } + + player1.push_back(line.parse().unwrap()); + } + + let player2 = lines.skip(1).map(|l| l.parse().unwrap()).collect(); + + (player1, player2) +} + +fn play_recursive_game(mut p1: Deck, mut p2: Deck) -> (bool, Deck) { + let mut seen = HashSet::new(); + + while !p1.is_empty() && !p2.is_empty() { + if !seen.insert((p1.clone(), p2.clone())) { + return (true, p1); + } + + let v1 = p1.pop_front().unwrap(); + let v2 = p2.pop_front().unwrap(); + + let p1_wins = if v1 as usize <= p1.len() && v2 as usize <= p2.len() { + let p1_copy = p1.iter().take(v1 as usize).copied().collect(); + let p2_copy = p2.iter().take(v2 as usize).copied().collect(); + + play_recursive_game(p1_copy, p2_copy).0 + } else { + v1 > v2 + }; + + if p1_wins { + p1.push_back(v1); + p1.push_back(v2); + } else { + p2.push_back(v2); + p2.push_back(v1); + } + } + + if p1.is_empty() { + (false, p2) + } else { + (true, p1) + } +} + +fn score(winner: Deck) -> u32 { + winner + .into_iter() + .rev() + .enumerate() + .map(|(pos, val)| (pos as u32 + 1) * (val as u32)) + .sum() +} + #[derive(Default)] pub struct Day22; impl Solution for Day22 { - fn part1(&mut self, _input: &mut dyn Read) -> String { - todo!() + fn part1(&mut self, input: &mut dyn Read) -> String { + let (mut p1, mut p2) = read_input(input); + + while !p1.is_empty() && !p2.is_empty() { + let v1 = p1.pop_front().unwrap(); + let v2 = p2.pop_front().unwrap(); + + if v1 > v2 { + p1.push_back(v1); + p1.push_back(v2); + } else { + p2.push_back(v2); + p2.push_back(v1); + } + } + + let winner = if p1.is_empty() { p2 } else { p1 }; + + score(winner).to_string() + } + + fn part2(&mut self, input: &mut dyn Read) -> String { + let (p1, p2) = read_input(input); + + score(play_recursive_game(p1, p2).1).to_string() + } +} + +#[cfg(test)] +mod tests { + use crate::test_implementation; + + use super::*; + + const SAMPLE: &[u8] = include_bytes!("../samples/22.txt"); + + #[test] + fn sample_part1() { + test_implementation!(Day22, 1, SAMPLE, 306); + } + + #[test] + fn sample_part2() { + test_implementation!(Day22, 2, SAMPLE, 291); } }