Skip to content

Commit ca525f4

Browse files
authored
Merge pull request #15 from leifgehrmann/day15
Day 15 - Beacon Exclusion Zone 🚨
2 parents ae4f0bf + 60f544c commit ca525f4

File tree

5 files changed

+250
-0
lines changed

5 files changed

+250
-0
lines changed

.github/workflows/Day-15.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Day-15
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
paths:
7+
- '**15*'
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v2
15+
- name: Build
16+
run: cargo build --release --verbose
17+
- name: Run
18+
run: time target/release/aoc 15

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This is primarily a learning experience, and the code may not be following best
2222
| 12 | Hill Climbing Algorithm | [src/day_12.rs](src/day_12.rs) | [src/day_12.data](src/day_12.data) | `0m0.053s` | [![Day-12](https://github.com/leifgehrmann/advent-of-code-2022/actions/workflows/Day-12.yml/badge.svg?branch=main)](https://github.com/leifgehrmann/advent-of-code-2022/actions/workflows/Day-12.yml?query=branch%3Amain)
2323
| 13 | Distress Signal | [src/day_13.rs](src/day_13.rs) | [src/day_13.data](src/day_13.data) | `0m0.053s` | [![Day-13](https://github.com/leifgehrmann/advent-of-code-2022/actions/workflows/Day-13.yml/badge.svg?branch=main)](https://github.com/leifgehrmann/advent-of-code-2022/actions/workflows/Day-13.yml?query=branch%3Amain)
2424
| 14 | Regolith Reservoir | [src/day_14.rs](src/day_14.rs) | [src/day_14.data](src/day_14.data) | `0m0.002s` | [![Day-14](https://github.com/leifgehrmann/advent-of-code-2022/actions/workflows/Day-14.yml/badge.svg?branch=main)](https://github.com/leifgehrmann/advent-of-code-2022/actions/workflows/Day-14.yml?query=branch%3Amain)
25+
| 15 | Beacon Exclusion Zone | [src/day_15.rs](src/day_15.rs) | [src/day_15.data](src/day_15.data) | `0m0.645s` | [![Day-15](https://github.com/leifgehrmann/advent-of-code-2022/actions/workflows/Day-15.yml/badge.svg?branch=main)](https://github.com/leifgehrmann/advent-of-code-2022/actions/workflows/Day-15.yml?query=branch%3Amain)
2526

2627
_The measured execution time in GitHub Actions_
2728

src/day_15.data

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
Sensor at x=1112863, y=496787: closest beacon is at x=1020600, y=2000000
2+
Sensor at x=2980210, y=1712427: closest beacon is at x=2946825, y=1712605
3+
Sensor at x=2799204, y=1425283: closest beacon is at x=2946825, y=1712605
4+
Sensor at x=3999908, y=2754283: closest beacon is at x=4064129, y=2651511
5+
Sensor at x=760990, y=1455625: closest beacon is at x=1020600, y=2000000
6+
Sensor at x=3996490, y=3239979: closest beacon is at x=4064129, y=2651511
7+
Sensor at x=3347352, y=3603589: closest beacon is at x=3621840, y=3614596
8+
Sensor at x=2888433, y=2337157: closest beacon is at x=2946825, y=1712605
9+
Sensor at x=3423261, y=2191958: closest beacon is at x=3153728, y=1862250
10+
Sensor at x=1160237, y=3999960: closest beacon is at x=109153, y=3585462
11+
Sensor at x=693519, y=3701289: closest beacon is at x=109153, y=3585462
12+
Sensor at x=2615270, y=2824808: closest beacon is at x=2554122, y=2935074
13+
Sensor at x=3046971, y=1755494: closest beacon is at x=2946825, y=1712605
14+
Sensor at x=139591, y=1186912: closest beacon is at x=1020600, y=2000000
15+
Sensor at x=2309134, y=47090: closest beacon is at x=3211831, y=-792661
16+
Sensor at x=1849154, y=1377259: closest beacon is at x=2946825, y=1712605
17+
Sensor at x=2515971, y=2851853: closest beacon is at x=2554122, y=2935074
18+
Sensor at x=2524614, y=2738138: closest beacon is at x=2554122, y=2935074
19+
Sensor at x=3811778, y=1370280: closest beacon is at x=3153728, y=1862250
20+
Sensor at x=2615590, y=3819371: closest beacon is at x=2554122, y=2935074
21+
Sensor at x=3996286, y=3719213: closest beacon is at x=3621840, y=3614596
22+
Sensor at x=3963152, y=2368927: closest beacon is at x=4064129, y=2651511
23+
Sensor at x=3495504, y=3076982: closest beacon is at x=3621840, y=3614596
24+
Sensor at x=3725521, y=2560764: closest beacon is at x=4064129, y=2651511
25+
Sensor at x=952643, y=2385401: closest beacon is at x=1020600, y=2000000
26+
Sensor at x=3934384, y=2596106: closest beacon is at x=4064129, y=2651511
27+
Sensor at x=3060628, y=3082730: closest beacon is at x=2554122, y=2935074
28+
Sensor at x=3468382, y=3916817: closest beacon is at x=3621840, y=3614596
29+
Sensor at x=3300107, y=469364: closest beacon is at x=3211831, y=-792661
30+
Sensor at x=2306388, y=1932261: closest beacon is at x=2946825, y=1712605
31+
Sensor at x=1965, y=3514070: closest beacon is at x=109153, y=3585462
32+
Sensor at x=3081537, y=1841861: closest beacon is at x=3153728, y=1862250
33+
Sensor at x=2997643, y=1729779: closest beacon is at x=2946825, y=1712605
34+
Sensor at x=21714, y=3624181: closest beacon is at x=109153, y=3585462
35+
Sensor at x=1549467, y=3109269: closest beacon is at x=2554122, y=2935074
36+
Sensor at x=3722307, y=3839410: closest beacon is at x=3621840, y=3614596
37+
Sensor at x=3848580, y=3544878: closest beacon is at x=3621840, y=3614596
38+
Sensor at x=1189516, y=2153239: closest beacon is at x=1020600, y=2000000
39+
Sensor at x=468190, y=1889204: closest beacon is at x=1020600, y=2000000
40+
Sensor at x=270403, y=2762568: closest beacon is at x=109153, y=3585462

src/day_15.rs

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
use crate::input_reader;
2+
3+
#[derive(Debug, Clone, Copy)]
4+
struct Point {
5+
x: i32,
6+
y: i32,
7+
}
8+
9+
#[derive(Debug, Clone, Copy)]
10+
struct Scan {
11+
sensor: Point,
12+
beacon: Point,
13+
}
14+
15+
// Ranges are inclusive, meaning Range {x: 1, y: 5} = 1,2,3,4,5
16+
#[derive(Debug, Clone, Copy)]
17+
struct Range {
18+
start: i32,
19+
end: i32,
20+
}
21+
22+
// Returns a range of x-cooridinates that have been scanned by the sensor.
23+
//
24+
// In the example below, the scanned line --RRRRRRRRR---- would be:
25+
// Range { start: 2, end: 10 }
26+
//
27+
// 1
28+
// 0 5 0
29+
// ...............
30+
// ......x........
31+
// .....x.x.......
32+
// ....B...x......
33+
// ...x.....x.....
34+
// --RRRRRRRRR----
35+
// .x....X....x...
36+
// ..x.......x....
37+
// ...x.....x.....
38+
// ....x...x......
39+
// .....x.x.......
40+
// ......x........
41+
fn get_x_range(scan: &Scan, inspect_y: i32, without_beacons: bool) -> Option<Range> {
42+
let distance = (scan.beacon.x - scan.sensor.x).abs() + (scan.beacon.y - scan.sensor.y).abs();
43+
if inspect_y > scan.sensor.y + distance || inspect_y < scan.sensor.y - distance {
44+
return None
45+
}
46+
47+
let delta = (scan.sensor.y - inspect_y).abs();
48+
let mut start = scan.sensor.x - distance + delta;
49+
let mut end = scan.sensor.x + distance - delta;
50+
if without_beacons {
51+
if inspect_y == scan.beacon.y {
52+
if scan.beacon.x == scan.sensor.x {
53+
54+
} else if scan.beacon.x <= scan.sensor.x {
55+
start += 1;
56+
} else {
57+
end -= 1;
58+
}
59+
}
60+
}
61+
// if start == end {
62+
// return None
63+
// }
64+
return Some(Range {
65+
start,
66+
end,
67+
})
68+
}
69+
70+
// Returns the range that comes after the position x.
71+
fn get_next_range(ranges: &Vec<Range>, x: i32) -> Option<Range> {
72+
let mut min_range: Option<Range> = None;
73+
for range in ranges {
74+
if range.end < x {
75+
continue;
76+
}
77+
if min_range.is_some() && range.start > min_range.unwrap().start {
78+
continue;
79+
}
80+
min_range = Some(range.clone());
81+
}
82+
return min_range
83+
}
84+
85+
fn part1(scans: &Vec<Scan>, inspect_y: i32) {
86+
let mut ranges = vec![];
87+
let mut min_range_opt = None;
88+
let mut min_x = i32::MAX;
89+
for scan in scans {
90+
let range_opt = get_x_range(scan, inspect_y, true);
91+
if range_opt.is_some() {
92+
let range = range_opt.unwrap();
93+
ranges.push(range);
94+
if range.start < min_x {
95+
min_x = range.start;
96+
min_range_opt = Some(range);
97+
}
98+
}
99+
}
100+
101+
if min_range_opt.is_none() {
102+
println!("Part 1: 0");
103+
}
104+
let min_range = min_range_opt.unwrap();
105+
106+
// Sweep through the ranges counting how many places that have been scanned.
107+
let mut cursor = min_x;
108+
let mut cursor_range = min_range;
109+
let mut count = 0;
110+
loop {
111+
// Sum up the current range.
112+
count += cursor_range.end - cursor + 1; // +1 to account for the fact that the ranges are "inclusive".
113+
cursor = cursor_range.end + 1;
114+
115+
// The find the next range.
116+
let next_range = get_next_range(&ranges, cursor);
117+
if next_range.is_some() {
118+
cursor = i32::max(cursor, next_range.unwrap().start);
119+
cursor_range = next_range.unwrap();
120+
continue;
121+
}
122+
123+
break;
124+
}
125+
126+
println!("Part 1: {}", count);
127+
}
128+
129+
fn part2(scans: &Vec<Scan>, inspect_max: i32) {
130+
for y in 0..=inspect_max {
131+
let ranges: Vec<Range> = scans.iter()
132+
.map(|&scan| { get_x_range(&scan, y, false) })
133+
.filter(|x| x.is_some())
134+
.map(|range| { range.unwrap() })
135+
.collect();
136+
137+
// println!("{:?}", ranges);
138+
139+
let mut cursor = 0;
140+
let mut cursor_range: Option<Range> = None;
141+
while cursor <= inspect_max {
142+
let next_range = get_next_range(&ranges, cursor);
143+
//println!("{:?}, {:?}", cursor_range, next_range);
144+
if next_range.is_some() {
145+
if cursor_range.is_none() || next_range.unwrap().start <= cursor_range.unwrap().end + 1 {
146+
cursor = next_range.unwrap().end + 1;
147+
cursor_range = next_range;
148+
continue
149+
} else {
150+
break;
151+
}
152+
}
153+
}
154+
if cursor < inspect_max {
155+
println!("Part 2: {}", (inspect_max as usize) * (cursor as usize) + (y as usize));
156+
break;
157+
} else {
158+
// println!("Part 2: None{}\n\n\n", y);
159+
}
160+
}
161+
}
162+
163+
pub fn run() {
164+
let mut input = input_reader::read_file_in_cwd("src/day_15.data");
165+
input = input
166+
.replace("=", " ")
167+
.replace(", ", " ")
168+
.replace(": ", " ");
169+
170+
let scans_str: Vec<&str> = input.split("\n").collect();
171+
let scans: Vec<Scan> = scans_str.iter().map(|&val| {
172+
let scan_str: Vec<&str> = val.split(" ").collect();
173+
174+
return Scan {
175+
sensor: Point {
176+
x: scan_str[3].parse::<i32>().unwrap(),
177+
y: scan_str[5].parse::<i32>().unwrap(),
178+
},
179+
beacon: Point {
180+
x: scan_str[11].parse::<i32>().unwrap(),
181+
y: scan_str[13].parse::<i32>().unwrap(),
182+
}
183+
};
184+
}).collect();
185+
part1(&scans, 2000000);
186+
part2(&scans, 4000000);
187+
// part1(&scans, 10);
188+
// part2(&scans, 20);
189+
}

src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod day_11;
1313
mod day_12;
1414
mod day_13;
1515
mod day_14;
16+
mod day_15;
1617

1718
fn main() {
1819
let day: String = std::env::args().nth(1).expect(
@@ -35,6 +36,7 @@ fn main() {
3536
"12" => day_12::run(),
3637
"13" => day_13::run(),
3738
"14" => day_14::run(),
39+
"15" => day_15::run(),
3840
_ => println!("No valid day given. Possible options are: 01-25."),
3941
};
4042
}

0 commit comments

Comments
 (0)