diff options
-rw-r--r-- | 17/Cargo.toml | 11 | ||||
-rw-r--r-- | 17/input | 1 | ||||
-rw-r--r-- | 17/src/main.rs | 184 | ||||
-rw-r--r-- | 17/tests/main.rs | 19 | ||||
-rw-r--r-- | Cargo.lock | 8 | ||||
-rw-r--r-- | Cargo.toml | 1 |
6 files changed, 224 insertions, 0 deletions
diff --git a/17/Cargo.toml b/17/Cargo.toml new file mode 100644 index 0000000..5bd32e3 --- /dev/null +++ b/17/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "advent_17" +version = "0.1.0" +authors = ["Irene Knapp <ireneista@gmail.com>"] +edition = "2018" + +[dependencies] +advent_lib = { path = "../lib" } + +[dev-dependencies] +assert_cmd = "0.10" diff --git a/17/input b/17/input new file mode 100644 index 0000000..052ebeb --- /dev/null +++ b/17/input @@ -0,0 +1 @@ +target area: x=282..314, y=-80..-45 diff --git a/17/src/main.rs b/17/src/main.rs new file mode 100644 index 0000000..0bc5297 --- /dev/null +++ b/17/src/main.rs @@ -0,0 +1,184 @@ +use advent_lib::prelude::*; + + +#[derive(Debug)] +struct TargetArea { + min_x: i64, + max_x: i64, + min_y: i64, + max_y: i64, +} + + +#[derive(Debug, Clone, Copy)] +struct Point { + x: i64, + y: i64, +} + + +fn main() -> Result<()> { + let mut args = std::env::args(); + if args.len() != 2 { + eprintln!("Usage: advent input"); + } + let _ = args.next(); + let filename = args.next().unwrap(); + + let input = advent_lib::read_lines_file(&filename)?; + + let words: Vec<&str> = input[0].split_whitespace().collect(); + let x_parts: Vec<&str> = words[2].strip_prefix("x=").unwrap() + .strip_suffix(",").unwrap().split("..").collect(); + let y_parts: Vec<&str> = words[3].strip_prefix("y=").unwrap() + .split("..").collect(); + let min_x = x_parts[0].parse::<i64>().unwrap(); + let max_x = x_parts[1].parse::<i64>().unwrap(); + let min_y = y_parts[0].parse::<i64>().unwrap(); + let max_y = y_parts[1].parse::<i64>().unwrap(); + let target_area = TargetArea { min_x, max_x, min_y, max_y }; + + let (best_apogee, n_successes) = search_for_best_apogee(&target_area); + println!("{}", best_apogee); + println!("{}", n_successes); + + Ok(()) +} + + +fn search_for_best_apogee(target_area: &TargetArea) -> (i64, i64) { + let mut best_apogee = None; + let mut n_successes = 0; + + for dx in 1 .. target_area.max_x + 1 { + for dy in -100 .. { + let trajectory = Point { x: dx, y: dy }; + + let apogee = find_apogee(trajectory, target_area); + + match (best_apogee, apogee) { + (Some(old_apogee), Some(new_apogee)) => { + if new_apogee > old_apogee { + best_apogee = apogee; + } + + n_successes += 1; + } + (None, Some(_)) => { + best_apogee = apogee; + n_successes += 1; + } + (_, None) => { } + } + + if should_stop_y(trajectory, target_area) { + break; + } + + if dy > 5000 { + break; + } + } + } + + (best_apogee.unwrap(), n_successes) +} + + +fn should_stop_y(trajectory: Point, target_area: &TargetArea) -> bool { + let mut trajectory = trajectory; + let mut position = Point { x: 0, y: 0 }; + + loop { + + if is_in_target_area(&position, target_area) { + return false; + } + + if is_unable_to_reach_target_area(&position, &trajectory, target_area) { + return true; + } + + if is_past_target_area(&position, target_area) { + if is_above_target_area(&position, target_area) { + return true; + } else { + return false; + } + } + + iterate(&mut position, &mut trajectory); + } +} + + +fn find_apogee(trajectory: Point, target_area: &TargetArea) + -> Option<i64> +{ + let mut trajectory = trajectory; + let mut position = Point { x: 0, y: 0 }; + let mut apogee = 0; + + loop { + if position.y > apogee { + apogee = position.y; + } + + if is_in_target_area(&position, target_area) { + return Some(apogee); + } + + if is_unable_to_reach_target_area(&position, &trajectory, target_area) { + return None; + } + + if is_past_target_area(&position, target_area) { + return None; + } + + iterate(&mut position, &mut trajectory); + } +} + + +fn iterate(position: &mut Point, trajectory: &mut Point) { + position.x += trajectory.x; + position.y += trajectory.y; + + if trajectory.x > 0 { + trajectory.x -= 1; + } else if trajectory.x < 0 { + trajectory.x += 1; + } + + trajectory.y -= 1; +} + + +fn is_in_target_area(position: &Point, target_area: &TargetArea) -> bool { + (position.x >= target_area.min_x) + && (position.x <= target_area.max_x) + && (position.y >= target_area.min_y) + && (position.y <= target_area.max_y) +} + + +fn is_past_target_area(position: &Point, target_area: &TargetArea) -> bool { + (position.x > target_area.max_x) || (position.y < target_area.min_y) +} + + +fn is_unable_to_reach_target_area(position: &Point, trajectory: &Point, + target_area: &TargetArea) + -> bool +{ + (position.x < target_area.min_x) && (trajectory.x == 0) +} + + +fn is_above_target_area(position: &Point, target_area: &TargetArea) + -> bool +{ + position.y > target_area.max_y +} + diff --git a/17/tests/main.rs b/17/tests/main.rs new file mode 100644 index 0000000..20b4420 --- /dev/null +++ b/17/tests/main.rs @@ -0,0 +1,19 @@ +use assert_cmd::prelude::*; +//use predicates::prelude::*; +use std::process::Command; + + +#[test] +fn personal_input() -> Result<(), Box<dyn std::error::Error>> { + let mut command = Command::cargo_bin("advent_17")?; + + command.arg("input"); + command.assert().success().stdout( + "3160\n\ + 1928\n"); + + + + Ok(()) +} + diff --git a/Cargo.lock b/Cargo.lock index 2c1fbd4..48af539 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,6 +129,14 @@ dependencies = [ ] [[package]] +name = "advent_17" +version = "0.1.0" +dependencies = [ + "advent_lib", + "assert_cmd", +] + +[[package]] name = "advent_lib" version = "0.1.0" dependencies = [ diff --git a/Cargo.toml b/Cargo.toml index 4a97c58..c2dfe1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,5 @@ members = [ "14", "15", "16", + "17", ] |