Day 6
This commit is contained in:
parent
fe8a63cd27
commit
36008a5622
1 changed files with 195 additions and 0 deletions
195
src/bin/day6.rs
Normal file
195
src/bin/day6.rs
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use aoc_2025::{load, print_res};
|
||||||
|
use bstr::{BStr, BString, ByteSlice};
|
||||||
|
use color_eyre::eyre::ContextCompat;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Op {
|
||||||
|
Sum,
|
||||||
|
Product,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Op {
|
||||||
|
pub fn parse(v: &[u8]) -> color_eyre::Result<Self> {
|
||||||
|
match v {
|
||||||
|
b"+" => Ok(Op::Sum),
|
||||||
|
b"*" => Ok(Op::Product),
|
||||||
|
_ => color_eyre::eyre::bail!("Invalid operation: `{}`", v.as_bstr()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parsed<'a> = Vec<&'a BStr>;
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn parsing(input: &BString) -> color_eyre::Result<Parsed<'_>> {
|
||||||
|
Ok(input.lines().map(|a| a.as_bstr()).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
type Problem = (Op, Vec<u64>);
|
||||||
|
|
||||||
|
fn parse_part1(input: Parsed) -> color_eyre::Result<Vec<Problem>> {
|
||||||
|
let mut values = Vec::new();
|
||||||
|
|
||||||
|
for line in input {
|
||||||
|
if line.starts_with(b"+") || line.starts_with(b"*") {
|
||||||
|
return line
|
||||||
|
.fields()
|
||||||
|
.map(Op::parse)
|
||||||
|
.zip(values.into_iter())
|
||||||
|
.map(|(r, v)| Ok((r?, v)))
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
let line = str::from_utf8(line)?;
|
||||||
|
|
||||||
|
if values.is_empty() {
|
||||||
|
values = line
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|v| Ok::<_, color_eyre::Report>(vec![v.parse()?]))
|
||||||
|
.collect::<Result<_, _>>()?;
|
||||||
|
} else {
|
||||||
|
line.split_whitespace()
|
||||||
|
.zip(values.iter_mut())
|
||||||
|
.try_for_each(|(v, col)| {
|
||||||
|
col.push(v.parse()?);
|
||||||
|
Ok::<_, color_eyre::Report>(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color_eyre::eyre::bail!("Operations not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grand_total(problems: &[Problem]) -> u64 {
|
||||||
|
let mut grand_total = 0;
|
||||||
|
|
||||||
|
for (op, values) in problems {
|
||||||
|
match op {
|
||||||
|
Op::Sum => grand_total += values.iter().sum::<u64>(),
|
||||||
|
Op::Product => grand_total += values.iter().product::<u64>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grand_total
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_part2(input: Parsed) -> color_eyre::Result<Vec<Problem>> {
|
||||||
|
let num_cols = input
|
||||||
|
.first()
|
||||||
|
.with_context(|| "input is empty")?
|
||||||
|
.fields()
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let mut col_widths = vec![0; num_cols];
|
||||||
|
|
||||||
|
for line in &input {
|
||||||
|
line.fields()
|
||||||
|
.zip(col_widths.iter_mut())
|
||||||
|
.for_each(|(v, max)| *max = (*max).max(v.len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let col_width_sum = col_widths.iter().sum::<usize>() + col_widths.len() - 1;
|
||||||
|
|
||||||
|
let mut iter = input.iter();
|
||||||
|
let mut cols: Vec<_> = col_widths
|
||||||
|
.iter()
|
||||||
|
.map(|&w| vec![None::<(u64, bool)>; w])
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let line = iter.next().with_context(|| "Unexpected end of input")?;
|
||||||
|
|
||||||
|
color_eyre::eyre::ensure!(
|
||||||
|
line.len() == col_width_sum,
|
||||||
|
"Line `{line}` is of an incorrect length (expected {col_width_sum})"
|
||||||
|
);
|
||||||
|
|
||||||
|
if line[0] == b'*' || line[0] == b'+' {
|
||||||
|
return line
|
||||||
|
.fields()
|
||||||
|
.map(Op::parse)
|
||||||
|
.zip(cols)
|
||||||
|
.map(|(op, v)| {
|
||||||
|
let op = op?;
|
||||||
|
let values = v
|
||||||
|
.into_iter()
|
||||||
|
.map(|n| match n {
|
||||||
|
Some((v, _)) => Ok(v),
|
||||||
|
None => color_eyre::eyre::bail!("No number found"),
|
||||||
|
})
|
||||||
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
|
Ok((op, values))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut line: &[u8] = line;
|
||||||
|
|
||||||
|
for (values, &width) in cols.iter_mut().zip(&col_widths) {
|
||||||
|
for (value, &digit) in values.iter_mut().zip(line.iter()) {
|
||||||
|
if digit == b' ' {
|
||||||
|
match value {
|
||||||
|
// Mark the number as finished
|
||||||
|
&mut Some((v, false)) => *value = Some((v, true)),
|
||||||
|
// Already finished, skip this number
|
||||||
|
Some((_, true)) => continue,
|
||||||
|
// Not yet started, skip this number
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let digit = (digit - b'0') as u64;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
Some((_, true)) => {
|
||||||
|
color_eyre::eyre::bail!("Number has re-started after it has ended")
|
||||||
|
}
|
||||||
|
Some((v, _)) => *v = *v * 10 + digit,
|
||||||
|
None => *value = Some((digit, false)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.len() > width {
|
||||||
|
line = &line[width + 1..];
|
||||||
|
} else {
|
||||||
|
line = &[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn part1(input: Parsed) {
|
||||||
|
let grand_total = grand_total(&parse_part1(input).unwrap());
|
||||||
|
print_res!("Grand total is: {grand_total}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn part2(input: Parsed) {
|
||||||
|
let grand_total = grand_total(&parse_part2(input).unwrap());
|
||||||
|
print_res!("Grand total is: {grand_total}");
|
||||||
|
}
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue