Day 12.....
This commit is contained in:
parent
e0df7d08ef
commit
d610e7e757
2 changed files with 164 additions and 0 deletions
160
src/bin/day12.rs
Normal file
160
src/bin/day12.rs
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use aoc_2025::{Grid, load, print_res};
|
||||||
|
use bstr::{BString, ByteSlice};
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
enum ShapeSlot {
|
||||||
|
Full,
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Shape(Grid<ShapeSlot>);
|
||||||
|
|
||||||
|
impl std::fmt::Display for ShapeSlot {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ShapeSlot::Full => write!(f, "#"),
|
||||||
|
ShapeSlot::Empty => write!(f, "."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Shape {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Region {
|
||||||
|
lines: usize,
|
||||||
|
cols: usize,
|
||||||
|
shapes: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parsed = (Vec<Shape>, Vec<Region>);
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn parsing(input: &BString) -> color_eyre::Result<Parsed> {
|
||||||
|
let mut parts = input.split_str("\n\n").peekable();
|
||||||
|
let mut shapes = Vec::new();
|
||||||
|
|
||||||
|
for i in 0.. {
|
||||||
|
let Some(&part) = parts.peek() else {
|
||||||
|
color_eyre::eyre::bail!("Unexpected end of input\n");
|
||||||
|
};
|
||||||
|
let expect = format!("{i}:\n");
|
||||||
|
|
||||||
|
if !part.starts_with_str(&expect) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let part = parts.next().unwrap();
|
||||||
|
|
||||||
|
let line_len = part.lines().nth(1).unwrap().len();
|
||||||
|
let values = part
|
||||||
|
.lines()
|
||||||
|
.skip(1)
|
||||||
|
.flat_map(|l| {
|
||||||
|
l.iter().map(|&b| match b {
|
||||||
|
b'.' => Ok(ShapeSlot::Empty),
|
||||||
|
b'#' => Ok(ShapeSlot::Full),
|
||||||
|
_ => Err(color_eyre::eyre::eyre!("Invalid grid point: {}", b as char)),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
|
shapes.push(Shape(Grid::new(values, line_len)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(regions) = parts.next() else {
|
||||||
|
color_eyre::eyre::bail!("Unexpected end on input\n")
|
||||||
|
};
|
||||||
|
|
||||||
|
color_eyre::eyre::ensure!(parts.count() == 0, "Too many parts of the input");
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
shapes,
|
||||||
|
str::from_utf8(regions)?
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
let Some((size, shapes)) = line.split_once(": ") else {
|
||||||
|
color_eyre::eyre::bail!("Malformed region: {line}");
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some((lines, cols)) = size.split_once('x') else {
|
||||||
|
color_eyre::eyre::bail!("Malformed region size: {size}");
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Region {
|
||||||
|
lines: lines
|
||||||
|
.parse()
|
||||||
|
.wrap_err_with(|| format!("While parsing lines: {lines}"))?,
|
||||||
|
cols: cols
|
||||||
|
.parse()
|
||||||
|
.wrap_err_with(|| format!("While parsing cols: {cols}"))?,
|
||||||
|
shapes: shapes
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|n| {
|
||||||
|
n.parse()
|
||||||
|
.wrap_err_with(|| format!("While parsing shape: {n}"))
|
||||||
|
})
|
||||||
|
.collect::<Result<_, _>>()?,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<_, _>>()?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn part1((shapes, regions): Parsed) {
|
||||||
|
let shape_areas: Vec<_> = shapes.iter().map(|s| s.0.count(&ShapeSlot::Full)).collect();
|
||||||
|
let mut remain = 0;
|
||||||
|
|
||||||
|
for region in regions {
|
||||||
|
let area = region.lines * region.cols;
|
||||||
|
let min_area: usize = region
|
||||||
|
.shapes
|
||||||
|
.iter()
|
||||||
|
.zip(&shape_areas)
|
||||||
|
.map(|(&n, &a)| n as usize * a)
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
// Not enough area to even attempt
|
||||||
|
if min_area > area {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
remain += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_res!("Possible solvable: {remain}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn part2(input: Parsed) {
|
||||||
|
todo!("todo part2")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() -> color_eyre::Result<()> {
|
||||||
|
let context = load()?;
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let parsed = parsing(&context.input)?;
|
||||||
|
let elapsed = humantime::format_duration(start.elapsed());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
if context.part == 1 {
|
||||||
|
part1(parsed);
|
||||||
|
} else {
|
||||||
|
part2(parsed);
|
||||||
|
}
|
||||||
|
let elapsed_part = humantime::format_duration(start.elapsed());
|
||||||
|
|
||||||
|
println!(" Parsing: {elapsed}");
|
||||||
|
println!(" Solving: {elapsed_part}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -69,6 +69,10 @@ impl<T: PartialEq + Eq> Grid<T> {
|
||||||
}
|
}
|
||||||
sum
|
sum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn count(&self, like: &T) -> usize {
|
||||||
|
self.values.iter().filter(|&v| v == like).count()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::ops::Index<(usize, usize)> for Grid<T> {
|
impl<T> std::ops::Index<(usize, usize)> for Grid<T> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue