mirror of
https://github.com/peter-tanner/advent-of-code-2022.git
synced 2024-11-30 14:20:22 +08:00
day 14
this is the part where the challenges start to get hard. implementing the naive solution for part 1 did not take much time. used a hashset since it's easier than using arrays, but slightly less performant. I expected the naive solution would not work for part 2 due to the size of the problem but it still worked, although it did take a few seconds to finish. the solution i would have used if part 2 took too long would be to trace some 45* rays from the end points of horizontal beams and subtract the area inside from the largest sand triangle.
This commit is contained in:
parent
1e4645e835
commit
2ae5cce33d
|
@ -1,3 +1,112 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::{collections::HashSet, fs::read_to_string, ops::RangeInclusive};
|
||||
|
||||
const PATH: &str = "src/input";
|
||||
|
||||
fn parse_pt(p_str: &str) -> Vec<i32> {
|
||||
p_str
|
||||
.split(',')
|
||||
.map(|x| x.parse::<i32>().unwrap())
|
||||
.collect::<Vec<i32>>()
|
||||
}
|
||||
|
||||
fn any_range(a: i32, b: i32) -> RangeInclusive<i32> {
|
||||
if a < b {
|
||||
return a..=b;
|
||||
}
|
||||
return b..=a;
|
||||
}
|
||||
|
||||
const SAND_SOURCE: (i32, i32) = (500, 0);
|
||||
|
||||
fn main() {
|
||||
let data = read_to_string(PATH).expect("Error reading file");
|
||||
assert!(data.is_ascii());
|
||||
println!("PART 1 {}", sand_sim(data, true));
|
||||
let data = read_to_string(PATH).expect("Error reading file");
|
||||
assert!(data.is_ascii());
|
||||
println!("PART 2 {}", sand_sim(data, false));
|
||||
}
|
||||
|
||||
fn sand_sim(data: String, part_1: bool) -> u32 {
|
||||
// TODO: DETERMINE MAX DEPTH AUTOMATICALLY.
|
||||
let (mut walls, max_depth) = scan_walls(data);
|
||||
|
||||
let mut stop_sand = false;
|
||||
let mut sand_units = 0;
|
||||
while !stop_sand && !walls.contains(&SAND_SOURCE) {
|
||||
let mut sand_pos = SAND_SOURCE;
|
||||
|
||||
loop {
|
||||
// If the tile immediately below is blocked (by rock or sand), ...
|
||||
if walls.contains(&(sand_pos.0, sand_pos.1 + 1)) {
|
||||
// ... the unit of sand attempts to instead move diagonally one step down and to the left
|
||||
if !walls.contains(&(sand_pos.0 - 1, sand_pos.1 + 1)) {
|
||||
sand_pos.0 -= 1;
|
||||
// If that tile is blocked, the unit of sand attempts to instead move diagonally one step down and to the right
|
||||
} else if !walls.contains(&(sand_pos.0 + 1, sand_pos.1 + 1)) {
|
||||
sand_pos.0 += 1;
|
||||
// If all three possible destinations are blocked, the unit of sand comes to rest and no longer moves
|
||||
} else {
|
||||
walls.insert(sand_pos);
|
||||
sand_units += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if sand_pos.1 > max_depth {
|
||||
walls.insert(sand_pos);
|
||||
if part_1 {
|
||||
stop_sand = true;
|
||||
}
|
||||
sand_units += 1;
|
||||
break;
|
||||
}
|
||||
// A unit of sand always falls down one step if possible.
|
||||
sand_pos.1 += 1;
|
||||
}
|
||||
}
|
||||
// visualize_sand(walls, max_depth);
|
||||
return sand_units;
|
||||
}
|
||||
|
||||
fn scan_walls(data: String) -> (HashSet<(i32, i32)>, i32) {
|
||||
let paths = data.split('\n');
|
||||
let mut walls = HashSet::<(i32, i32)>::new();
|
||||
let mut max_depth = 0;
|
||||
for path in paths {
|
||||
let mut points = path.split(" -> ").into_iter();
|
||||
let mut previous_point = parse_pt(points.next().unwrap());
|
||||
while let Some(next_point) = points.next() {
|
||||
let next_point = parse_pt(next_point);
|
||||
if previous_point[1] > max_depth {
|
||||
max_depth = previous_point[1];
|
||||
}
|
||||
if next_point[1] > max_depth {
|
||||
max_depth = next_point[1];
|
||||
}
|
||||
// println!(
|
||||
// "{} {} -> {} {}",
|
||||
// previous_point[0], previous_point[1], next_point[0], next_point[1]
|
||||
// );
|
||||
for x in any_range(previous_point[0], next_point[0]) {
|
||||
for y in any_range(previous_point[1], next_point[1]) {
|
||||
walls.insert((x, y));
|
||||
}
|
||||
}
|
||||
previous_point = next_point;
|
||||
}
|
||||
}
|
||||
return (walls, max_depth);
|
||||
}
|
||||
|
||||
fn visualize_sand(walls: HashSet<(i32, i32)>, max_depth: i32) {
|
||||
for j in 0..=max_depth + 2 {
|
||||
for i in 480..550 {
|
||||
if walls.contains(&(i, j)) {
|
||||
print!("#");
|
||||
} else {
|
||||
print!(".");
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user