I admit I tried to brute force part 2 at first, then had to think about it. The solution was quite neat in the end and runs in 4 milliseconds.
usestd::fs::File;usestd::io::prelude::*;useparser::*;// --- file readfnread_file(filename:&str)->std::io::Result<String>{letmutfile=File::open(filename)?;letmutcontents=String::new();file.read_to_string(&mutcontents)?;Ok(contents)}// -- modeltypeTimestamp=i64;typeBusID=i64;structInput{estimate:Timestamp,bus_ids:Vec<Option<BusID>>}implFrom<&str>forInput{fnfrom(s:&str)->Self{letbus_id=either(match_literal("x").means(None),integer.map(Option::Some));letbus_ids=bus_id.sep_by(match_literal(","));letinput=pair(whitespace_wrap(integer),bus_ids,|estimate,bus_ids|Input{estimate,bus_ids});input.parse(s).unwrap().1}}// --- problemsimplInput{fnnext_bus_departing(&self)->Option<(BusID,Timestamp)>{self.bus_ids.iter().filter_map(|maybe_id|*maybe_id).map(|id|(id,id-(self.estimate%id))).min_by_key(|(_id,wait_time)|*wait_time)}fnbus_ids_with_departure_offsets(&self)->implIterator<Item=(BusID,Timestamp)>+'_{// find the valid bus IDs and pair them with their position in the // list, which equates to the departure offset in minutesself.bus_ids.iter().enumerate().filter_map(|(index,maybe_id)|maybe_id.map(|id|(id,indexasTimestamp)))}fnfind_first_aligned_timestamp(&self,after:Timestamp)->Timestamp{// for each bus, find a new base timestamp after the current timestamp at which// the bus leaves (subject to its indexed departure offset), and a repetition period// which is true for all buses examined so far// (the period is a product of all bus ids, which passes all tests and finds// the right answer, but technically it should only count common factors once each;// this is possibly a deliberate design of the input data to make the problem// easier - thay do all seem to be primes)self.bus_ids_with_departure_offsets().fold((after,1),|(base_timestamp,period),(bus_id,offset)|(0..).find_map(|i|{lettimestamp=base_timestamp+i*period;if(timestamp+offset)%bus_id==0{Some((timestamp,period*bus_id))}else{None}}).unwrap()).0}}fnpart1(input:&Input)->Option<i64>{input.next_bus_departing().map(|(id,wait)|id*wait)}fnpart2(input:&Input)->Timestamp{input.find_first_aligned_timestamp(100000000000000)}fnmain(){letinput=Input::from(read_file("./input.txt").unwrap().as_str());println!("part1 {:?}",part1(&input));println!("part2 {:?}",part2(&input));}#[cfg(test)]modtests{usesuper::*;#[test]fntest_parser(){letinput=Input::from("939\n7,13,x,x,59,x,31,19");assert_eq!(input.estimate,939);assert_eq!(input.bus_ids,vec![Some(7),Some(13),None,None,Some(59),None,Some(31),Some(19)]);}#[test]fntest_next_bus_departing(){letinput=Input::from("939\n7,13,x,x,59,x,31,19");assert_eq!(input.next_bus_departing(),Some((59,5)));}#[test]fntest_find_first_aligned_timestamp_1(){letinput=Input::from("939\n7,13,x,x,59,x,31,19");assert_eq!(input.find_first_aligned_timestamp(1000000),1068781);}#[test]fntest_find_first_aligned_timestamp_2(){letinput=Input::from("0\n17,x,13,19");assert_eq!(input.find_first_aligned_timestamp(0),3417);}#[test]fntest_find_first_aligned_timestamp_3(){letinput=Input::from("0\n67,7,59,61");assert_eq!(input.find_first_aligned_timestamp(0),754018);}#[test]fntest_find_first_aligned_timestamp_4(){letinput=Input::from("0\n67,x,7,59,61");assert_eq!(input.find_first_aligned_timestamp(0),779210);}#[test]fntest_find_first_aligned_timestamp_5(){letinput=Input::from("0\n67,7,x,59,61");assert_eq!(input.find_first_aligned_timestamp(0),1261476);}#[test]fntest_find_first_aligned_timestamp_6(){letinput=Input::from("0\n1789,37,47,1889");assert_eq!(input.find_first_aligned_timestamp(0),1202161486);}}
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
I admit I tried to brute force part 2 at first, then had to think about it. The solution was quite neat in the end and runs in 4 milliseconds.