Browse Source

Day 9 WIP working on test example

Still need to handle a special case for the full example.
Tyler Hallada 5 years ago
parent
commit
dc5e1c6427
4 changed files with 172 additions and 2 deletions
  1. 1 0
      inputs/9.txt
  2. 1 0
      inputs/9_test.txt
  3. 165 0
      src/day9.rs
  4. 5 2
      src/main.rs

+ 1 - 0
inputs/9.txt

@@ -0,0 +1 @@
1
+471 players; last marble is worth 72026 points

+ 1 - 0
inputs/9_test.txt

@@ -0,0 +1 @@
1
+9 players; last marble is worth 25 points

+ 165 - 0
src/day9.rs

@@ -0,0 +1,165 @@
1
+extern crate regex;
2
+
3
+use std::error::Error;
4
+use std::fmt;
5
+use std::fs;
6
+use std::result;
7
+use std::str::FromStr;
8
+
9
+use regex::Regex;
10
+
11
+type Result<T> = result::Result<T, Box<Error>>;
12
+
13
+const INPUT: &str = "inputs/9_test.txt";
14
+
15
+#[derive(Clone, Copy, Debug, PartialEq)]
16
+struct GameParameters {
17
+    players: usize,
18
+    last_marble: usize,
19
+}
20
+
21
+impl FromStr for GameParameters {
22
+    type Err = Box<Error>;
23
+
24
+    fn from_str(s: &str) -> Result<GameParameters> {
25
+        lazy_static! {
26
+            static ref RE: Regex = Regex::new(
27
+                r"(?P<players>\d+) players; last marble is worth (?P<last_marble>\d+) points"
28
+            )
29
+            .unwrap();
30
+        }
31
+
32
+        let captures = match RE.captures(s) {
33
+            None => {
34
+                return Err(From::from(
35
+                    "Malformed game parameters, no fields could be found",
36
+                ));
37
+            }
38
+            Some(captures) => captures,
39
+        };
40
+        Ok(GameParameters {
41
+            players: captures["players"].parse()?,
42
+            last_marble: captures["last_marble"].parse()?,
43
+        })
44
+    }
45
+}
46
+
47
+#[derive(Debug, PartialEq)]
48
+struct GameState {
49
+    turn: Option<usize>,
50
+    circle: Vec<usize>,
51
+    current_marble_index: usize,
52
+    current_marble: usize,
53
+    player_scores: Vec<usize>,
54
+}
55
+
56
+impl GameState {
57
+    fn new(parameters: GameParameters) -> GameState {
58
+        GameState {
59
+            turn: None,
60
+            circle: vec![0],
61
+            current_marble_index: 0,
62
+            current_marble: 0,
63
+            player_scores: vec![0; parameters.players as usize],
64
+        }
65
+    }
66
+
67
+    fn play_until_marble(&mut self, last_marble: usize) {
68
+        println!("{}", &self);
69
+        for _ in 0..last_marble {
70
+            self.turn = match self.turn {
71
+                None => Some(0),
72
+                Some(turn) => Some((turn + 1) % self.player_scores.len()),
73
+            };
74
+
75
+            if (self.current_marble + 1) % 23 == 0 {
76
+                self.place_23rd_marble();
77
+            } else {
78
+                self.place_next_marble();
79
+            }
80
+            println!("{}", &self);
81
+        }
82
+        dbg!(&self.player_scores);
83
+    }
84
+
85
+    fn place_next_marble(&mut self) {
86
+        self.current_marble += 1;
87
+        if self.current_marble_index == self.circle.len() - 1 {
88
+            self.current_marble_index = 1;
89
+            self.circle.insert(self.current_marble_index, self.current_marble);
90
+        } else {
91
+            self.current_marble_index += 2;
92
+            self.circle.insert(self.current_marble_index, self.current_marble);
93
+        }
94
+    }
95
+
96
+    fn place_23rd_marble(&mut self) {
97
+        println!("23rd marble placed");
98
+        self.current_marble += 1;
99
+
100
+        // TODO: handle case where this over-extends over the beginning of the vec
101
+        let removed_marble = self.circle.remove(self.current_marble_index - 7);
102
+
103
+        self.player_scores[self.turn.unwrap()] += removed_marble + self.current_marble;
104
+
105
+        self.current_marble_index -= 7;
106
+    }
107
+
108
+    fn highest_score(&mut self) -> usize {
109
+        *self.player_scores.iter().max().unwrap_or(&0)
110
+    }
111
+}
112
+
113
+impl fmt::Display for GameState {
114
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115
+        match self.turn {
116
+            None => write!(f, "[-] ")?,
117
+            Some(turn) => write!(f, "[{}] ", turn + 1)?,
118
+        }
119
+        for (index, marble) in self.circle.iter().enumerate() {
120
+            if index == self.current_marble_index {
121
+                write!(f, "({}) ", marble)?;
122
+            } else {
123
+                write!(f, "{} ", marble)?;
124
+            }
125
+        }
126
+        Ok(())
127
+    }
128
+}
129
+
130
+pub fn solve_part1() -> Result<usize> {
131
+    let game_params = read_game_parameters(INPUT)?;
132
+    Ok(get_highest_score_for_game(game_params))
133
+}
134
+
135
+fn read_game_parameters(filename: &str) -> Result<GameParameters> {
136
+    let game_params = fs::read_to_string(filename)?;
137
+    Ok(game_params.parse()?)
138
+}
139
+
140
+fn get_highest_score_for_game(game_params: GameParameters) -> usize {
141
+    let mut game_state = GameState::new(game_params);
142
+    game_state.play_until_marble(game_params.last_marble);
143
+    game_state.highest_score()
144
+}
145
+
146
+#[cfg(test)]
147
+mod tests {
148
+    use super::*;
149
+
150
+    const TEST_INPUT: &str = "inputs/9_test.txt";
151
+    const TEST_GAME_PARAMS: GameParameters = GameParameters {
152
+        players: 9,
153
+        last_marble: 25,
154
+    };
155
+
156
+    #[test]
157
+    fn reads_game_parameters_file() {
158
+        assert_eq!(read_game_parameters(TEST_INPUT).unwrap(), TEST_GAME_PARAMS);
159
+    }
160
+
161
+    #[test]
162
+    fn gets_highest_score_for_game() {
163
+        assert_eq!(get_highest_score_for_game(TEST_GAME_PARAMS), 32);
164
+    }
165
+}

+ 5 - 2
src/main.rs

@@ -11,6 +11,7 @@ mod day5;
11 11
 mod day6;
12 12
 mod day7;
13 13
 mod day8;
14
+mod day9;
14 15
 
15 16
 fn main() {
16 17
     // println!("Day 1:");
@@ -34,7 +35,9 @@ fn main() {
34 35
     // println!("Day 7:");
35 36
     // println!("{}", day7::solve_part1().unwrap());
36 37
     // println!("{}", day7::solve_part2().unwrap());
37
-    println!("Day 8:");
38
+    // println!("Day 8:");
38 39
     // println!("{}", day8::solve_part1().unwrap());
39
-    println!("{}", day8::solve_part2().unwrap());
40
+    // println!("{}", day8::solve_part2().unwrap());
41
+    println!("Day 9:");
42
+    println!("{}", day9::solve_part1().unwrap());
40 43
 }