Skip to content

Commit cccc46c

Browse files
committed
AoC 2022 Day 15 - rust
1 parent dc10273 commit cccc46c

File tree

4 files changed

+192
-1
lines changed

4 files changed

+192
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
| bash | [](src/main/bash/AoC2022_01.sh) | [](src/main/bash/AoC2022_02.sh) | [](src/main/bash/AoC2022_03.sh) | [](src/main/bash/AoC2022_04.sh) | | [](src/main/bash/AoC2022_06.sh) | [](src/main/bash/AoC2022_07.sh) | | | [](src/main/bash/AoC2022_10.sh) | | | | | | | | | | | | | | | [](src/main/bash/AoC2022_25.sh) |
4646
| c++ | [](src/main/cpp/2022/01/AoC2022_01.cpp) | [](src/main/cpp/2022/02/AoC2022_02.cpp) | [](src/main/cpp/2022/03/AoC2022_03.cpp) | [](src/main/cpp/2022/04/AoC2022_04.cpp) | [](src/main/cpp/2022/05/AoC2022_05.cpp) | [](src/main/cpp/2022/06/AoC2022_06.cpp) | | | [](src/main/cpp/2022/09/AoC2022_09.cpp) | [](src/main/cpp/2022/10/AoC2022_10.cpp) | | | | [](src/main/cpp/2022/14/AoC2022_14.cpp) | | | | | | | | | [](src/main/cpp/2022/23/AoC2022_23.cpp) | [](src/main/cpp/2022/24/AoC2022_24.cpp) | [](src/main/cpp/2022/25/AoC2022_25.cpp) |
4747
| julia | [](src/main/julia/AoC2022_01.jl) | [](src/main/julia/AoC2022_02.jl) | [](src/main/julia/AoC2022_03.jl) | [](src/main/julia/AoC2022_04.jl) | | [](src/main/julia/AoC2022_06.jl) | | | | [](src/main/julia/AoC2022_10.jl) | [](src/main/julia/AoC2022_11.jl) | | | | | | | | | | | | | | |
48-
| rust | [](src/main/rust/AoC2022_01/src/main.rs) | [](src/main/rust/AoC2022_02/src/main.rs) | [](src/main/rust/AoC2022_03/src/main.rs) | [](src/main/rust/AoC2022_04/src/main.rs) | [](src/main/rust/AoC2022_05/src/main.rs) | [](src/main/rust/AoC2022_06/src/main.rs) | [](src/main/rust/AoC2022_07/src/main.rs) | [](src/main/rust/AoC2022_08/src/main.rs) | [](src/main/rust/AoC2022_09/src/main.rs) | [](src/main/rust/AoC2022_10/src/main.rs) | [](src/main/rust/AoC2022_11/src/main.rs) | [](src/main/rust/AoC2022_12/src/main.rs) | [](src/main/rust/AoC2022_13/src/main.rs) | [](src/main/rust/AoC2022_14/src/main.rs) | | [](src/main/rust/AoC2022_16/src/main.rs) | [](src/main/rust/AoC2022_17/src/main.rs) | [](src/main/rust/AoC2022_18/src/main.rs) | [](src/main/rust/AoC2022_19/src/main.rs) | [](src/main/rust/AoC2022_20/src/main.rs) | | | | | [](src/main/rust/AoC2022_25/src/main.rs) |
48+
| rust | [](src/main/rust/AoC2022_01/src/main.rs) | [](src/main/rust/AoC2022_02/src/main.rs) | [](src/main/rust/AoC2022_03/src/main.rs) | [](src/main/rust/AoC2022_04/src/main.rs) | [](src/main/rust/AoC2022_05/src/main.rs) | [](src/main/rust/AoC2022_06/src/main.rs) | [](src/main/rust/AoC2022_07/src/main.rs) | [](src/main/rust/AoC2022_08/src/main.rs) | [](src/main/rust/AoC2022_09/src/main.rs) | [](src/main/rust/AoC2022_10/src/main.rs) | [](src/main/rust/AoC2022_11/src/main.rs) | [](src/main/rust/AoC2022_12/src/main.rs) | [](src/main/rust/AoC2022_13/src/main.rs) | [](src/main/rust/AoC2022_14/src/main.rs) | [](src/main/rust/AoC2022_15/src/main.rs) | [](src/main/rust/AoC2022_16/src/main.rs) | [](src/main/rust/AoC2022_17/src/main.rs) | [](src/main/rust/AoC2022_18/src/main.rs) | [](src/main/rust/AoC2022_19/src/main.rs) | [](src/main/rust/AoC2022_20/src/main.rs) | | | | | [](src/main/rust/AoC2022_25/src/main.rs) |
4949
<!-- @END:ImplementationsTable:2022@ -->
5050

5151
## 2021

src/main/rust/AoC2022_15/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "AoC2022_15"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
aoc = { path = "../aoc" }
8+
itertools = "0.11"

src/main/rust/AoC2022_15/src/main.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
#![allow(non_snake_case)]
2+
3+
use aoc::geometry::XY;
4+
use aoc::Puzzle;
5+
use itertools::Itertools;
6+
use std::cmp::Ordering;
7+
use std::collections::{HashMap, HashSet};
8+
use std::ops::RangeInclusive;
9+
10+
trait IsOverlappedBy {
11+
fn is_overlapped_by(&self, other: &RangeInclusive<i32>) -> bool;
12+
}
13+
14+
impl IsOverlappedBy for RangeInclusive<i32> {
15+
fn is_overlapped_by(&self, other: &RangeInclusive<i32>) -> bool {
16+
other.contains(self.start())
17+
|| other.contains(self.end())
18+
|| self.contains(other.start())
19+
}
20+
}
21+
22+
struct AoC2022_15;
23+
24+
impl AoC2022_15 {
25+
fn solve_1(
26+
&self,
27+
sensors: &HashMap<XY, u32>,
28+
beacons: &HashSet<XY>,
29+
y: i32,
30+
) -> i32 {
31+
let mut ranges: Vec<RangeInclusive<i32>> = Vec::new();
32+
for (s, md) in sensors {
33+
let md = *md as i32;
34+
let dy = (s.y() - y).abs();
35+
if dy > md {
36+
continue;
37+
}
38+
ranges.push(s.x() - md + dy..=s.x() + md - dy);
39+
}
40+
let mut merged: Vec<RangeInclusive<i32>> = Vec::new();
41+
ranges.sort_unstable_by(|s, o| {
42+
let ans = s.start().cmp(o.start());
43+
match ans {
44+
Ordering::Equal => s.end().cmp(o.end()),
45+
_ => ans,
46+
}
47+
});
48+
for range in ranges {
49+
if merged.is_empty() {
50+
merged.push(range);
51+
continue;
52+
}
53+
let last = merged.last().unwrap().clone();
54+
if last.is_overlapped_by(&range) {
55+
merged.pop();
56+
merged.push(*last.start()..=*last.end().max(range.end()));
57+
} else {
58+
merged.push(range);
59+
}
60+
}
61+
merged
62+
.iter()
63+
.map(|r| {
64+
r.end() - r.start() + 1
65+
- beacons
66+
.iter()
67+
.filter(|b| b.y() == y && r.contains(&b.x()))
68+
.count() as i32
69+
})
70+
.sum()
71+
}
72+
73+
fn sample_part_1(&self, input: &(HashMap<XY, u32>, HashSet<XY>)) -> i32 {
74+
let (sensors, beacons) = input;
75+
self.solve_1(sensors, beacons, 10)
76+
}
77+
78+
fn solve_2(&self, sensors: &HashMap<XY, u32>, max: i32) -> u64 {
79+
let mut a_coeffs: HashSet<i32> = HashSet::new();
80+
let mut b_coeffs: HashSet<i32> = HashSet::new();
81+
for (s, md) in sensors {
82+
a_coeffs.insert(s.y() - s.x() + *md as i32 + 1);
83+
a_coeffs.insert(s.y() - s.x() - *md as i32 - 1);
84+
b_coeffs.insert(s.x() + s.y() + *md as i32 + 1);
85+
b_coeffs.insert(s.x() + s.y() - *md as i32 - 1);
86+
}
87+
a_coeffs
88+
.iter()
89+
.cartesian_product(b_coeffs.iter())
90+
.filter(|(a, b)| *a < *b && (*b - *a) % 2 == 0)
91+
.map(|(a, b)| XY::of((b - a) / 2, (a + b) / 2))
92+
.filter(|p| 0 < p.x() && p.x() < max)
93+
.filter(|p| 0 < p.y() && p.y() < max)
94+
.filter(|p| {
95+
sensors.iter().all(|(s, md)| p.manhattan_distance(&s) > *md)
96+
})
97+
.map(|p| 4_000_000_u64 * p.x() as u64 + p.y() as u64)
98+
.next()
99+
.unwrap()
100+
}
101+
102+
fn sample_part_2(&self, input: &(HashMap<XY, u32>, HashSet<XY>)) -> u64 {
103+
let (sensors, _) = input;
104+
self.solve_2(sensors, 20)
105+
}
106+
}
107+
108+
impl aoc::Puzzle for AoC2022_15 {
109+
type Input = (HashMap<XY, u32>, HashSet<XY>);
110+
type Output1 = i32;
111+
type Output2 = u64;
112+
113+
aoc::puzzle_year_day!(2022, 15);
114+
115+
fn parse_input(&self, lines: Vec<String>) -> Self::Input {
116+
let mut sensors: HashMap<XY, u32> = HashMap::new();
117+
let mut beacons: HashSet<XY> = HashSet::new();
118+
for line in lines {
119+
let nums = aoc::ints_with_check(&line, 4);
120+
let s = XY::of(nums[0], nums[1]);
121+
let b = XY::of(nums[2], nums[3]);
122+
sensors.insert(s, s.manhattan_distance(&b));
123+
beacons.insert(b);
124+
}
125+
(sensors, beacons)
126+
}
127+
128+
fn part_1(&self, input: &Self::Input) -> Self::Output1 {
129+
let (sensors, beacons) = input;
130+
self.solve_1(sensors, beacons, 2_000_000)
131+
}
132+
133+
fn part_2(&self, input: &Self::Input) -> Self::Output2 {
134+
let (sensors, _) = input;
135+
self.solve_2(sensors, 4_000_000)
136+
}
137+
138+
fn samples(&self) {
139+
aoc::puzzle_samples! {
140+
self, sample_part_1, TEST, 26,
141+
self, sample_part_2, TEST, 56_000_011
142+
};
143+
}
144+
}
145+
146+
fn main() {
147+
AoC2022_15 {}.run(std::env::args());
148+
}
149+
150+
const TEST: &str = "\
151+
Sensor at x=2, y=18: closest beacon is at x=-2, y=15
152+
Sensor at x=9, y=16: closest beacon is at x=10, y=16
153+
Sensor at x=13, y=2: closest beacon is at x=15, y=3
154+
Sensor at x=12, y=14: closest beacon is at x=10, y=16
155+
Sensor at x=10, y=20: closest beacon is at x=10, y=16
156+
Sensor at x=14, y=17: closest beacon is at x=10, y=16
157+
Sensor at x=8, y=7: closest beacon is at x=2, y=10
158+
Sensor at x=2, y=0: closest beacon is at x=2, y=10
159+
Sensor at x=0, y=11: closest beacon is at x=2, y=10
160+
Sensor at x=20, y=14: closest beacon is at x=25, y=17
161+
Sensor at x=17, y=20: closest beacon is at x=21, y=22
162+
Sensor at x=16, y=7: closest beacon is at x=15, y=3
163+
Sensor at x=14, y=3: closest beacon is at x=15, y=3
164+
Sensor at x=20, y=1: closest beacon is at x=15, y=3
165+
";
166+
167+
#[cfg(test)]
168+
mod tests {
169+
use super::*;
170+
171+
#[test]
172+
pub fn samples() {
173+
AoC2022_15 {}.samples();
174+
}
175+
}

src/main/rust/Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy