Solve day 6
This commit is contained in:
@@ -8,7 +8,7 @@ clap = { version = "4.5", features = ["derive"] }
|
||||
color-eyre = "0.6"
|
||||
itertools = "0.14"
|
||||
rayon = "1.11"
|
||||
tracing = "0.1"
|
||||
tracing = { version = "0.1", features = ["release_max_level_info"] }
|
||||
tracing-error = "0.2"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ Timings are given as: [lower-bound **best-estimate** upper-bound]
|
||||
| 03 | [45.711 µs **45.937 µs** 46.177 µs] | [267.18 µs **267.95 µs** 268.75 µs] |
|
||||
| 04 | [143.40 µs **144.00 µs** 144.73 µs] | [1.6165 ms **1.6258 ms** 1.6355 ms] |
|
||||
| 05 | [187.25 µs **188.93 µs** 190.74 µs] | [63.809 µs **64.204 µs** 64.606 µs] |
|
||||
| 06 | [128.44 µs **129.44 µs** 130.52 µs] | [165.05 µs **165.70 µs** 166.36 µs] |
|
||||
|
||||
## Profiling
|
||||
|
||||
|
||||
4
src/day06/input/test1.txt
Normal file
4
src/day06/input/test1.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
123 328 51 64
|
||||
45 64 387 23
|
||||
6 98 215 314
|
||||
* + * +
|
||||
212
src/day06/mod.rs
Normal file
212
src/day06/mod.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use color_eyre::{
|
||||
Result,
|
||||
eyre::{Context, Error, OptionExt, eyre},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
pub const INPUT: &str = include_str!("input/input.txt");
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Operation {
|
||||
Add,
|
||||
Multiply,
|
||||
}
|
||||
|
||||
impl FromStr for Operation {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"+" => Ok(Operation::Add),
|
||||
"*" => Ok(Operation::Multiply),
|
||||
_ => Err(eyre!("invalid operation: {}", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
fn from_byte(byte: u8) -> Result<Self> {
|
||||
match byte {
|
||||
b'+' => Ok(Operation::Add),
|
||||
b'*' => Ok(Operation::Multiply),
|
||||
_ => Err(eyre!("invalid operation byte: {}", byte)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Problem {
|
||||
numbers: Vec<u64>,
|
||||
operation: Operation,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CephalopodProblem {
|
||||
columns: Vec<Vec<u8>>,
|
||||
operation: Operation,
|
||||
width: u8,
|
||||
}
|
||||
|
||||
#[instrument(skip(input))]
|
||||
pub fn part1(input: &str) -> Result<u64> {
|
||||
let mut lines = input.trim().lines();
|
||||
let first_numbers: Vec<u64> = lines
|
||||
.next()
|
||||
.ok_or_eyre("no first line in input")?
|
||||
.split_whitespace()
|
||||
.map(|s| s.parse::<u64>().context("parsing number"))
|
||||
.collect::<Result<Vec<u64>>>()?;
|
||||
let mut problems = first_numbers
|
||||
.into_iter()
|
||||
.map(|n| Problem {
|
||||
numbers: vec![n],
|
||||
operation: Operation::Add,
|
||||
})
|
||||
.collect::<Vec<Problem>>();
|
||||
for line in lines {
|
||||
let first_byte = line.bytes().nth(0).ok_or_eyre("empty line in input")?;
|
||||
if matches!(first_byte, b'*' | b'+') {
|
||||
for (index, op_result) in line.split_whitespace().map(|s| s.parse()).enumerate() {
|
||||
let op = op_result?;
|
||||
problems[index].operation = op;
|
||||
}
|
||||
} else {
|
||||
for (index, num_result) in line.split_whitespace().map(|s| s.parse()).enumerate() {
|
||||
let num = num_result?;
|
||||
problems[index].numbers.push(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(problems
|
||||
.into_iter()
|
||||
.map(|problem| match problem.operation {
|
||||
Operation::Add => {
|
||||
let sum = problem.numbers.iter().sum::<u64>();
|
||||
debug!("{} = {}", problem.numbers.iter().join(" + "), sum);
|
||||
return sum;
|
||||
}
|
||||
Operation::Multiply => {
|
||||
let product = problem.numbers.iter().product::<u64>();
|
||||
debug!("{} = {}", problem.numbers.iter().join(" * "), product);
|
||||
return product;
|
||||
}
|
||||
})
|
||||
.sum())
|
||||
}
|
||||
|
||||
#[instrument(skip(input))]
|
||||
pub fn part2(input: &str) -> Result<usize> {
|
||||
let mut lines = input.lines();
|
||||
let last_line = lines.next_back().ok_or_eyre("no last line in input")?;
|
||||
let mut problems = Vec::new();
|
||||
let mut spaces: u8 = 1;
|
||||
for byte in last_line.bytes().rev() {
|
||||
if byte.is_ascii_whitespace() {
|
||||
spaces += 1;
|
||||
} else {
|
||||
problems.push(CephalopodProblem {
|
||||
columns: (0..spaces).map(|_| Vec::new()).collect(),
|
||||
operation: Operation::from_byte(byte)?,
|
||||
width: spaces,
|
||||
});
|
||||
spaces = 0;
|
||||
}
|
||||
}
|
||||
debug!(last_problem = ?problems[0]);
|
||||
debug!(second_last_problem = ?problems[1]);
|
||||
problems.reverse();
|
||||
for line in lines {
|
||||
let bytes = line.as_bytes();
|
||||
let mut offset = 0;
|
||||
for i in 0..problems.len() {
|
||||
if offset + (problems[i].width as usize) > bytes.len() {
|
||||
return Err(eyre!("line too short for problem columns"));
|
||||
}
|
||||
for (cell_col, &byte) in bytes[offset..offset + problems[i].width as usize]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if !byte.is_ascii_whitespace() {
|
||||
problems[i].columns[cell_col].push(byte - b'0');
|
||||
}
|
||||
}
|
||||
offset += problems[i].width as usize + 1;
|
||||
}
|
||||
}
|
||||
debug!(first_problem = ?problems[0]);
|
||||
debug!(second_problem = ?problems[1]);
|
||||
Ok(problems
|
||||
.iter()
|
||||
.map(|problem| match problem.operation {
|
||||
Operation::Add => {
|
||||
let sum: usize = problem
|
||||
.columns
|
||||
.iter()
|
||||
.map(|col| {
|
||||
col.iter()
|
||||
.fold(0usize, |acc, &digit| acc * 10 + (digit as usize))
|
||||
})
|
||||
.sum();
|
||||
debug!(
|
||||
"{} = {}",
|
||||
problem
|
||||
.columns
|
||||
.iter()
|
||||
.map(|col| {
|
||||
col.iter()
|
||||
.fold(0usize, |acc, &digit| acc * 10 + (digit as usize))
|
||||
.to_string()
|
||||
})
|
||||
.join(" + "),
|
||||
sum
|
||||
);
|
||||
sum
|
||||
}
|
||||
Operation::Multiply => {
|
||||
let product: usize = problem
|
||||
.columns
|
||||
.iter()
|
||||
.map(|col| {
|
||||
col.iter()
|
||||
.fold(0usize, |acc, &digit| acc * 10 + (digit as usize))
|
||||
})
|
||||
.product();
|
||||
debug!(
|
||||
"{} = {}",
|
||||
problem
|
||||
.columns
|
||||
.iter()
|
||||
.map(|col| {
|
||||
col.iter()
|
||||
.fold(0usize, |acc, &digit| acc * 10 + (digit as usize))
|
||||
.to_string()
|
||||
})
|
||||
.join(" * "),
|
||||
product
|
||||
);
|
||||
product
|
||||
}
|
||||
})
|
||||
.sum())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use test_log::test;
|
||||
|
||||
const TEST_INPUT1: &str = include_str!("input/test1.txt");
|
||||
|
||||
#[test]
|
||||
fn test_part1() {
|
||||
assert_eq!(part1(TEST_INPUT1).unwrap(), 4277556);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() {
|
||||
assert_eq!(part2(TEST_INPUT1).unwrap(), 3263827);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ macro_rules! all_days {
|
||||
3 => day03,
|
||||
4 => day04,
|
||||
5 => day05,
|
||||
6 => day06,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ pub mod day02;
|
||||
pub mod day03;
|
||||
pub mod day04;
|
||||
pub mod day05;
|
||||
pub mod day06;
|
||||
pub mod days;
|
||||
|
||||
Reference in New Issue
Block a user