diff --git a/day15/Cargo.lock b/day15/Cargo.lock new file mode 100644 index 0000000..c327390 --- /dev/null +++ b/day15/Cargo.lock @@ -0,0 +1,42 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "day15" +version = "0.1.0" +dependencies = [ + "regex", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" diff --git a/day15/Cargo.toml b/day15/Cargo.toml new file mode 100644 index 0000000..4ccb6f6 --- /dev/null +++ b/day15/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day15" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex = "1.7.0" diff --git a/day15/data.txt b/day15/data.txt new file mode 100644 index 0000000..f9faa3b --- /dev/null +++ b/day15/data.txt @@ -0,0 +1,27 @@ +Sensor at x=2288642, y=2282562: closest beacon is at x=1581951, y=2271709 +Sensor at x=2215505, y=2975419: closest beacon is at x=2229474, y=3709584 +Sensor at x=275497, y=3166843: closest beacon is at x=-626874, y=3143870 +Sensor at x=1189444, y=2115305: closest beacon is at x=1581951, y=2271709 +Sensor at x=172215, y=2327851: closest beacon is at x=-101830, y=2000000 +Sensor at x=3953907, y=1957660: closest beacon is at x=2882446, y=1934422 +Sensor at x=685737, y=2465261: closest beacon is at x=1581951, y=2271709 +Sensor at x=1458348, y=2739442: closest beacon is at x=1581951, y=2271709 +Sensor at x=3742876, y=2811554: closest beacon is at x=3133845, y=3162635 +Sensor at x=437819, y=638526: closest beacon is at x=-101830, y=2000000 +Sensor at x=2537979, y=1762726: closest beacon is at x=2882446, y=1934422 +Sensor at x=1368739, y=2222863: closest beacon is at x=1581951, y=2271709 +Sensor at x=2743572, y=3976937: closest beacon is at x=2229474, y=3709584 +Sensor at x=2180640, y=105414: closest beacon is at x=3011118, y=-101788 +Sensor at x=3845753, y=474814: closest beacon is at x=3011118, y=-101788 +Sensor at x=2493694, y=3828087: closest beacon is at x=2229474, y=3709584 +Sensor at x=2786014, y=3388077: closest beacon is at x=3133845, y=3162635 +Sensor at x=3593418, y=3761871: closest beacon is at x=3133845, y=3162635 +Sensor at x=856288, y=3880566: closest beacon is at x=2229474, y=3709584 +Sensor at x=1757086, y=2518373: closest beacon is at x=1581951, y=2271709 +Sensor at x=2853518, y=2939097: closest beacon is at x=3133845, y=3162635 +Sensor at x=1682023, y=1449902: closest beacon is at x=1581951, y=2271709 +Sensor at x=3360575, y=1739100: closest beacon is at x=2882446, y=1934422 +Sensor at x=2904259, y=1465606: closest beacon is at x=2882446, y=1934422 +Sensor at x=3078500, y=3564862: closest beacon is at x=3133845, y=3162635 +Sensor at x=2835288, y=1011055: closest beacon is at x=2882446, y=1934422 +Sensor at x=2998762, y=2414323: closest beacon is at x=2882446, y=1934422 diff --git a/day15/src/main.rs b/day15/src/main.rs new file mode 100644 index 0000000..bcf5ebf --- /dev/null +++ b/day15/src/main.rs @@ -0,0 +1,126 @@ +use regex::Regex; +use std::ops::Range; + +#[derive(Debug)] +struct Sensor { + location: (isize, isize), + beacon: (isize, isize), + reach: isize, +} + +fn main() { + let contents = std::fs::read_to_string("data.txt").expect("Failed to read file"); + let sensors = contents.lines().map(parse).collect::>(); + + // Part 1 + let row = 2000000; + let mut reached = 0; + let range = find_range(&sensors); + for col in range { + let p = (col, row); + // if this cell has a beacon or sensor, it can' be here + if sensors.iter().any(|s| s.beacon == p) { + continue; + } + // if any of the beacons can reach this cell, count it + if sensors.iter().any(|s| can_reach(s, p)) { + reached += 1; + } + } + println!("Reached {reached}"); + + // Part 2 + let max = 4_000_000; + // Look in a diamond shape just outside of each sensor's reach + 'outer: for s in &sensors { + let per = perimeter(&s) + .into_iter() + .filter(|c| c.0 <= max && c.0 >= 0 && c.1 <= max && c.1 >= 0) + .collect::>(); + for coord in per { + if sensors.iter().any(|s| can_reach(s, coord)) { + continue; + } else { + println!("Found it: {:?}", coord); + let freq = coord.0 * 4000000 + coord.1; + println!("Tuning Frequency: {:?}", freq); + break 'outer; + } + } + } +} + +fn parse(str: &str) -> Sensor { + let re = Regex::new(r"Sensor at x=(.*), y=(.*): closest beacon is at x=(.*), y=(.*)").unwrap(); + let c = re.captures(str).unwrap(); + let p = (1..=4) + .map(|i| c.get(i).unwrap().as_str().parse().unwrap()) + .collect::>(); + + let location = (p[0], p[1]); + let beacon = (p[2], p[3]); + let reach = distance(location, beacon); + Sensor { + location, + beacon, + reach, + } +} + +fn distance(p1: (isize, isize), p2: (isize, isize)) -> isize { + let (x1, y1) = p1; + let (x2, y2) = p2; + (x1 - x2).abs() + (y1 - y2).abs() +} + +fn can_reach(s: &Sensor, p: (isize, isize)) -> bool { + distance(s.location, p) <= s.reach +} + +fn find_range(sensors: &Vec) -> Range { + let mut min = 0; + let mut max = 0; + + for s in sensors { + let leftmost = s.location.0 - s.reach; + if leftmost < min { + min = leftmost; + } + + let rightmost = s.location.1 + s.reach; + if rightmost > max { + max = rightmost; + } + } + min..max +} + +fn perimeter(s: &Sensor) -> Vec<(isize, isize)> { + let mut coords = vec![]; + let length = s.reach + 2; + + // start on the left, then go clockwise around the sensor's range + let (mut col, mut row) = (s.location.0 - s.reach - 1, s.location.1); + for i in 0..=length { + coords.push((col + i, row - i)); + } + // from the top, down and right + (col, row) = (s.location.0, s.location.1 - s.reach - 1); + for i in 0..=length { + coords.push((col + i, row + i)); + } + + // from the right, going down and left + (col, row) = (s.location.0 + s.reach + 1, s.location.1); + for i in 0..=length { + coords.push((col - i, row + i)); + } + + // from the bottom, going up and left + (col, row) = (s.location.0, s.location.1 + s.reach + 1); + for i in 0..=length { + coords.push((col - i, row - i)); + } + + coords +} diff --git a/day15/test.txt b/day15/test.txt new file mode 100644 index 0000000..a612424 --- /dev/null +++ b/day15/test.txt @@ -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