2018-12-04 18:36:08 +01:00
#[ macro_use ] extern crate text_io ;
2018-12-05 01:41:55 +01:00
use std ::collections ::HashMap ;
2018-12-04 20:36:22 +01:00
mod types ;
use types ::* ;
2018-12-04 18:36:08 +01:00
fn parse_action ( input : & String ) -> GuardAction {
2018-12-04 20:36:22 +01:00
match input . chars ( ) . next ( ) . unwrap ( ) {
'f' = > GuardAction ::FallAsleep ,
'w' = > GuardAction ::WakeUp ,
'G' = > {
2018-12-04 19:33:07 +01:00
let gid : i32 ;
scan! ( input . bytes ( ) = > " Guard #{} begins shift " , gid ) ;
GuardAction ::BeginShift ( gid )
}
2018-12-04 20:36:22 +01:00
_ = > std ::panic! ( )
2018-12-04 19:33:07 +01:00
}
2018-12-04 18:36:08 +01:00
}
2018-12-05 01:41:55 +01:00
fn event_from_line ( line : String ) -> Event {
2018-12-04 18:36:08 +01:00
let ( month , day , hour , minute , unparsed_action ) : ( i32 , i32 , i32 , i32 , String ) ;
2018-12-05 01:41:55 +01:00
// I’m only adding the \n here to use it as a marker for scan!,
// which would otherwise stop at the first space.
let line2 = line . to_string ( ) + " \n " ;
scan! ( line2 . bytes ( ) = > " [1518-{}-{} {}:{}] {} \n " , month , day , hour , minute , unparsed_action ) ;
2018-12-04 20:36:22 +01:00
let datetime = types ::DateTime ::new ( month , day , hour , minute ) ;
2018-12-04 18:36:08 +01:00
return Event ::new ( datetime , parse_action ( & unparsed_action ) ) ;
}
2018-12-05 01:41:55 +01:00
fn events_to_shifts ( events : Vec < Event > ) -> Vec < Shift > {
let mut shifts : Vec < Shift > = Vec ::new ( ) ;
// It was easier to parse by just adding a dummy shift at the beginning
let mut current_shift = Shift ::new ( - 1 ) ;
for event in events {
match event . action {
GuardAction ::BeginShift ( gid ) = > {
shifts . push ( current_shift ) ;
current_shift = Shift ::new ( gid ) ;
} ,
_ = > current_shift . events . push ( event )
}
}
// Remove the dummy we added earlier
shifts . remove ( 0 ) ;
return shifts ;
}
fn group_shifts_by_guard ( shifts : Vec < Shift > ) -> HashMap < i32 , Vec < Shift > > {
let mut shifts_by_guard : HashMap < i32 , Vec < Shift > > = HashMap ::new ( ) ;
for shift in shifts {
let shifts_for_guard = shifts_by_guard . entry ( shift . guard . id ) . or_insert_with ( Vec ::new ) ;
shifts_for_guard . push ( shift ) ;
}
return shifts_by_guard ;
}
2018-12-05 10:28:08 +01:00
fn calculate_sleep ( events : & Vec < Event > ) -> Vec < bool > {
2018-12-05 01:41:55 +01:00
let mut minutes = vec! [ false ; 60 ] ;
let mut sleeping = false ;
let mut last = 0 ;
for e in events {
if sleeping {
for i in ( last .. e . datetime . minute ) {
minutes [ i as usize ] = true ;
}
}
last = e . datetime . minute ;
sleeping = match e . action {
GuardAction ::FallAsleep = > true ,
_ = > false
}
}
return minutes ;
}
2018-12-05 10:28:08 +01:00
fn count_awake_minutes ( minutes : & Vec < bool > ) -> i32 {
let mut sum = 0 ;
for minute in minutes {
if * minute {
sum + = 1 ;
}
}
return sum ;
}
fn find_sleepy_guard ( guards : & HashMap < i32 , Vec < Shift > > ) -> i32 {
let mut max_sleep = 0 ;
let mut id_of_sleepiest = - 1 ;
for ( guard , shifts ) in guards {
let mut minutes_asleep = 0 ;
for shift in shifts {
minutes_asleep + = count_awake_minutes ( & calculate_sleep ( & shift . events ) ) ;
}
if minutes_asleep > max_sleep {
max_sleep = minutes_asleep ;
id_of_sleepiest = guard . clone ( ) ;
}
}
return id_of_sleepiest ;
}
fn get_sleepy_minute ( shifts : & Vec < Shift > ) -> i32 {
let mut sleep_during_shifts = vec! [ 0 ; 60 ] ;
for shift in shifts {
let minutes_asleep = calculate_sleep ( & shift . events ) ;
for i in 0 .. sleep_during_shifts . len ( ) {
sleep_during_shifts [ i ] + = if minutes_asleep [ i ] { 1 } else { 0 } ;
}
}
let sleepy_minute = sleep_during_shifts . iter ( ) . max ( ) . unwrap ( ) ;
return sleep_during_shifts . iter ( ) . position ( | & m | & m = = sleepy_minute ) . unwrap ( ) as i32 ;
}
2018-12-04 18:36:08 +01:00
fn main ( ) {
2018-12-05 01:41:55 +01:00
let lines : Vec < & str > = include_str! ( " ../input " ) . split ( " \n " ) . collect ( ) ;
2018-12-04 18:36:08 +01:00
let mut events : Vec < Event > = Vec ::new ( ) ;
for line in lines {
2018-12-05 01:41:55 +01:00
events . push ( event_from_line ( line . to_string ( ) ) ) ;
}
events . sort ( ) ;
let shifts = events_to_shifts ( events ) ;
/*
for shift in shifts {
for event in shift . events {
println! ( " {} " , event . datetime ) ;
}
2018-12-04 18:36:08 +01:00
}
2018-12-05 01:41:55 +01:00
* /
let shifts_by_guard = group_shifts_by_guard ( shifts ) ;
let sleepy_guard = find_sleepy_guard ( & shifts_by_guard ) ;
2018-12-05 10:28:08 +01:00
let sleepy_minute = get_sleepy_minute ( & shifts_by_guard . get ( & sleepy_guard ) . unwrap ( ) ) ;
println! ( " guard {} , minute {} : {} " , sleepy_guard , sleepy_minute , sleepy_guard * sleepy_minute ) ;
2018-12-04 18:36:08 +01:00
}
2018-12-04 20:36:22 +01:00