diff --git a/Cargo.lock b/Cargo.lock index fbe51d5..b3cf365 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,18 +15,116 @@ dependencies = [ name = "aoc2022" version = "0.0.0" dependencies = [ + "indicatif", "itertools", + "rayon", "regex", "serde", "serde_json", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "unicode-width", + "winapi", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + [[package]] name = "either" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indicatif" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4295cbb7573c16d310e99e713cf9e75101eb190ab31fccd35f2d2691b4352b19" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", +] + [[package]] name = "itertools" version = "0.10.5" @@ -42,12 +140,55 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" + [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "portable-atomic" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bdd679d533107e090c2704a35982fc06302e30898e63ffa26a81155c012e92" + [[package]] name = "proc-macro2" version = "1.0.47" @@ -66,6 +207,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "regex" version = "1.7.0" @@ -89,6 +252,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.150" @@ -131,8 +300,46 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "unicode-ident" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index fcd40a5..0c53a05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,9 @@ version = "0.0.0" edition = "2021" [dependencies] +indicatif = "0.17.2" itertools = "0.10.5" +rayon = "1.6.1" regex = "1.7.0" serde = { version = "1.0.150", features = ["derive"] } serde_json = "1.0.89" diff --git a/input/15 b/input/15 new file mode 100644 index 0000000..c2ab143 --- /dev/null +++ b/input/15 @@ -0,0 +1,28 @@ +Sensor at x=1638847, y=3775370: closest beacon is at x=2498385, y=3565515 +Sensor at x=3654046, y=17188: closest beacon is at x=3628729, y=113719 +Sensor at x=3255262, y=2496809: closest beacon is at x=3266439, y=2494761 +Sensor at x=3743681, y=1144821: closest beacon is at x=3628729, y=113719 +Sensor at x=801506, y=2605771: closest beacon is at x=1043356, y=2000000 +Sensor at x=2933878, y=5850: closest beacon is at x=3628729, y=113719 +Sensor at x=3833210, y=12449: closest beacon is at x=3628729, y=113719 +Sensor at x=2604874, y=3991135: closest beacon is at x=2498385, y=3565515 +Sensor at x=1287765, y=1415912: closest beacon is at x=1043356, y=2000000 +Sensor at x=3111474, y=3680987: closest beacon is at x=2498385, y=3565515 +Sensor at x=2823460, y=1679092: closest beacon is at x=3212538, y=2537816 +Sensor at x=580633, y=1973060: closest beacon is at x=1043356, y=2000000 +Sensor at x=3983949, y=236589: closest beacon is at x=3628729, y=113719 +Sensor at x=3312433, y=246388: closest beacon is at x=3628729, y=113719 +Sensor at x=505, y=67828: closest beacon is at x=-645204, y=289136 +Sensor at x=1566406, y=647261: closest beacon is at x=1043356, y=2000000 +Sensor at x=2210221, y=2960790: closest beacon is at x=2498385, y=3565515 +Sensor at x=3538385, y=1990300: closest beacon is at x=3266439, y=2494761 +Sensor at x=3780372, y=2801075: closest beacon is at x=3266439, y=2494761 +Sensor at x=312110, y=1285740: closest beacon is at x=1043356, y=2000000 +Sensor at x=51945, y=2855778: closest beacon is at x=-32922, y=3577599 +Sensor at x=1387635, y=2875487: closest beacon is at x=1043356, y=2000000 +Sensor at x=82486, y=3631563: closest beacon is at x=-32922, y=3577599 +Sensor at x=3689149, y=3669721: closest beacon is at x=3481800, y=4169166 +Sensor at x=2085975, y=2190591: closest beacon is at x=1043356, y=2000000 +Sensor at x=712588, y=3677889: closest beacon is at x=-32922, y=3577599 +Sensor at x=22095, y=3888893: closest beacon is at x=-32922, y=3577599 +Sensor at x=3248397, y=2952817: closest beacon is at x=3212538, y=2537816 diff --git a/input/15-test b/input/15-test new file mode 100644 index 0000000..652e631 --- /dev/null +++ b/input/15-test @@ -0,0 +1,14 @@ +Sensor at x=2, y=18: closest beacon is at x=-2, y=15 +Sensor at x=9, y=16: closest beacon is at x=10, y=16 +Sensor at x=13, y=2: closest beacon is at x=15, y=3 +Sensor at x=12, y=14: closest beacon is at x=10, y=16 +Sensor at x=10, y=20: closest beacon is at x=10, y=16 +Sensor at x=14, y=17: closest beacon is at x=10, y=16 +Sensor at x=8, y=7: closest beacon is at x=2, y=10 +Sensor at x=2, y=0: closest beacon is at x=2, y=10 +Sensor at x=0, y=11: closest beacon is at x=2, y=10 +Sensor at x=20, y=14: closest beacon is at x=25, y=17 +Sensor at x=17, y=20: closest beacon is at x=21, y=22 +Sensor at x=16, y=7: closest beacon is at x=15, y=3 +Sensor at x=14, y=3: closest beacon is at x=15, y=3 +Sensor at x=20, y=1: closest beacon is at x=15, y=3 \ No newline at end of file diff --git a/src/bin/15.rs b/src/bin/15.rs new file mode 100644 index 0000000..7d79fee --- /dev/null +++ b/src/bin/15.rs @@ -0,0 +1,113 @@ +use aoc2022::*; +use indicatif::{ProgressBar, ProgressStyle}; +use itertools::Itertools; +use rayon::iter::ParallelIterator; +use rayon::prelude::IntoParallelIterator; +use regex::Regex; + +// const INPUT: &str = include_str!("../../input/15-test"); +// const Y: i64 = 10; +// const MAX_COORD: i64 = 20; + +const INPUT: &str = include_str!("../../input/15"); +const Y: i64 = 2_000_000; +const MAX_COORD: i64 = 4_000_000; + +fn main() { + solved_level_1(level1()); + solved_level_2(level2()); +} + +fn level1() -> usize { + let sensors = input().collect_vec(); + let (min, max) = sensors + .iter() + .flat_map(|s| [s.x - s.beacon_distance(), s.x + s.beacon_distance()]) + .minmax() + .into_option() + .unwrap(); + + (min..=max) + .filter(|&x| { + sensors.iter().any(|s| { + s.distance(x, Y) <= s.beacon_distance() && !(x == s.beacon_x && Y == s.beacon_y) + }) + }) + .count() +} + +fn level2() -> i64 { + // Efficient solution? 🚫 + // Fancy progress bar? ✅ + + let style = ProgressStyle::with_template("[{bar:60}] {percent}%, ~{eta}") + .unwrap() + .progress_chars("❌🔎🔍🔎🔍🔎🔍❓"); + let bar = ProgressBar::new(MAX_COORD as u64).with_style(style); + + (0..=MAX_COORD) + .into_par_iter() + .flat_map(|y| { + bar.inc(1); + + let mut x = 0; + // Push x to the right for each sensor range. + let mut moved = true; + while moved { + moved = false; + for sensor in input() { + if sensor.distance(x, y) <= sensor.beacon_distance() { + let rightmost = sensor.x + sensor.beacon_distance(); + let y_diff = (sensor.y - y).abs(); + let next_x = rightmost - y_diff; + x = x.max(next_x) + 1; + moved = true; + } + } + if x > MAX_COORD { + break; + } + } + + if x <= MAX_COORD { + println!("Found x={x}, y={y}"); + Some(x * 4000000 + y) + } else { + None + } + }) + .find_any(|_| true) + .unwrap() +} + +#[derive(Debug)] +struct Sensor { + x: i64, + y: i64, + beacon_x: i64, + beacon_y: i64, +} + +impl Sensor { + fn distance(&self, x: i64, y: i64) -> i64 { + (self.x.abs_diff(x) + self.y.abs_diff(y)) as i64 + } + + fn beacon_distance(&self) -> i64 { + self.distance(self.beacon_x, self.beacon_y) + } +} + +fn input() -> impl Iterator { + let re = + Regex::new(r"^Sensor at x=(.+), y=(.+): closest beacon is at x=(.+), y=(.+)$").unwrap(); + INPUT + .lines() + .map(move |line| re.captures(line).unwrap()) + .map(|cap| Sensor { + x: cap.get(1).unwrap().as_str().parse().unwrap(), + y: cap.get(2).unwrap().as_str().parse().unwrap(), + beacon_x: cap.get(3).unwrap().as_str().parse().unwrap(), + beacon_y: cap.get(4).unwrap().as_str().parse().unwrap(), + }) +}