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
|
||||
}
|
||||
|
||||
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> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue