Add day 15
This commit is contained in:
137
src/day15/main.rs
Normal file
137
src/day15/main.rs
Normal file
@ -0,0 +1,137 @@
|
||||
use std::cmp::max;
|
||||
use std::collections::HashSet;
|
||||
use base::read_file;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
||||
struct Pos(i32, i32);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Beacon {
|
||||
pos: Pos,
|
||||
beacon: Pos,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Range {
|
||||
start: i32,
|
||||
end: i32,
|
||||
}
|
||||
|
||||
impl Range {
|
||||
fn new(start: i32, end: i32) -> Self {
|
||||
Range { start, end }
|
||||
}
|
||||
|
||||
fn contains(&self, number: i32) -> bool {
|
||||
number >= self.start && number <= self.end
|
||||
}
|
||||
|
||||
fn fully_overlap(&self, other: &Range) -> bool {
|
||||
self.contains(other.start) && self.contains(other.end)
|
||||
}
|
||||
|
||||
fn partly_overlap(&self, other: &Range) -> bool {
|
||||
self.contains(other.start) || self.contains(other.end)
|
||||
}
|
||||
}
|
||||
|
||||
struct YLine {
|
||||
y: i32,
|
||||
start_x: i32,
|
||||
start_y: i32,
|
||||
}
|
||||
|
||||
impl Beacon {
|
||||
fn possible_positions_into_of(&self, positions: &mut HashSet<Pos>, y: i32) {
|
||||
let distance = self.get_distance();
|
||||
for x in -distance..=distance {
|
||||
if x.abs() + (self.pos.1 - y).abs() <= distance {
|
||||
positions.insert(Pos(self.pos.0 + x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_distance(&self) -> i32 {
|
||||
let Pos(px, py) = self.pos;
|
||||
let Pos(bx, by) = self.beacon;
|
||||
(px - bx).abs() + (py - by).abs()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let lines = read_file("day15.txt");
|
||||
let mut beacons = vec![];
|
||||
|
||||
for line in lines {
|
||||
beacons.push(line.split([' ', '=', ':', ',']).filter_map(|tok| tok.parse::<i32>().ok()).collect::<Vec<_>>().chunks_exact(4).map(|positions| Beacon { pos: Pos(positions[0], positions[1]), beacon: Pos(positions[2], positions[3]) }).next().unwrap());
|
||||
}
|
||||
|
||||
let mut possible_positions = HashSet::new();
|
||||
|
||||
println!("Found {} beacons", beacons.len());
|
||||
|
||||
println!("Inserting possible positions");
|
||||
let y = 2000000;
|
||||
|
||||
for (idx, beacon) in beacons.iter().enumerate() {
|
||||
println!("Generating positions for beacon {}", idx);
|
||||
beacon.possible_positions_into_of(&mut possible_positions, y);
|
||||
}
|
||||
|
||||
println!("Inserting beacons");
|
||||
|
||||
for beacon in &beacons {
|
||||
possible_positions.remove(&beacon.pos);
|
||||
possible_positions.remove(&beacon.beacon);
|
||||
}
|
||||
|
||||
|
||||
println!("Searching for possible positions");
|
||||
|
||||
let count = possible_positions.iter().filter(|pos| pos.1 == y).count();
|
||||
|
||||
println!("Found {} at {}", count, y);
|
||||
|
||||
let max = 4000001;
|
||||
for y in 0..max {
|
||||
if y % 1000 == 0 {
|
||||
println!("Y is {}/{}", y, max);
|
||||
}
|
||||
let mut beacon_radiation = vec![];
|
||||
for beacon in &beacons {
|
||||
let distance = (beacon.pos.1 - y as i32).abs();
|
||||
let max_distance = beacon.get_distance();
|
||||
if distance <= max_distance {
|
||||
let start_x = beacon.pos.0 - (max_distance - distance);
|
||||
let end_x = beacon.pos.0 + (max_distance - distance);
|
||||
beacon_radiation.push(Range::new(start_x, end_x));
|
||||
}
|
||||
}
|
||||
|
||||
beacon_radiation.sort_by(|r1, r2| r1.start.cmp(&r2.start));
|
||||
|
||||
let mut start: Option<Range> = None;
|
||||
for range in beacon_radiation {
|
||||
match start {
|
||||
None => {
|
||||
start = Some(range);
|
||||
}
|
||||
Some(before) => {
|
||||
if range.partly_overlap(&before) || (range.start - before.end) == 1 {
|
||||
if range.end > before.end {
|
||||
start = Some(Range::new(before.start, range.end));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(sol) = start {
|
||||
if sol.end < max {
|
||||
let x = sol.end + 1;
|
||||
println!("Possible solution: {}/{} Distress: {}", x, y, (x as i64) * 4000000 + (y as i64));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user