diff options
| author | Tom Smeding <tom.smeding@gmail.com> | 2018-12-04 16:17:14 +0100 | 
|---|---|---|
| committer | Tom Smeding <tom.smeding@gmail.com> | 2018-12-04 16:17:14 +0100 | 
| commit | d139374ef1518c5bd4e5c84e1d88263fdda2e15c (patch) | |
| tree | e44b6ffc995bb638a91fe8361d341d3c747e9ae3 /2018/src | |
| parent | 4ea93557fe55133ad7162dba4877694307145808 (diff) | |
Day 4
Diffstat (limited to '2018/src')
| -rw-r--r-- | 2018/src/day4.rs | 134 | ||||
| -rw-r--r-- | 2018/src/main.rs | 6 | 
2 files changed, 139 insertions, 1 deletions
| diff --git a/2018/src/day4.rs b/2018/src/day4.rs new file mode 100644 index 0000000..90cab72 --- /dev/null +++ b/2018/src/day4.rs @@ -0,0 +1,134 @@ +use std::io; +use std::io::BufRead; +use std::collections::HashMap; +use std::cmp::max; +use regex::Regex; + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +enum Action { +    Begin(i32), +    Sleep, +    Wake +} + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +struct Record { +    year: i32, +    month: i32, +    day: i32, +    hour: i32, +    minute: i32, +    action: Action +} + +struct Guard { +    id: i32, +    sleep_times: Vec<(i32, i32)>,  // inclusive-exclusive +    asleep: [i32; 60] +} + +fn parse_action(line: &str) -> Action { +    if line.chars().next() == Some('G') { +        let idx = 7 + line[7..].find(' ').unwrap(); +        Action::Begin(line[7 .. idx].parse().unwrap()) +    } else if line.chars().next() == Some('f') { +        Action::Sleep +    } else { +        Action::Wake +    } +} + +fn parse_line(line: &str) -> Record { +    lazy_static! { +        static ref RE: Regex = Regex::new(r"^\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (.*)$").unwrap(); +    } + +    let caps = RE.captures(line).unwrap(); +    Record { +        year: caps.get(1).unwrap().as_str().parse().unwrap(), +        month: caps.get(2).unwrap().as_str().parse().unwrap(), +        day: caps.get(3).unwrap().as_str().parse().unwrap(), +        hour: caps.get(4).unwrap().as_str().parse().unwrap(), +        minute: caps.get(5).unwrap().as_str().parse().unwrap(), +        action: parse_action(caps.get(6).unwrap().as_str()) +    } +} + +fn argmax<T: Ord>(v: &[T]) -> Option<usize> { +    if v.len() == 0 { +        None +    } else { +        let mut maxat = 0; +        for i in 1..v.len() { +            if v[i] > v[maxat] { +                maxat = i; +            } +        } +        Some(maxat) +    } +} + +pub fn main<T: BufRead>(reader: T) -> io::Result<()> { +    let mut records: Vec<Record> = reader.lines().map(|l| parse_line(&l.unwrap())).collect(); + +    records.sort_unstable(); +    let mut guards = HashMap::new(); + +    { +        let mut current_id = 0; +        let mut sleep_start = 0; + +        for record in records.iter() { +            match record.action { +                Action::Begin(id) => { +                    if let None = guards.get(&id) { +                        guards.insert(id, Guard {id: id, sleep_times: Vec::new(), asleep: [0; 60]}); +                    } +                    current_id = id; +                }, +                Action::Sleep => sleep_start = record.minute, +                Action::Wake => +                    guards.get_mut(¤t_id).unwrap() +                        .sleep_times.push((sleep_start, record.minute)) +            } +        } +    } + +    let mut max_sleep = -1; +    let mut max_sleep_at = -1; +    let mut max_times = -1; +    let mut max_times_at = -1; + +    for mut guard in guards.values_mut() { +        let mut sleep = 0; +        let mut times = 0; + +        for (from, to) in guard.sleep_times.iter() { +            for i in *from..*to { +                guard.asleep[i as usize] += 1; +                times = max(times, guard.asleep[i as usize]); +            } +            sleep += to - from; +        } + +        if sleep > max_sleep { +            max_sleep = sleep; +            max_sleep_at = guard.id; +        } + +        if times > max_times { +            max_times = times; +            max_times_at = guard.id; +        } +    } + +    let sleepy_guard = guards.get(&max_sleep_at).unwrap(); +    let max_minute = argmax(&sleepy_guard.asleep).unwrap() as i32; +    println!("{}", max_minute * sleepy_guard.id); + +    let consistent_guard = guards.get(&max_times_at).unwrap(); +    let max_minute = argmax(&consistent_guard.asleep).unwrap() as i32; +    println!("{}", max_minute * consistent_guard.id); + +    Ok(()) +} diff --git a/2018/src/main.rs b/2018/src/main.rs index 349d857..98c0f7b 100644 --- a/2018/src/main.rs +++ b/2018/src/main.rs @@ -1,3 +1,5 @@ +#[macro_use] extern crate lazy_static; +extern crate regex;  extern crate argparse;  use std::io; @@ -9,12 +11,14 @@ use argparse::{ArgumentParser, StoreTrue, Store};  mod day1;  mod day2;  mod day3; +mod day4;  fn day_switch<T: BufRead>(day: i32, reader: T) -> io::Result<()> {      match day {          1 => day1::main(reader),          2 => day2::main(reader),          3 => day3::main(reader), +        4 => day4::main(reader),          _ => Err(Error::new(ErrorKind::Other, "Invalid day"))      }  } @@ -70,7 +74,7 @@ fn main() -> io::Result<()> {      error_handler(||          if day_string.len() == 0 { -            for day in 1..4 { +            for day in 1..5 {                  run_day(day, &options)?;              }              Ok(()) | 
