Rust Day 14 - Performance improvements
Use [usize; 2] instead of (usize, usize) Use HashSet instead of HashMap Use !.contains instead of .get(...).is_none() Compute lowest_stone when Cave is created, instead of for every sand
This commit is contained in:
parent
53f9a710e0
commit
caf113ce3d
2 changed files with 46 additions and 72 deletions
|
@ -3,118 +3,95 @@
|
||||||
#![feature(generators, generator_trait)]
|
#![feature(generators, generator_trait)]
|
||||||
const INPUT: &str = include_str!("input.txt");
|
const INPUT: &str = include_str!("input.txt");
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
mod part_1;
|
mod part_1;
|
||||||
use part_1::part_1;
|
use part_1::part_1;
|
||||||
mod part_2;
|
mod part_2;
|
||||||
use part_2::part_2;
|
use part_2::part_2;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
enum Material {
|
|
||||||
Stone,
|
|
||||||
Sand,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub(crate) struct Cave {
|
pub(crate) struct Cave {
|
||||||
pub(crate) field: HashMap<(usize, usize), Material>,
|
pub(crate) field: HashSet<[usize; 2]>,
|
||||||
|
lowest_stone: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cave {
|
impl Cave {
|
||||||
fn lowest_stone(&self) -> usize {
|
fn new(field: HashSet<[usize; 2]>) -> Cave {
|
||||||
self.field
|
let lowest_stone = field
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(position, material)| {
|
.map(|position| position[1])
|
||||||
if matches!(material, Material::Stone) {
|
|
||||||
Some(position.1)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default();
|
||||||
|
Cave {
|
||||||
|
field,
|
||||||
|
lowest_stone,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a field of sand into this [`Cave`], then returns whether it landed.
|
/// Inserts a field of sand into this [`Cave`], then returns whether it landed.
|
||||||
pub(crate) fn insert_sand_void<const X: usize>(&mut self) -> Option<(usize, usize)> {
|
pub(crate) fn insert_sand_void<const X: usize>(&mut self) -> Option<[usize; 2]> {
|
||||||
let lowest_position = self.lowest_stone();
|
let mut current_coordinate = [X, 0];
|
||||||
|
|
||||||
let mut current_coordinate = (X, 0);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if current_coordinate.1 >= lowest_position {
|
if current_coordinate[1] >= self.lowest_stone {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let coordinate_below_straight = (current_coordinate.0, current_coordinate.1 + 1);
|
let coordinate_below_straight = [current_coordinate[0], current_coordinate[1] + 1];
|
||||||
let field_below_straight = self.field.get(&coordinate_below_straight);
|
if !self.field.contains(&coordinate_below_straight) {
|
||||||
if field_below_straight.is_none() {
|
|
||||||
current_coordinate = coordinate_below_straight;
|
current_coordinate = coordinate_below_straight;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let coordinate_below_left = (current_coordinate.0 - 1, current_coordinate.1 + 1);
|
let coordinate_below_left = [current_coordinate[0] - 1, current_coordinate[1] + 1];
|
||||||
let field_below_left = self.field.get(&coordinate_below_left);
|
if !self.field.contains(&coordinate_below_left) {
|
||||||
if field_below_left.is_none() {
|
|
||||||
current_coordinate = coordinate_below_left;
|
current_coordinate = coordinate_below_left;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let coordinate_below_right = (current_coordinate.0 + 1, current_coordinate.1 + 1);
|
let coordinate_below_right = [current_coordinate[0] + 1, current_coordinate[1] + 1];
|
||||||
let field_below_right = self.field.get(&coordinate_below_right);
|
if !self.field.contains(&coordinate_below_right) {
|
||||||
if field_below_right.is_none() {
|
|
||||||
current_coordinate = coordinate_below_right;
|
current_coordinate = coordinate_below_right;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.field.insert(current_coordinate, Material::Sand);
|
self.field.insert(current_coordinate);
|
||||||
return Some(current_coordinate);
|
return Some(current_coordinate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a field of sand into this [`Cave`], then returns where it landed.
|
/// Inserts a field of sand into this [`Cave`], then returns where it landed.
|
||||||
pub(crate) fn insert_sand_floor<const X: usize>(&mut self) -> (usize, usize) {
|
pub(crate) fn insert_sand_floor<const X: usize>(&mut self) -> [usize; 2] {
|
||||||
let lowest_position = self.lowest_stone() + 2;
|
let lowest_position = self.lowest_stone + 2;
|
||||||
|
|
||||||
let mut current_coordinate = (X, 0);
|
let mut current_coordinate = [X, 0];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let y_below = current_coordinate.1 + 1;
|
let y_below = current_coordinate[1] + 1;
|
||||||
if y_below < lowest_position {
|
if y_below < lowest_position {
|
||||||
let coordinate_below_straight = (current_coordinate.0, y_below);
|
let coordinate_below_straight = [current_coordinate[0], y_below];
|
||||||
let field_below_straight = self.field.get(&coordinate_below_straight);
|
if !self.field.contains(&coordinate_below_straight) {
|
||||||
if field_below_straight.is_none() {
|
|
||||||
current_coordinate = coordinate_below_straight;
|
current_coordinate = coordinate_below_straight;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let coordinate_below_left = (current_coordinate.0 - 1, y_below);
|
let coordinate_below_left = [current_coordinate[0] - 1, y_below];
|
||||||
let field_below_left = self.field.get(&coordinate_below_left);
|
if !self.field.contains(&coordinate_below_left) {
|
||||||
if field_below_left.is_none() {
|
|
||||||
current_coordinate = coordinate_below_left;
|
current_coordinate = coordinate_below_left;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let coordinate_below_right = (current_coordinate.0 + 1, y_below);
|
let coordinate_below_right = [current_coordinate[0] + 1, y_below];
|
||||||
let field_below_right = self.field.get(&coordinate_below_right);
|
if !self.field.contains(&coordinate_below_right) {
|
||||||
if field_below_right.is_none() {
|
|
||||||
current_coordinate = coordinate_below_right;
|
current_coordinate = coordinate_below_right;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.field
|
assert!(self.field.insert(current_coordinate));
|
||||||
.try_insert(current_coordinate, Material::Sand)
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
panic!("Tried to insert Sand at occupied position {current_coordinate:?} - {err}")
|
|
||||||
});
|
|
||||||
return current_coordinate;
|
return current_coordinate;
|
||||||
} else {
|
} else {
|
||||||
self.field
|
assert!(self.field.insert(current_coordinate));
|
||||||
.try_insert(current_coordinate, Material::Sand)
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
panic!("Tried to insert Sand at occupied position {current_coordinate:?} - {err}")
|
|
||||||
});
|
|
||||||
return current_coordinate;
|
return current_coordinate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,15 +100,12 @@ impl Cave {
|
||||||
|
|
||||||
pub(crate) type Input = Cave;
|
pub(crate) type Input = Cave;
|
||||||
|
|
||||||
pub(crate) fn interpolate(
|
pub(crate) fn interpolate(from: [usize; 2], to: [usize; 2]) -> impl Iterator<Item = [usize; 2]> {
|
||||||
from: (usize, usize),
|
let min_x = from[0].min(to[0]);
|
||||||
to: (usize, usize),
|
let max_x = from[0].max(to[0]);
|
||||||
) -> impl Iterator<Item = (usize, usize)> {
|
let min_y = from[1].min(to[1]);
|
||||||
let min_x = from.0.min(to.0);
|
let max_y = from[1].max(to[1]);
|
||||||
let max_x = from.0.max(to.0);
|
(min_x..=max_x).flat_map(move |x| (min_y..=max_y).map(move |y| [x, y]))
|
||||||
let min_y = from.1.min(to.1);
|
|
||||||
let max_y = from.1.max(to.1);
|
|
||||||
(min_x..=max_x).flat_map(move |x| (min_y..=max_y).map(move |y| (x, y)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_input(input: &'static str) -> Input {
|
fn parse_input(input: &'static str) -> Input {
|
||||||
|
@ -140,14 +114,14 @@ fn parse_input(input: &'static str) -> Input {
|
||||||
let coordinates = position_string.split(',').collect::<Vec<_>>();
|
let coordinates = position_string.split(',').collect::<Vec<_>>();
|
||||||
assert_eq!(coordinates.len(), 2);
|
assert_eq!(coordinates.len(), 2);
|
||||||
|
|
||||||
(
|
[
|
||||||
coordinates[0].parse::<usize>().unwrap(),
|
coordinates[0].parse::<usize>().unwrap(),
|
||||||
coordinates[1].parse::<usize>().unwrap(),
|
coordinates[1].parse::<usize>().unwrap(),
|
||||||
)
|
]
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut stone_tiles = HashMap::new();
|
let mut stone_tiles = HashSet::new();
|
||||||
|
|
||||||
for lines in result {
|
for lines in result {
|
||||||
let mut coordinates = lines;
|
let mut coordinates = lines;
|
||||||
|
@ -155,14 +129,14 @@ fn parse_input(input: &'static str) -> Input {
|
||||||
|
|
||||||
for destination in coordinates {
|
for destination in coordinates {
|
||||||
for coordinate in interpolate(current_point, destination) {
|
for coordinate in interpolate(current_point, destination) {
|
||||||
stone_tiles.insert(coordinate, Material::Stone);
|
stone_tiles.insert(coordinate);
|
||||||
}
|
}
|
||||||
|
|
||||||
current_point = destination;
|
current_point = destination;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Cave { field: stone_tiles }
|
Cave::new(stone_tiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
pub(crate) fn part_2(mut input: crate::Input) -> u64 {
|
pub(crate) fn part_2(mut input: crate::Input) -> u64 {
|
||||||
// Increase by 1 because I break as soon as (500, 0) is placed, so it doesn't get counted
|
// Increase by 1 because I break as soon as (500, 0) is placed, so it doesn't get counted
|
||||||
let mut sand_count = 1;
|
let mut sand_count = 1;
|
||||||
while let inserted_at = input.insert_sand_floor::<500>() && inserted_at.1 != 0 {
|
while let inserted_at = input.insert_sand_floor::<500>() && inserted_at[1] != 0 {
|
||||||
sand_count += 1;
|
sand_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue