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-05 11:27:59 +01:00
let ( year , month , day , hour , minute , unparsed_action ) : ( i32 , 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 " ;
2018-12-05 11:27:59 +01:00
scan! ( line2 . bytes ( ) = > " [{}-{}-{} {}:{}] {} \n " , year , month , day , hour , minute , unparsed_action ) ;
let datetime = types ::DateTime ::new ( year , 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 {
2018-12-05 10:51:07 +01:00
for i in last .. e . datetime . minute {
2018-12-05 01:41:55 +01:00
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 ;
}
2018-12-05 10:51:07 +01:00
fn get_sleepy_minute ( shifts : & Vec < Shift > ) -> ( i32 , i32 ) {
2018-12-05 10:28:08 +01:00
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 ( ) ;
2018-12-05 10:51:07 +01:00
return ( * sleepy_minute , sleep_during_shifts . iter ( ) . position ( | & m | & m = = sleepy_minute ) . unwrap ( ) as i32 ) ;
2018-12-05 10:28:08 +01:00
}
2018-12-04 18:36:08 +01:00
fn main ( ) {
2018-12-05 11:27:59 +01:00
let lines : Vec < & str > = include_str! ( " ../input_big " ) . split ( " \n " ) . collect ( ) ;
2018-12-05 01:41:55 +01:00
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 ) ;
2018-12-05 10:51:07 +01:00
let shifts_by_guard = group_shifts_by_guard ( shifts ) ;
// part 1
let mut sleepy_guard = find_sleepy_guard ( & shifts_by_guard ) ;
let sleepy_minute = get_sleepy_minute ( & shifts_by_guard . get ( & sleepy_guard ) . unwrap ( ) ) . 1 ;
println! ( " part 1: guard {} , minute {} : {} " , sleepy_guard , sleepy_minute , sleepy_guard * sleepy_minute ) ;
// part 2
let ( mut sleepy_minute_amount , mut sleepy_minute_id ) = ( - 1 , - 1 ) ;
sleepy_guard = - 1 ;
for ( guard , shifts ) in shifts_by_guard {
let ( minute_amount , minute_id ) = get_sleepy_minute ( & shifts ) ;
if minute_amount > sleepy_minute_amount {
sleepy_minute_amount = minute_amount ;
sleepy_minute_id = minute_id ;
sleepy_guard = guard ;
2018-12-05 01:41:55 +01:00
}
2018-12-04 18:36:08 +01:00
}
2018-12-05 10:51:07 +01:00
println! ( " part 2: guard {} , minute {} , asleep for {} : {} " , sleepy_guard , sleepy_minute_id , sleepy_minute_amount , sleepy_guard * sleepy_minute_id ) ;
2018-12-04 18:36:08 +01:00
}
2018-12-04 20:36:22 +01:00