Day 17 part 1

This commit is contained in:
2023-05-26 22:23:19 +02:00
parent cfb3ae497e
commit 8bc589488c
4 changed files with 1624 additions and 29 deletions

16
Cargo.lock generated
View File

@@ -15,6 +15,7 @@ dependencies = [
name = "aoc_2018" name = "aoc_2018"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bmp",
"chrono", "chrono",
"gcd", "gcd",
"itertools", "itertools",
@@ -22,6 +23,21 @@ dependencies = [
"regex", "regex",
] ]
[[package]]
name = "bmp"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69985ff4f58085ac696454692d0b646a66ad1f9cc9be294c91dc51bb5df511ae"
dependencies = [
"byteorder",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.6" version = "0.1.6"

View File

@@ -10,3 +10,4 @@ chrono = "0.4.6"
itertools = "0.7.11" itertools = "0.7.11"
gcd = "1.1.0" gcd = "1.1.0"
lazy_static = "1.2.0" lazy_static = "1.2.0"
bmp = "0.5.0"

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,9 @@
use bmp::Image;
use itertools::Itertools; use itertools::Itertools;
use regex::Regex; use regex::Regex;
use crate::utils; use crate::utils;
use std::collections::HashMap; use std::{collections::HashMap, fmt::Display};
use Tile::*; use Tile::*;
fn horizontal(line: &str) -> Option<(i32, i32, i32)> { fn horizontal(line: &str) -> Option<(i32, i32, i32)> {
@@ -28,41 +29,156 @@ fn vertical(line: &str) -> Option<(i32, i32, i32)> {
} }
pub fn task1() { pub fn task1() {
let input = utils::read_file("input/day17.txt"); let input = utils::read_file("input/day17.txt");
let clay_tiles: HashMap<Pos, Tile> = input.lines().fold(HashMap::new(), |mut tiles, line| { let mut clay_tiles: HashMap<Pos, Tile> =
if let Some((x, y1, y2)) = vertical(line) { input.lines().fold(HashMap::new(), |mut tiles, line| {
for y in y1..=y2 { if let Some((x, y1, y2)) = vertical(line) {
tiles.insert(Pos(x, y), Clay); for y in y1..=y2 {
tiles.insert(Pos(x, y), Clay);
}
} }
} if let Some((y, x1, x2)) = horizontal(line) {
if let Some((y, x1, x2)) = horizontal(line) { for x in x1..=x2 {
for x in x1..=x2 { tiles.insert(Pos(x, y), Clay);
tiles.insert(Pos(x, y), Clay); }
} }
} tiles
tiles });
});
let (x_min, x_max) = clay_tiles
.keys()
.map(|p| p.0)
.minmax()
.into_option()
.unwrap();
let (y_min, y_max) = clay_tiles let (y_min, y_max) = clay_tiles
.keys() .keys()
.map(|p| p.1) .map(|p| p.1)
.minmax() .minmax()
.into_option() .into_option()
.unwrap(); .unwrap();
flow(&mut clay_tiles, y_max, Pos(500, 0), Pos(500, 0));
let water_count = clay_tiles
.iter()
.filter(|(_, tile)| **tile == StuckWater || **tile == FallingWater)
.filter(|(p, _)| (y_min..=y_max).contains(&p.1))
.count();
println!("part 1 water count: {water_count}");
// print_tiles(&clay_tiles);
// 30605 too low
print_bmp(&clay_tiles);
} }
#[allow(dead_code)]
fn print_tiles(tiles: &HashMap<Pos, Tile>) {
let (x_min, x_max) = tiles.keys().map(|p| p.0).minmax().into_option().unwrap();
let (_y_min, y_max) = tiles.keys().map(|p| p.1).minmax().into_option().unwrap();
for y in 0..=y_max {
for x in x_min..=x_max {
let s = match tiles.get(&Pos(x, y)) {
Some(t) => format!("{t}"),
None => " ".to_string(),
};
print!("{s}");
}
print!("\n");
}
}
fn print_bmp(tiles: &HashMap<Pos, Tile>) {
let (x_min, x_max) = tiles.keys().map(|p| p.0).minmax().into_option().unwrap();
let (y_min, y_max) = tiles.keys().map(|p| p.1).minmax().into_option().unwrap();
let mut img = Image::new((x_max - x_min + 1) as u32, (y_max - y_min + 1) as u32);
for y in 0..=y_max {
for x in x_min..=x_max {
let color = match tiles.get(&Pos(x, y)) {
Some(t) => match t {
Clay => bmp::consts::BROWN,
FallingWater => bmp::consts::LIGHT_BLUE,
StuckWater => bmp::consts::DARK_BLUE,
},
None => bmp::consts::WHITE,
};
img.set_pixel((x - x_min) as u32, (y - y_min) as u32, color);
}
}
img.save("final.bmp").unwrap();
}
/// returns true iff going left/right and hit a wall
fn flow(tiles: &mut HashMap<Pos, Tile>, y_max: i32, pos: Pos, from: Pos) -> bool {
if pos.1 > y_max {
return false;
}
if let Some(Clay) = tiles.get(&pos) {
return true;
}
if let Some(StuckWater) = tiles.get(&pos) {
return true;
}
if tiles.contains_key(&pos) {
return false;
}
tiles.insert(pos, FallingWater);
// println!();
// print_tiles(tiles);
if flow(tiles, y_max, pos.down(), pos) {
let bumped_left = flow(tiles, y_max, pos.left(), pos);
let bumped_right = flow(tiles, y_max, pos.right(), pos);
if from.down() == pos {
if bumped_right && bumped_left {
fill(tiles, pos);
// println!();
// print_tiles(tiles);
return true;
}
} else if from.right() == pos && bumped_right {
return true;
} else if from.left() == pos && bumped_left {
return true;
}
}
false
}
fn fill(tiles: &mut HashMap<Pos, Tile>, pos: Pos) {
if let Some(FallingWater) = tiles.get(&pos) {
tiles.insert(pos, StuckWater);
fill(tiles, pos.left());
fill(tiles, pos.right());
}
}
#[derive(PartialEq, Eq)]
enum Tile { enum Tile {
Clay, Clay,
Water, FallingWater,
StuckWater,
} }
#[derive(PartialEq, Eq, Hash)] impl Display for Tile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Clay => "#",
FallingWater => "|",
StuckWater => "~",
};
f.write_str(s)
}
}
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
struct Pos(i32, i32); struct Pos(i32, i32);
impl Pos {
fn left(&self) -> Self {
Pos(self.0 - 1, self.1)
}
fn right(&self) -> Self {
Pos(self.0 + 1, self.1)
}
fn down(&self) -> Self {
Pos(self.0, self.1 + 1)
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;