Browse Source

Day 4 part 1

Tyler Hallada 5 years ago
parent
commit
dc1211cae2
3 changed files with 1186 additions and 12 deletions
  1. 1092 0
      inputs/4.txt
  2. 92 12
      src/day4.rs
  3. 2 0
      src/main.rs

File diff suppressed because it is too large
+ 1092 - 0
inputs/4.txt


+ 92 - 12
src/day4.rs

@@ -6,6 +6,7 @@ use std::fs::File;
6 6
 use std::io::{BufRead, BufReader};
7 7
 use std::fmt;
8 8
 use std::collections::{HashMap, HashSet};
9
+use std::collections::hash_map::Entry;
9 10
 use std::iter::FromIterator;
10 11
 
11 12
 use chrono::prelude::*;
@@ -27,6 +28,16 @@ enum Record {
27 28
     },
28 29
 }
29 30
 
31
+impl Record {
32
+    fn time(&self) -> NaiveDateTime {
33
+        match *self {
34
+            Record::Start { time, guard_id: _ } => time,
35
+            Record::Sleep { time } => time,
36
+            Record::Wake { time } => time,
37
+        }
38
+    }
39
+}
40
+
30 41
 #[derive(Debug, Clone, PartialEq)]
31 42
 struct MalformedRecord {
32 43
     details: String
@@ -50,35 +61,78 @@ impl Error for MalformedRecord {
50 61
     }
51 62
 }
52 63
 
64
+pub fn solve_part1() -> Result<u32, Box<Error>> {
65
+    Ok(get_part1(INPUT)?)
66
+}
67
+
68
+fn get_part1(filename: &str) -> Result<u32, Box<Error>> {
69
+    let records = read_records(filename)?;
70
+    let minutes_asleep = minutes_asleep_per_guard(records);
71
+    let sleepiest_guard = minutes_asleep.iter().max_by_key(|&(_, mins)| mins.len()).unwrap();
72
+    let sleepiest_minute = mode(sleepiest_guard.1);
73
+    Ok(sleepiest_guard.0 * sleepiest_minute)
74
+}
75
+
76
+fn mode(numbers: &[u32]) -> u32 {
77
+    let mut occurences = HashMap::new();
78
+    for &value in numbers {
79
+        *occurences.entry(value).or_insert(0) += 1;
80
+    }
81
+    occurences
82
+        .into_iter()
83
+        .max_by_key(|&(_, count)| count)
84
+        .map(|(val, _)| val)
85
+        .unwrap_or(0)
86
+}
87
+
88
+fn minutes_asleep_per_guard(mut records: Vec<Record>) -> HashMap<u32, Vec<u32>> {
89
+    let mut minutes_asleep: HashMap<u32, Vec<u32>> = HashMap::new();
90
+    records.sort_by_key(|r| r.time());
91
+    let mut current_guard = 0;
92
+    let mut fell_asleep = 0;
93
+    for record in records {
94
+        match record {
95
+            Record::Start { time: _, guard_id } => current_guard = guard_id,
96
+            Record::Sleep { time } => fell_asleep = time.minute(),
97
+            Record::Wake { time } => {
98
+                let mut slept_minutes = (fell_asleep..time.minute()).collect();
99
+                match minutes_asleep.entry(current_guard) {
100
+                    Entry::Vacant(e) => { e.insert(slept_minutes); },
101
+                    Entry::Occupied(mut e) => { e.get_mut().append(&mut slept_minutes); },
102
+                }
103
+            }
104
+        }
105
+    }
106
+    minutes_asleep
107
+}
108
+
53 109
 fn read_records(filename: &str) -> Result<Vec<Record>, Box<Error>> {
54 110
     let mut records: Vec<Record> = Vec::new();
55 111
     let record_regex =
56
-        Regex::new(r"\[(?P<timestamp>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2})\]\s(?:(?P<start>Guard #(?P<guard_id>\d+) begins shift)|(?P<sleep>falls asleep)|(?P<wake>wakes up))")?;
112
+        Regex::new(concat!(
113
+            r"\[(?P<timestamp>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2})\]\s(?:",
114
+            r"(?P<start>Guard #(?P<guard_id>\d+) begins shift)|",
115
+            r"(?P<sleep>falls asleep)|",
116
+            r"(?P<wake>wakes up))"))?;
57 117
     let file = File::open(filename)?;
58 118
     for line in BufReader::new(file).lines() {
59 119
         match record_regex.captures(&line?) {
60 120
             Some(captures) => {
61
-                println!("{:?}", NaiveDateTime::parse_from_str(
121
+                let time = NaiveDateTime::parse_from_str(
62 122
                     &get_captured_field(&captures, "timestamp")?,
63
-                    "%Y-%m-%d %H:%M")?);
123
+                    "%Y-%m-%d %H:%M")?;
64 124
                 if has_captured_field(&captures, "start")? {
65 125
                     records.push(Record::Start {
66
-                        time: NaiveDateTime::parse_from_str(
67
-                            &get_captured_field(&captures, "timestamp")?,
68
-                            "%Y-%m-%d %H:%M")?,
126
+                        time: time,
69 127
                         guard_id: get_captured_field(&captures, "guard_id")?.parse()?,
70 128
                     });
71 129
                 } else if has_captured_field(&captures, "sleep")? {
72 130
                     records.push(Record::Sleep {
73
-                        time: NaiveDateTime::parse_from_str(
74
-                            &get_captured_field(&captures, "timestamp")?,
75
-                            "%Y-%m-%d %H:%M")?,
131
+                        time: time,
76 132
                     });
77 133
                 } else {
78 134
                     records.push(Record::Wake {
79
-                        time: NaiveDateTime::parse_from_str(
80
-                            &get_captured_field(&captures, "timestamp")?,
81
-                            "%Y-%m-%d %H:%M")?,
135
+                        time: time,
82 136
                     });
83 137
                 }
84 138
             },
@@ -203,4 +257,30 @@ mod tests {
203 257
             ),
204 258
         }
205 259
     }
260
+
261
+    #[test]
262
+    fn gets_minutes_asleep_per_guard() {
263
+        let mut expected: HashMap<u32, Vec<u32>> = HashMap::new();
264
+        expected.insert(10, vec![5, 6, 7, 8, 9]);
265
+        assert_eq!(minutes_asleep_per_guard(vec![
266
+            Record::Sleep {
267
+                time: NaiveDateTime::parse_from_str(
268
+                          "1518-11-01 00:05", "%Y-%m-%d %H:%M").unwrap(),
269
+            },
270
+            Record::Start {
271
+                time: NaiveDateTime::parse_from_str(
272
+                          "1518-11-01 00:00", "%Y-%m-%d %H:%M").unwrap(),
273
+                guard_id: 10,
274
+            },
275
+            Record::Wake {
276
+                time: NaiveDateTime::parse_from_str(
277
+                          "1518-11-01 00:10", "%Y-%m-%d %H:%M").unwrap(),
278
+            },
279
+        ]), expected);
280
+    }
281
+
282
+    #[test]
283
+    fn solves_part1() {
284
+        assert_eq!(get_part1(TEST_INPUT).unwrap(), 240);
285
+    }
206 286
 }

+ 2 - 0
src/main.rs

@@ -13,4 +13,6 @@ fn main() {
13 13
     println!("Day 3:");
14 14
     println!("{}", day3::solve_part1().unwrap());
15 15
     println!("{}", day3::solve_part2().unwrap().unwrap());
16
+    println!("Day 4:");
17
+    println!("{}", day4::solve_part1().unwrap());
16 18
 }