From 0750f8732e39c0aa21e8829df75cda52062bf9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Tue, 22 Dec 2020 09:40:19 +0100 Subject: [PATCH] day 22 --- data/day22/input | 53 ++++++++++++++++++++++++++ src/bin/day22.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 data/day22/input create mode 100644 src/bin/day22.rs diff --git a/data/day22/input b/data/day22/input new file mode 100644 index 0000000..6b5d6d5 --- /dev/null +++ b/data/day22/input @@ -0,0 +1,53 @@ +Player 1: +26 +8 +2 +17 +19 +29 +41 +7 +25 +33 +50 +16 +36 +37 +32 +4 +46 +12 +21 +48 +11 +6 +13 +23 +9 + +Player 2: +27 +47 +15 +45 +10 +14 +3 +44 +31 +39 +42 +5 +49 +24 +22 +20 +30 +1 +35 +38 +18 +43 +28 +40 +34 diff --git a/src/bin/day22.rs b/src/bin/day22.rs new file mode 100644 index 0000000..efa7a01 --- /dev/null +++ b/src/bin/day22.rs @@ -0,0 +1,98 @@ +use std::collections::{VecDeque, HashSet}; + +type Deck = VecDeque; + +const INPUT: &str = include_str!("../../data/day22/input"); + +fn parse_player(block: &str) -> (u32, Deck) { + let block = block.strip_prefix("Player ").unwrap(); + let player = block[..1].parse::().unwrap(); + let block = block[1..].strip_prefix(":").unwrap().trim(); + let deck = block.lines().map(|s| s.parse::().unwrap()).collect(); + (player, deck) +} + +fn score(deck: &Deck) -> u64 { + deck.iter().rev().enumerate().map(|(pos, &value)| { + ((pos + 1) as u64) * (value as u64) + }).sum::() +} + +fn crab(mut deck1: Deck, mut deck2: Deck) { + while !deck1.is_empty() && !deck2.is_empty() { + let c1 = deck1.pop_front().unwrap(); + let c2 = deck2.pop_front().unwrap(); + if c1 > c2 { + deck1.push_back(c1); + deck1.push_back(c2); + } else { + assert!(c2 > c1); + deck2.push_back(c2); + deck2.push_back(c1); + } + } + if deck2.is_empty() { + println!("Player 1 won: {:?}", deck1); + println!("Score: {}", score(&deck1)); + } else { + println!("Player 2 won: {:?}", deck2); + println!("Score: {}", score(&deck2)); + } +} + +fn _crab_rec(deck1: &mut Deck, deck2: &mut Deck) -> bool { + // println!("Rec Combat: {:?}, {:?}", deck1, deck2); + let mut previous_rounds = HashSet::new(); + while !deck1.is_empty() && !deck2.is_empty() { + if !previous_rounds.insert((deck1.clone(), deck2.clone())) { + // prevent infinite loop; player 1 wins + return true; + } + let c1 = deck1.pop_front().unwrap(); + let c2 = deck2.pop_front().unwrap(); + let p1_won = if deck1.len() >= c1 as usize && deck2.len() >= c2 as usize { + let mut deck1: Deck = deck1.iter().copied().take(c1 as usize).collect(); + let mut deck2: Deck = deck2.iter().copied().take(c2 as usize).collect(); + assert_eq!(deck1.len(), c1 as usize); + assert_eq!(deck2.len(), c2 as usize); + // recurse + _crab_rec(&mut deck1, &mut deck2) + } else { + assert_ne!(c1, c2); + c1 > c2 + }; + if p1_won { + deck1.push_back(c1); + deck1.push_back(c2); + } else { + deck2.push_back(c2); + deck2.push_back(c1); + } + } + deck2.is_empty() +} + +fn crab_rec(mut deck1: Deck, mut deck2: Deck) { + let p1_won = _crab_rec(&mut deck1, &mut deck2); + if p1_won { + println!("Player 1 won recursive combat: {:?}", deck1); + println!("Score: {}", score(&deck1)); + } else { + println!("Player 2 won recursive combat: {:?}", deck2); + println!("Score: {}", score(&deck2)); + } +} + +fn main() { + let (deck1, deck2) = { + let pos = INPUT.find("\n\n").unwrap(); + let (id1, deck1) = parse_player(&INPUT[..pos]); + let (id2, deck2) = parse_player(&INPUT[pos+2..]); + assert_eq!(id1, 1); + assert_eq!(id2, 2); + (deck1, deck2) + }; + + crab(deck1.clone(), deck2.clone()); + crab_rec(deck1, deck2); +}