1
0
www.mikescher.com/www/statics/aoc/2020/22_solution.rs

187 lines
5.7 KiB
Rust

use crate::common::AdventOfCodeDay;
use regex::Regex;
use std::convert::TryInto;
use std::collections::HashSet;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
#[derive(Debug)]
pub struct Day22 {
cards_p1: Vec<u32>,
cards_p2: Vec<u32>,
}
impl Day22 {
pub fn new() -> Self {
let input_bytes = include_bytes!("../res/22_input.txt");
let input_str = String::from_utf8_lossy(input_bytes);
let rex_lines = Regex::new(r"(\r?\n){2}").unwrap();
let split = rex_lines.split(&input_str).collect::<Vec<&str>>();
Self {
cards_p1: split[0].lines().skip(1).map(|p| p.parse::<u32>().unwrap()).collect(),
cards_p2: split[1].lines().skip(1).map(|p| p.parse::<u32>().unwrap()).collect(),
}
}
}
#[derive(Hash)]
struct Game {
cards_p1: Vec<u32>,
cards_p2: Vec<u32>,
}
impl Game {
fn play_one(&mut self) {
let c1 = self.cards_p1.remove(0);
let c2 = self.cards_p2.remove(0);
if c1 > c2 {
self.cards_p1.push(c1);
self.cards_p1.push(c2);
} else {
self.cards_p2.push(c2);
self.cards_p2.push(c1);
}
}
fn play(&mut self) -> usize {
verboseln!("Round[0]:");
verboseln!(" P1: {:?}", self.cards_p1);
verboseln!(" P2: {:?}", self.cards_p2);
verboseln!();
let mut winner = 0;
for i in 1.. {
self.play_one();
verboseln!("Round[{}]:", i);
verboseln!(" P1: {:?}", self.cards_p1);
verboseln!(" P2: {:?}", self.cards_p2);
verboseln!();
if self.cards_p1.is_empty() { winner = 2; break; }
if self.cards_p2.is_empty() { winner = 1; break; }
}
return winner;
}
fn score(&self, player: usize) -> u128 {
let cards = match player {
1 => &self.cards_p1,
2 => &self.cards_p2,
_ => panic!(),
};
return cards.iter()
.rev()
.enumerate()
.map(|(i,v)| ((i+1) as u128, *v as u128))
.map(|(i,v)| i*v)
.fold(0, |a,b| a + b);
}
fn play_recursive(&mut self, game_id: u32) -> usize {
verboseln!("=== Game {} ===", game_id);
verboseln!();
let mut history = HashSet::<u64>::new();
let mut winner = 0;
for i in 1.. {
let mut dhasher = DefaultHasher::new();
self.hash(&mut dhasher);
let hash = dhasher.finish();
if history.contains(&hash) {
verboseln!("Player 1 wins inf-recursion-protection in game: {}", game_id);
return 1;
} else {
history.insert(hash);
}
verboseln!("-- Round {} (Game {}) --", i, game_id);
verboseln!("Player 1's deck: {:?}", self.cards_p1);
verboseln!("Player 2's deck: {:?}", self.cards_p2);
let c1 = self.cards_p1.remove(0);
let c2 = self.cards_p2.remove(0);
verboseln!("Player 1 plays: {}", c1);
verboseln!("Player 2 plays: {}", c2);
if self.cards_p1.len() as u32 >= c1 && self.cards_p2.len() as u32 >= c2 {
verboseln!("Playing a sub-game to determine the winner...");
verboseln!();
let mut subgame = Game {
cards_p1: self.cards_p1.iter().take(c1.try_into().unwrap()).map(|p|*p).collect::<Vec<_>>(),
cards_p2:self.cards_p2.iter().take(c2.try_into().unwrap()).map(|p|*p).collect::<Vec<_>>()
};
let sg_winner = subgame.play_recursive(game_id+1);
verboseln!();
verboseln!("...anyway, back to game {}.", game_id);
if sg_winner == 1 {
verboseln!("Player 1 wins round {} of game {}!", i, game_id);
self.cards_p1.push(c1);
self.cards_p1.push(c2);
} else {
verboseln!("Player 2 wins round {} of game {}!", i, game_id);
self.cards_p2.push(c2);
self.cards_p2.push(c1);
}
} else {
if c1 > c2 {
verboseln!("Player 1 wins round {} of game {}!", i, game_id);
self.cards_p1.push(c1);
self.cards_p1.push(c2);
} else {
verboseln!("Player 2 wins round {} of game {}!", i, game_id);
self.cards_p2.push(c2);
self.cards_p2.push(c1);
}
}
if self.cards_p1.is_empty() { winner = 2; break; }
if self.cards_p2.is_empty() { winner = 1; break; }
verboseln!();
}
verboseln!("The winner of game {} is player {}!", game_id, winner);
if game_id == 1 {
verboseln!();
verboseln!("== Post-game results ==");
verboseln!("Player 1's deck: {:?}", self.cards_p1);
verboseln!("Player 2's deck: {:?}", self.cards_p2);
}
return winner;
}
}
impl AdventOfCodeDay for Day22 {
fn task_1(&self) -> String {
let mut game = Game { cards_p1: self.cards_p1.clone(), cards_p2: self.cards_p2.clone() };
let winner = game.play();
return game.score(winner).to_string();
}
fn task_2(&self) -> String {
let mut game = Game { cards_p1: self.cards_p1.clone(), cards_p2: self.cards_p2.clone() };
let winner = game.play_recursive(1);
return game.score(winner).to_string();
}
}