diff options
-rw-r--r-- | Cargo.lock | 16 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | inputs/day_19.txt | 1 | ||||
-rw-r--r-- | src/bin/day_18.rs | 1 | ||||
-rw-r--r-- | src/bin/day_19.rs | 105 |
5 files changed, 123 insertions, 1 deletions
@@ -13,6 +13,7 @@ name = "aoc2019" version = "0.1.0" dependencies = [ "archery 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cached 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)", "im 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -57,6 +58,14 @@ dependencies = [ ] [[package]] +name = "cached" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -257,6 +266,11 @@ dependencies = [ ] [[package]] +name = "once_cell" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "proc-macro-error" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -465,6 +479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bitmaps 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81e039a80914325b37fde728ef7693c212f0ac913d5599607d7b95a9484aae0b" +"checksum cached 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b052fd10f32987c3bd028d91ef86190b36fba5c8fccb5515d42083f061e6104" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" @@ -487,6 +502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" "checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" "checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" +"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed" "checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" @@ -12,6 +12,7 @@ rpds = "0.7.0" archery = "0.3.0" num = "0.2" rayon = "1.3.0" +cached = "0.11.0" [profile.release] debug = true diff --git a/inputs/day_19.txt b/inputs/day_19.txt new file mode 100644 index 0000000..e85881e --- /dev/null +++ b/inputs/day_19.txt @@ -0,0 +1 @@ +109,424,203,1,21102,11,1,0,1106,0,282,21101,0,18,0,1106,0,259,1201,1,0,221,203,1,21102,1,31,0,1106,0,282,21101,0,38,0,1106,0,259,20102,1,23,2,21202,1,1,3,21101,1,0,1,21101,0,57,0,1105,1,303,2101,0,1,222,20101,0,221,3,21001,221,0,2,21102,1,259,1,21101,0,80,0,1105,1,225,21101,185,0,2,21102,91,1,0,1106,0,303,1202,1,1,223,21001,222,0,4,21102,259,1,3,21101,225,0,2,21102,1,225,1,21101,0,118,0,1106,0,225,20102,1,222,3,21102,1,131,2,21101,133,0,0,1106,0,303,21202,1,-1,1,22001,223,1,1,21101,148,0,0,1105,1,259,2101,0,1,223,21002,221,1,4,21002,222,1,3,21101,0,16,2,1001,132,-2,224,1002,224,2,224,1001,224,3,224,1002,132,-1,132,1,224,132,224,21001,224,1,1,21101,0,195,0,106,0,109,20207,1,223,2,20101,0,23,1,21102,1,-1,3,21101,0,214,0,1105,1,303,22101,1,1,1,204,1,99,0,0,0,0,109,5,1201,-4,0,249,22101,0,-3,1,22101,0,-2,2,21201,-1,0,3,21101,0,250,0,1106,0,225,21201,1,0,-4,109,-5,2106,0,0,109,3,22107,0,-2,-1,21202,-1,2,-1,21201,-1,-1,-1,22202,-1,-2,-2,109,-3,2106,0,0,109,3,21207,-2,0,-1,1206,-1,294,104,0,99,22102,1,-2,-2,109,-3,2105,1,0,109,5,22207,-3,-4,-1,1206,-1,346,22201,-4,-3,-4,21202,-3,-1,-1,22201,-4,-1,2,21202,2,-1,-1,22201,-4,-1,1,21201,-2,0,3,21101,343,0,0,1106,0,303,1105,1,415,22207,-2,-3,-1,1206,-1,387,22201,-3,-2,-3,21202,-2,-1,-1,22201,-3,-1,3,21202,3,-1,-1,22201,-3,-1,2,22101,0,-4,1,21102,384,1,0,1106,0,303,1105,1,415,21202,-4,-1,-4,22201,-4,-3,-4,22202,-3,-2,-2,22202,-2,-4,-4,22202,-3,-2,-3,21202,-4,-1,-2,22201,-3,-2,1,21201,1,0,-4,109,-5,2106,0,0 diff --git a/src/bin/day_18.rs b/src/bin/day_18.rs index 8714e4f..34db7f9 100644 --- a/src/bin/day_18.rs +++ b/src/bin/day_18.rs @@ -1,4 +1,3 @@ -use rayon::prelude::*; use rpds::rbt_set; use rpds::vector; use rpds::vector::Vector; diff --git a/src/bin/day_19.rs b/src/bin/day_19.rs new file mode 100644 index 0000000..d5ee7f2 --- /dev/null +++ b/src/bin/day_19.rs @@ -0,0 +1,105 @@ +use aoc2019::*; +use cached::cached_key; +use cached::UnboundCache; +use rpds::list; +use rpds::list::List; +use rpds::vector; +use rpds::vector::Vector; +use std::collections::HashMap; +use std::io; +use std::io::prelude::*; +use std::iter; +use std::process; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "Day 19: Tractor Beam")] +/// Finds the effective area of a tractor beam in an n x n square, and +/// how far away you need to be to capture Santa's ship. +/// +/// See https://adventofcode.com/2019/day/19 for details. +struct Opt { + /// The size for a diagnostics scan. + #[structopt(long = "diagnostics-size")] + diagnostics_size: Option<usize>, + /// The size of Santa's ship + #[structopt(long = "ship-size")] + ship_size: Option<usize>, +} + +fn main() { + let stdin = io::stdin(); + let opt = Opt::from_args(); + + let program: IntcodeProgram = stdin + .lock() + .split(b',') + .map(|x| exit_on_failed_assertion(x, "Error reading input")) + .map(|x| exit_on_failed_assertion(String::from_utf8(x), "Input was not valid UTF-8")) + .map(|x| exit_on_failed_assertion(x.trim().parse::<Intcode>(), "Invalid number")) + .collect::<IntcodeProgram>(); + + if let Some(size) = opt.diagnostics_size { + println!("{}", count_active_in_area(program.clone(), 0, 0, size)); + } + if let Some(size) = opt.ship_size { + println!("{:?}", find_closest_ship_space(program, size)) + } +} + +fn exit_on_failed_assertion<A, E: std::error::Error>(data: Result<A, E>, message: &str) -> A { + match data { + Ok(data) => data, + Err(e) => { + eprintln!("{}: {}", message, e); + process::exit(1); + } + } +} + +fn count_active_in_area(program: IntcodeProgram, left: usize, top: usize, size: usize) -> usize { + (left..left + size) + .flat_map(|x| (top..top + size).map(move |y| (x, y))) + .filter(|(x, y)| tractor_beam_is_active(program.clone(), *x, *y)) + .count() +} + +fn area_is_all_full(program: IntcodeProgram, left: usize, top: usize, size: usize) -> bool { + // This check with a grid that's aligned to 10 gives an early exit + // for most, that will have the program executions shared. This + // makes the memoized tractor function more effective at cutting + // down on execution, even though you need to do the whole lot + // again to verify if this passes. + (left..left + size) + .flat_map(|x| (top..top + size).map(move |y| (x, y))) + .filter(|(x, y)| x % 10 == 0 && y % 10 == 0) + .all(|(x, y)| tractor_beam_is_active(program.clone(), x, y)) + && (left..left + size) + .flat_map(|x| (top..top + size).map(move |y| (x, y))) + .all(|(x, y)| tractor_beam_is_active(program.clone(), x, y)) +} + +fn find_closest_ship_space(program: IntcodeProgram, size: usize) -> (usize, usize) { + (0..) + .flat_map(|radius| { + (0..radius) + .flat_map(move |x| (0..radius).map(move |y| (x, y))) + .filter(move |(x, y)| { + (radius - 1) * (radius - 1) < x * x + y * y && x * x + y * y <= radius * radius + }) + }) + .find(|(x, y)| area_is_all_full(program.clone(), *x, *y, size)) + .unwrap() +} + +cached_key! { + TRACTOR_BEAM_IS_ACTIVE: UnboundCache<(usize, usize), bool> = UnboundCache::new(); + Key = { (x, y) }; + fn tractor_beam_is_active(program: IntcodeProgram, x: usize, y: usize) -> bool = { + program + .with_input(list![Intcode::from(x), Intcode::from(y)]) + .execute() + == Ok(vector![Intcode::from(1)]) + + } +} |