From dc5e1c6427b3bc74f89cb88f8e5ef103a9e1be19 Mon Sep 17 00:00:00 2001 From: Tyler Hallada Date: Sat, 16 Feb 2019 02:27:38 -0500 Subject: [PATCH] Day 9 WIP working on test example Still need to handle a special case for the full example. --- inputs/9.txt | 1 + inputs/9_test.txt | 1 + src/day9.rs | 165 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 +- 4 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 inputs/9.txt create mode 100644 inputs/9_test.txt create mode 100644 src/day9.rs diff --git a/inputs/9.txt b/inputs/9.txt new file mode 100644 index 0000000..64cbba1 --- /dev/null +++ b/inputs/9.txt @@ -0,0 +1 @@ +471 players; last marble is worth 72026 points diff --git a/inputs/9_test.txt b/inputs/9_test.txt new file mode 100644 index 0000000..2ee4c70 --- /dev/null +++ b/inputs/9_test.txt @@ -0,0 +1 @@ +9 players; last marble is worth 25 points diff --git a/src/day9.rs b/src/day9.rs new file mode 100644 index 0000000..7b24f6c --- /dev/null +++ b/src/day9.rs @@ -0,0 +1,165 @@ +extern crate regex; + +use std::error::Error; +use std::fmt; +use std::fs; +use std::result; +use std::str::FromStr; + +use regex::Regex; + +type Result = result::Result>; + +const INPUT: &str = "inputs/9_test.txt"; + +#[derive(Clone, Copy, Debug, PartialEq)] +struct GameParameters { + players: usize, + last_marble: usize, +} + +impl FromStr for GameParameters { + type Err = Box; + + fn from_str(s: &str) -> Result { + lazy_static! { + static ref RE: Regex = Regex::new( + r"(?P\d+) players; last marble is worth (?P\d+) points" + ) + .unwrap(); + } + + let captures = match RE.captures(s) { + None => { + return Err(From::from( + "Malformed game parameters, no fields could be found", + )); + } + Some(captures) => captures, + }; + Ok(GameParameters { + players: captures["players"].parse()?, + last_marble: captures["last_marble"].parse()?, + }) + } +} + +#[derive(Debug, PartialEq)] +struct GameState { + turn: Option, + circle: Vec, + current_marble_index: usize, + current_marble: usize, + player_scores: Vec, +} + +impl GameState { + fn new(parameters: GameParameters) -> GameState { + GameState { + turn: None, + circle: vec![0], + current_marble_index: 0, + current_marble: 0, + player_scores: vec![0; parameters.players as usize], + } + } + + fn play_until_marble(&mut self, last_marble: usize) { + println!("{}", &self); + for _ in 0..last_marble { + self.turn = match self.turn { + None => Some(0), + Some(turn) => Some((turn + 1) % self.player_scores.len()), + }; + + if (self.current_marble + 1) % 23 == 0 { + self.place_23rd_marble(); + } else { + self.place_next_marble(); + } + println!("{}", &self); + } + dbg!(&self.player_scores); + } + + fn place_next_marble(&mut self) { + self.current_marble += 1; + if self.current_marble_index == self.circle.len() - 1 { + self.current_marble_index = 1; + self.circle.insert(self.current_marble_index, self.current_marble); + } else { + self.current_marble_index += 2; + self.circle.insert(self.current_marble_index, self.current_marble); + } + } + + fn place_23rd_marble(&mut self) { + println!("23rd marble placed"); + self.current_marble += 1; + + // TODO: handle case where this over-extends over the beginning of the vec + let removed_marble = self.circle.remove(self.current_marble_index - 7); + + self.player_scores[self.turn.unwrap()] += removed_marble + self.current_marble; + + self.current_marble_index -= 7; + } + + fn highest_score(&mut self) -> usize { + *self.player_scores.iter().max().unwrap_or(&0) + } +} + +impl fmt::Display for GameState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.turn { + None => write!(f, "[-] ")?, + Some(turn) => write!(f, "[{}] ", turn + 1)?, + } + for (index, marble) in self.circle.iter().enumerate() { + if index == self.current_marble_index { + write!(f, "({}) ", marble)?; + } else { + write!(f, "{} ", marble)?; + } + } + Ok(()) + } +} + +pub fn solve_part1() -> Result { + let game_params = read_game_parameters(INPUT)?; + Ok(get_highest_score_for_game(game_params)) +} + +fn read_game_parameters(filename: &str) -> Result { + let game_params = fs::read_to_string(filename)?; + Ok(game_params.parse()?) +} + +fn get_highest_score_for_game(game_params: GameParameters) -> usize { + let mut game_state = GameState::new(game_params); + game_state.play_until_marble(game_params.last_marble); + game_state.highest_score() +} + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_INPUT: &str = "inputs/9_test.txt"; + const TEST_GAME_PARAMS: GameParameters = GameParameters { + players: 9, + last_marble: 25, + }; + + #[test] + fn reads_game_parameters_file() { + assert_eq!(read_game_parameters(TEST_INPUT).unwrap(), TEST_GAME_PARAMS); + } + + #[test] + fn gets_highest_score_for_game() { + assert_eq!(get_highest_score_for_game(TEST_GAME_PARAMS), 32); + } +} diff --git a/src/main.rs b/src/main.rs index 6f4689a..601ff34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ mod day5; mod day6; mod day7; mod day8; +mod day9; fn main() { // println!("Day 1:"); @@ -34,7 +35,9 @@ fn main() { // println!("Day 7:"); // println!("{}", day7::solve_part1().unwrap()); // println!("{}", day7::solve_part2().unwrap()); - println!("Day 8:"); + // println!("Day 8:"); // println!("{}", day8::solve_part1().unwrap()); - println!("{}", day8::solve_part2().unwrap()); + // println!("{}", day8::solve_part2().unwrap()); + println!("Day 9:"); + println!("{}", day9::solve_part1().unwrap()); }