Day 22 part 2 solution.
This commit is contained in:
parent
67ee67ea42
commit
48a55571c2
@ -368,11 +368,11 @@
|
|||||||
//!
|
//!
|
||||||
//! Defend your honor as Raft Captain by playing the small crab in a game of Recursive Combat using the same two decks as before. What is the winning player's score?
|
//! Defend your honor as Raft Captain by playing the small crab in a game of Recursive Combat using the same two decks as before. What is the winning player's score?
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::{HashSet, VecDeque};
|
||||||
|
|
||||||
use aoc_runner_derive::aoc;
|
use aoc_runner_derive::aoc;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
struct Players {
|
struct Players {
|
||||||
p1: VecDeque<usize>,
|
p1: VecDeque<usize>,
|
||||||
p2: VecDeque<usize>,
|
p2: VecDeque<usize>,
|
||||||
@ -384,17 +384,90 @@ fn generator(input: &str) -> Players {
|
|||||||
p1: players[0]
|
p1: players[0]
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|s| s.parse().expect("couldn't parse p1 number"))
|
.map(|s| s.trim().parse().expect("couldn't parse p1 number"))
|
||||||
.collect::<VecDeque<usize>>(),
|
.collect::<VecDeque<usize>>(),
|
||||||
p2: players[1]
|
p2: players[1]
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|s| s.parse().expect("couldn't parse p2 number"))
|
.map(|s| s.trim().parse().expect("couldn't parse p2 number"))
|
||||||
.collect::<VecDeque<usize>>(),
|
.collect::<VecDeque<usize>>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deck_to_str(deck: &VecDeque<usize>) -> String {
|
||||||
|
let mut s = format!("{}", deck.iter().nth(0).unwrap());
|
||||||
|
for c in deck.iter().skip(1) {
|
||||||
|
s = format!("{}, {}", s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! debug_println {
|
||||||
|
($($arg:tt)*) => (#[cfg(debug_assertions)] println!($($arg)*));
|
||||||
|
}
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
static GAME_NUM: AtomicUsize = AtomicUsize::new(1);
|
||||||
impl Players {
|
impl Players {
|
||||||
|
fn play_recursive(&mut self, game: usize, parent_game: usize) -> bool {
|
||||||
|
debug_println!("=== Game {} ===\n", game);
|
||||||
|
let mut round = 0;
|
||||||
|
let mut previous_rounds = HashSet::new();
|
||||||
|
while !self.p1.is_empty() && !self.p2.is_empty() {
|
||||||
|
let p1s = deck_to_str(&self.p1);
|
||||||
|
let p2s = deck_to_str(&self.p2);
|
||||||
|
let deck_key = format!("{} *** {}", p1s, p2s);
|
||||||
|
if previous_rounds.contains(&deck_key) {
|
||||||
|
// Loop detected, p1 wins
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
debug_println!("{}: {}", game, deck_key);
|
||||||
|
previous_rounds.insert(deck_key);
|
||||||
|
|
||||||
|
let p1 = self.p1.pop_front().unwrap();
|
||||||
|
let p2 = self.p2.pop_front().unwrap();
|
||||||
|
round += 1;
|
||||||
|
debug_println!("-- Round {} (Game {}) --", round, game);
|
||||||
|
debug_println!("Player 1's deck: {}", p1s);
|
||||||
|
debug_println!("Player 2's deck: {}", p2s);
|
||||||
|
debug_println!("Player 1 plays: {}", p1);
|
||||||
|
debug_println!("Player 2 plays: {}", p2);
|
||||||
|
//dbg!(p1, self.p1.len(), p2, self.p2.len());
|
||||||
|
let p1_won = if p1 <= self.p1.len() && p2 <= self.p2.len() {
|
||||||
|
// Recurse
|
||||||
|
debug_println!("Playing a sub-game to determine the winner...\n");
|
||||||
|
let mut sub_game = self.clone();
|
||||||
|
sub_game.p1.truncate(p1);
|
||||||
|
sub_game.p2.truncate(p2);
|
||||||
|
let next_game = GAME_NUM.fetch_add(1, Ordering::SeqCst);
|
||||||
|
let p1_won = sub_game.play_recursive(next_game, game);
|
||||||
|
p1_won
|
||||||
|
} else {
|
||||||
|
p1 > p2
|
||||||
|
};
|
||||||
|
|
||||||
|
if p1_won {
|
||||||
|
debug_println!("Player 1 wins round {} of game {}!", round, game);
|
||||||
|
self.p1.push_back(p1);
|
||||||
|
self.p1.push_back(p2);
|
||||||
|
} else {
|
||||||
|
debug_println!("Player 2 wins round {} of game {}!", round, game);
|
||||||
|
self.p2.push_back(p2);
|
||||||
|
self.p2.push_back(p1);
|
||||||
|
}
|
||||||
|
debug_println!();
|
||||||
|
}
|
||||||
|
let p1_won = self.p1.len() > self.p2.len();
|
||||||
|
if p1_won {
|
||||||
|
debug_println!("The winner of game {} is player 1!", game);
|
||||||
|
} else {
|
||||||
|
debug_println!("The winner of game {} is player 2!", game);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_println!("...anyway, back to game {}.", parent_game);
|
||||||
|
p1_won
|
||||||
|
}
|
||||||
|
|
||||||
fn play(&mut self) {
|
fn play(&mut self) {
|
||||||
//let mut round = 0;
|
//let mut round = 0;
|
||||||
while !self.p1.is_empty() && !self.p2.is_empty() {
|
while !self.p1.is_empty() && !self.p2.is_empty() {
|
||||||
@ -440,6 +513,13 @@ fn solution1(input: &str) -> usize {
|
|||||||
players.winning_score()
|
players.winning_score()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part2)]
|
||||||
|
fn solution2(input: &str) -> usize {
|
||||||
|
let mut players = generator(input);
|
||||||
|
players.play_recursive(GAME_NUM.fetch_add(1, Ordering::SeqCst), 0);
|
||||||
|
players.winning_score()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -472,4 +552,9 @@ Player 2:
|
|||||||
fn test_solution1() {
|
fn test_solution1() {
|
||||||
assert_eq!(solution1(INPUT), 306);
|
assert_eq!(solution1(INPUT), 306);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_solution2() {
|
||||||
|
assert_eq!(solution2(INPUT), 291);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user