day 14 part 1 & 2

This commit is contained in:
OMGeeky
2024-06-21 15:27:19 +00:00
parent a338387a1d
commit a488955636
4 changed files with 260 additions and 4 deletions

View File

@@ -14,6 +14,8 @@ paste ={ version = "1.0" }
cached="0.46"
itertools="0.12"
rayon="1"
num="0.4"
indicatif="0.17"
[dev-dependencies]
rstest = "0.18"

248
src/day14.rs Normal file
View File

@@ -0,0 +1,248 @@
use std::{fmt::Display, iter::Sum};
use itertools::Itertools;
use crate::*;
pub struct Day14;
impl Day for Day14 {
const DAY_NUM: u8 = 14;
type Input = String;
type Output = usize;
fn get_test_data() -> Self::Input {
r"O....#....
O.OO#....#
.....##...
OO.#O....O
.O.....O#.
O.#..O.#.#
..O..#O..O
.......O..
#....###..
#OO..#...."
.to_string()
}
fn get_test_result() -> Self::Output {
136
}
fn run(data: Self::Input) -> Self::Output {
part1::run(data)
}
}
impl DayPart2 for Day14 {
fn run_part2(data: Self::Input) -> Self::Output {
part2::run(data)
}
fn get_test_result_part2() -> Self::Output {
64
}
fn get_test_data_part2() -> Self::Input {
Self::get_test_data()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum Object {
Stone,
Empty,
CubeStone,
}
impl Display for Object {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Object::Stone => "O",
Object::Empty => ".",
Object::CubeStone => "#",
}
)
}
}
impl Sum<Object> for usize {
fn sum<I: Iterator<Item = Object>>(iter: I) -> Self {
iter.map(|o| match o {
Object::Stone => 1,
Object::Empty => 0,
Object::CubeStone => 0,
})
.sum()
}
}
impl<'a> Sum<&'a Object> for usize {
fn sum<I: Iterator<Item = &'a Object>>(iter: I) -> Self {
iter.map(|o| *o).sum()
}
}
fn display_grid<T: ToString>(data: &Vec<Vec<T>>) {
println!("----------------------------");
for row in data.iter() {
let line = row.iter().map(ToString::to_string).join("");
println!("{}", line);
}
println!("----------------------------");
}
mod part1 {
use super::*;
pub fn run(data: String) -> usize {
let mut data = parse_lines(data);
display_grid(&data);
shift_stones(&mut data, Direction::North);
display_grid(&data);
evaluate_wheights(&data)
}
}
mod part2 {
use indicatif::{ProgressIterator as _, ProgressStyle};
use super::*;
pub fn run(data: String) -> usize {
let mut data = parse_lines(data);
display_grid(&data);
let iterator = 0..1_000_000_000;
// let iterator = 0..1000; //for testing
for _ in iterator.progress().with_style(ProgressStyle::with_template("[{elapsed_precise}] {wide_bar:.cyan/blue} eta:[{eta_precise}] at {per_sec:15} {human_pos:>13}/{human_len:13} {percent_precise}%").unwrap()) {
shift_stones(&mut data, Direction::North);
shift_stones(&mut data, Direction::West);
shift_stones(&mut data, Direction::South);
shift_stones(&mut data, Direction::East);
// display_grid(&data);
}
evaluate_wheights(&data)
}
}
fn parse_lines(data: String) -> Vec<Vec<Object>> {
data.lines()
// .rev()
.map(|l| {
l.chars()
.map(|c| match c {
'O' => Object::Stone,
'#' => Object::CubeStone,
'.' => Object::Empty,
_ => panic!("Invalid character: {}", c),
})
.collect()
})
.collect()
}
fn evaluate_wheights(data: &Vec<Vec<Object>>) -> usize {
data.iter()
.rev()
.enumerate()
.map(|(i, x)| (i + 1) * x.iter().sum::<usize>())
.sum()
}
fn shift_stones(data: &mut Vec<Vec<Object>>, direction: Direction) {
let (horizontal_active, vertical_active) = match direction {
Direction::North => (0, -1),
Direction::South => (0, 1),
Direction::West => (-1, 0),
Direction::East => (1, 0),
};
let width = data[0].len();
let mut count_stones: isize;
let height = data.len();
let range = match direction {
Direction::South => num::range_step(0, height as isize, 1),
Direction::North => num::range_step(height as isize - 1, 0 - 1, -1),
Direction::West => num::range_step(width as isize - 1, 0 - 1, -1),
Direction::East => num::range_step(0, width as isize, 1),
};
// println!("Shifting stones to {direction} v:{vertical_active} h:{horizontal_active}");
if vertical_active != 0 {
for x in 0..width {
count_stones = 0;
// println!("entering column: {x}");
for y in range.clone() {
// println!("entering row: {y}");
// display_grid(data);
move_object(
data,
y as usize,
x as usize,
&mut count_stones,
vertical_active,
horizontal_active,
);
}
}
} else {
for y in 0..height {
// println!("entering row: {y}");
count_stones = 0;
for x in range.clone() {
// println!("entering column: {x}");
// display_grid(data);
move_object(
data,
y as usize,
x as usize,
&mut count_stones,
vertical_active,
horizontal_active,
);
}
}
}
}
fn move_object(
data: &mut Vec<Vec<Object>>,
y: usize,
x: usize,
count_stones: &mut isize,
vertical_active: isize,
horizontal_active: isize,
) {
let obj = data[y][x];
match obj {
Object::Stone => {
*count_stones += 1;
}
Object::CubeStone => {
*count_stones = 0;
}
Object::Empty => {
let c = *count_stones;
if c > 0 {
let vertical_factor = c * vertical_active;
let origin_y = y as isize - vertical_factor;
let horizontal_factor = c * horizontal_active;
let origin_x = x as isize - horizontal_factor;
// println!("moving stone from {origin_x}x{origin_y}y to {x}x{y}y with factors: h:{horizontal_factor} v:{vertical_factor}");
data[origin_y as usize][origin_x as usize] = Object::Empty;
data[y][x] = Object::Stone;
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum Direction {
North,
South,
West,
East,
}
impl Display for Direction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Direction::North => "North",
Direction::South => "South",
Direction::West => "West",
Direction::East => "East",
}
)
}
}

View File

@@ -32,6 +32,9 @@ pub use day09::*;
mod day10;
pub use day10::*;
mod day14;
pub use day14::*;
mod day19;
pub use day19::*;
@@ -145,10 +148,10 @@ impl<T> DayConvenience for T where T: Day {}
pub trait DayPart2Convenience: DayPart2 + DayConvenience {
fn run_day_part2_tests(){
let test_inputs = Self::get_multiple_test_data_part2();
let expected_results = Self::get_multiple_test_result();
let expected_results = Self::get_multiple_test_result_part2();
(test_inputs).zip(expected_results).enumerate().for_each(|(i,(input, expected))|{
let test_res = Self::run(input);
println!("Day {} test {i}: {:?}", Self::DAY_NUM, test_res);
let test_res = Self::run_part2(input);
println!("Day {} part 2 test {i}: {:?}", Self::DAY_NUM, test_res);
assert_eq!(expected, test_res);
})
}

View File

@@ -11,9 +11,12 @@ fn main() {
//Day07::run_all();
// Day09::run_all();
// Day09::part2();
Day10::part1();
// Day10::part1();
// Day10::part2();
// Day10::run_all();
Day14::run_all();
// Day14::part1();
// Day14::part2();
//Day19::run_all();
// Day19::part2();
// Day19::part2();