|
|
@@ -0,0 +1,66 @@
|
|
|
+use std::fs;
|
|
|
+use std::env;
|
|
|
+
|
|
|
+use nom::IResult;
|
|
|
+use nom::multi::separated_list1;
|
|
|
+use nom::bytes::complete::tag;
|
|
|
+use nom::character::complete::i64;
|
|
|
+use nom::character::complete::space1;
|
|
|
+use nom::character::complete::line_ending;
|
|
|
+use nom::sequence::tuple;
|
|
|
+use nom::sequence::preceded;
|
|
|
+use nom::sequence::terminated;
|
|
|
+
|
|
|
+fn parse_input_data(input: &str) -> IResult<&str, (Vec<i64>, Vec<i64>)> {
|
|
|
+ tuple((terminated(preceded(tuple((tag("Time:"), space1)),
|
|
|
+ separated_list1(space1,i64)),
|
|
|
+ line_ending),
|
|
|
+ terminated(preceded(tuple((tag("Distance:"), space1)),
|
|
|
+ separated_list1(space1,i64)),
|
|
|
+ line_ending)
|
|
|
+ ))(input)
|
|
|
+}
|
|
|
+
|
|
|
+fn parse_leaderboard(input_data: &str) -> Result<(Vec<i64>,Vec<i64>), String> {
|
|
|
+ match parse_input_data(input_data) {
|
|
|
+ Ok((rest, data)) => if rest == "" {
|
|
|
+ Ok(data)
|
|
|
+ } else {
|
|
|
+ Err(format!("Incomplete parse, remaining: {}", rest))
|
|
|
+ },
|
|
|
+ Err(error) => Err(error.to_string()),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn solve_eq(t: f64, d: f64) -> Option<(f64,f64)> {
|
|
|
+ let discr = t*t - 4.0*d;
|
|
|
+ if discr >= 0.0 {
|
|
|
+ return Some(((t - discr.sqrt())/2.0, (t + discr.sqrt())/2.0));
|
|
|
+ }
|
|
|
+ None
|
|
|
+}
|
|
|
+
|
|
|
+fn integer_bounds(t: i64, d: i64) -> (i64, i64) {
|
|
|
+ match solve_eq(t as f64, d as f64) {
|
|
|
+ Some((x1,x2)) => ((x1+0.0000001).ceil() as i64, (x2-0.0000001).floor() as i64),
|
|
|
+ None => (0,0)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+fn main() {
|
|
|
+ let args: Vec<String> = env::args().collect();
|
|
|
+ let file_path = &args[1];
|
|
|
+ let input_data = fs::read_to_string(file_path).unwrap_or_else(
|
|
|
+ |_|{panic!("Can't read file {}", file_path)});
|
|
|
+ let (times,distances) = parse_leaderboard(&input_data).unwrap_or_else(
|
|
|
+ |e|{panic!("Failed to parse almanac: {}", e)});
|
|
|
+
|
|
|
+ let times_strings:Vec<String> = times.into_iter().map(|x|{x.to_string()}).collect();
|
|
|
+ let distances_strings:Vec<String> = distances.into_iter().map(|x|{x.to_string()}).collect();
|
|
|
+
|
|
|
+ let time = times_strings.join("").parse::<i64>().unwrap();
|
|
|
+ let distance = distances_strings.join("").parse::<i64>().unwrap();
|
|
|
+ let (min, max) = integer_bounds(time, distance);
|
|
|
+ println!("{}", max - min + 1);
|
|
|
+}
|