summaryrefslogtreecommitdiff
path: root/2018/src/bin/day_4.rs
blob: 2010cf8c656a1a0d83e885d0881f33e356edd640 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
extern crate advent_of_code_2018;
use advent_of_code_2018::*;

use std::str::FromStr;

use std::error::Error;
use std::path::PathBuf;
use std::collections::HashMap;

// cargo watch -cs "cargo run --release --bin day_4"

#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
struct Event {
    date: String,
    hour: u32,
    minute: u32,
    what: EventType
}

#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
enum EventType {
    BeginShift(u32),
    Asleep,
    Awake
}

impl FromStr for Event {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let date = s.split_whitespace().nth(0).unwrap().trim_matches('[').to_string();
        let time = s.split_whitespace().nth(1).unwrap().trim_matches(']');
        let hour = time.split(':').nth(0).unwrap().parse().unwrap();
        let minute = time.split(':').nth(1).unwrap().parse().unwrap();
        let guard = s.split_whitespace().nth(3).and_then(|x| x.trim_matches('#').parse().ok());

        let what = match s.split_whitespace().nth(2).unwrap() {
            "Guard" => EventType::BeginShift(guard.unwrap()),
            "falls" => EventType::Asleep,
            "wakes" => EventType::Awake,
            _ => panic!("Unknown event")
        };
        
        Ok(Event {
            date,
            hour, 
            minute,
            what
        })
    }
}

#[derive(Debug)]
struct GuardSleepStats {
    per_minute: HashMap<u32, u32>
}

impl GuardSleepStats {
    fn new() -> GuardSleepStats {
        GuardSleepStats {
            per_minute: HashMap::new()
        }
    }
    fn total(&self) -> u32 {
        self.per_minute.values().sum()
    }
}


fn main() -> Result<(), Box<Error>> {
    let input = read_file(&PathBuf::from("inputs/4.txt"))?;

    //println!("Input: {:?}", input);

    let mut events: Vec<Event> = input.iter().map(|line| line.parse().unwrap()).collect();
    events.sort();
    //println!("Events: {:?}", events);


    let mut sleep = HashMap::new();
    let mut current_guard = 0;
    let mut last_asleep = 0;
    for event in events {
        match event.what {
            EventType::BeginShift(guard) => current_guard = guard,
            EventType::Asleep => last_asleep = event.minute,
            EventType::Awake => {
                for i in last_asleep..event.minute {
                    *sleep
                        .entry(current_guard)
                        .or_insert(GuardSleepStats::new())
                        .per_minute
                        .entry(i)
                        .or_insert(0) += 1
                }
            }
        }
    }

    println!("Stats: {:?}", sleep);

    let (sleepiest_guard, sleepiest_stats) = sleep.iter().max_by_key(|(_,v)| v.total()).unwrap().clone();
    println!("Sleepiest guard: {:?}", sleepiest_guard);
    let (sleepiest_minute, sleepiest_occurances) = sleepiest_stats.per_minute.iter().max_by_key(|(_,v)| *v).unwrap().clone();
    println!("Sleepiest minute: {:?}", sleepiest_minute);
    println!("Part 1 answer: {}", sleepiest_guard * sleepiest_minute);


    let (specific_minute_offender, specific_minute_stats) = sleep.iter().max_by_key(|(_,v)| v.per_minute.values().max().unwrap()).unwrap().clone();
    println!("Specific minute: {:?}", specific_minute_offender);
    let (specific_minute_minute, specific_minute_occurances) = specific_minute_stats.per_minute.iter().max_by_key(|(_,v)| *v).unwrap().clone();
    println!("Specific Minute minute: {:?}", specific_minute_minute);
    println!("Part 2 answer: {}", specific_minute_offender * specific_minute_minute);
    
    Ok(())
}