mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Terribly inefficient part 1
This commit is contained in:
@@ -1,9 +1,188 @@
|
|||||||
use anyhow::Result;
|
use std::ops::Add;
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
pub fn part1(_input: &[u8]) -> Result<String> {
|
use anyhow::Result;
|
||||||
anyhow::bail!("not implemented")
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::character::complete::multispace1;
|
||||||
|
use nom::character::streaming::alpha1;
|
||||||
|
use nom::combinator::map_res;
|
||||||
|
use nom::combinator::opt;
|
||||||
|
use nom::multi::many1;
|
||||||
|
use nom::sequence::delimited;
|
||||||
|
use nom::sequence::preceded;
|
||||||
|
use nom::sequence::separated_pair;
|
||||||
|
use nom::sequence::terminated;
|
||||||
|
use nom::sequence::tuple;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
use crate::common::parse_input;
|
||||||
|
|
||||||
|
#[repr(usize)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum Mineral {
|
||||||
|
Ore,
|
||||||
|
Clay,
|
||||||
|
Obsidian,
|
||||||
|
Geode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&'_ [u8]> for Mineral {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(value: &'_ [u8]) -> std::result::Result<Self, Self::Error> {
|
||||||
|
dbg!(String::from_utf8_lossy(value));
|
||||||
|
match value {
|
||||||
|
b"ore" => Ok(Self::Ore),
|
||||||
|
b"clay" => Ok(Self::Clay),
|
||||||
|
b"obsidian" => Ok(Self::Obsidian),
|
||||||
|
b"geode" => Ok(Self::Geode),
|
||||||
|
other => Err(format!(
|
||||||
|
"Invalid mineral '{}'",
|
||||||
|
String::from_utf8_lossy(other)
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
|
struct Resources([u8; 4]);
|
||||||
|
|
||||||
|
impl Resources {
|
||||||
|
fn enough_for(self, other: Self) -> bool {
|
||||||
|
self.0.iter().zip(&other.0).all(|(a, b)| a >= b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Resources {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(std::array::from_fn(|i| self.0[i] - rhs.0[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<[u8; 4]> for Resources {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: [u8; 4]) -> Self::Output {
|
||||||
|
Self(std::array::from_fn(|i| self.0[i] + rhs[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BluePrint {
|
||||||
|
id: u32,
|
||||||
|
costs: [Resources; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BluePrint {
|
||||||
|
pub fn max_geodes(&self) -> u8 {
|
||||||
|
self.max_geodes_recursive(24, 0, [1, 0, 0, 0], Resources::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_geodes_recursive(
|
||||||
|
&self,
|
||||||
|
time_left: u32,
|
||||||
|
// forbidden is a bitset for convenience
|
||||||
|
forbidden: u8,
|
||||||
|
machines: [u8; 4],
|
||||||
|
resources: Resources,
|
||||||
|
) -> u8 {
|
||||||
|
if time_left <= 1 {
|
||||||
|
return resources.0[3] + machines[3] * (time_left as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
let resources_after = resources + machines;
|
||||||
|
|
||||||
|
let mut best = 0;
|
||||||
|
|
||||||
|
let mut can_buy = 0;
|
||||||
|
|
||||||
|
for (i, &cost) in self.costs.iter().enumerate() {
|
||||||
|
if ((1 << i) & forbidden) == 0 && resources.enough_for(cost) {
|
||||||
|
can_buy |= 1 << i;
|
||||||
|
let mut new_machines = machines;
|
||||||
|
new_machines[i] += 1;
|
||||||
|
|
||||||
|
best = best.max(self.max_geodes_recursive(
|
||||||
|
time_left - 1,
|
||||||
|
0,
|
||||||
|
new_machines,
|
||||||
|
resources_after - cost,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
best.max(self.max_geodes_recursive(
|
||||||
|
time_left - 1,
|
||||||
|
forbidden | can_buy,
|
||||||
|
machines,
|
||||||
|
resources_after,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_blueprint(input: &[u8]) -> IResult<&[u8], BluePrint> {
|
||||||
|
use nom::character::complete::u32;
|
||||||
|
|
||||||
|
fn parse_mineral(input: &[u8]) -> IResult<&[u8], Mineral> {
|
||||||
|
map_res(alpha1, Mineral::try_from)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_cost(input: &[u8]) -> IResult<&[u8], (u8, Mineral)> {
|
||||||
|
separated_pair(nom::character::complete::u8, tag(" "), parse_mineral)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut input, id) =
|
||||||
|
terminated(delimited(tag("Blueprint "), u32, tag(":")), multispace1)(input)?;
|
||||||
|
|
||||||
|
let mut costs: [Resources; 4] = Default::default();
|
||||||
|
|
||||||
|
let mut parse_robot = terminated(
|
||||||
|
tuple((
|
||||||
|
preceded(tag("Each "), parse_mineral),
|
||||||
|
preceded(tag(" robot costs "), parse_cost),
|
||||||
|
terminated(opt(preceded(tag(" and "), parse_cost)), tag(".")),
|
||||||
|
)),
|
||||||
|
multispace1,
|
||||||
|
);
|
||||||
|
|
||||||
|
for _ in 0..4 {
|
||||||
|
let (remaining, (element, (amount1, req1), cost2)) = parse_robot(input)?;
|
||||||
|
input = remaining;
|
||||||
|
|
||||||
|
costs[element as usize].0[req1 as usize] = amount1;
|
||||||
|
|
||||||
|
if let Some((amount2, req2)) = cost2 {
|
||||||
|
costs[element as usize].0[req2 as usize] = amount2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((input, BluePrint { id, costs }))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: &[u8]) -> Result<String> {
|
||||||
|
let blueprints = parse_input(input, many1(parse_blueprint))?;
|
||||||
|
|
||||||
|
Ok(blueprints
|
||||||
|
.into_iter()
|
||||||
|
.map(|bp| dbg!(bp.max_geodes()) as u32 * bp.id)
|
||||||
|
.sum::<u32>()
|
||||||
|
.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part2(_input: &[u8]) -> Result<String> {
|
pub fn part2(_input: &[u8]) -> Result<String> {
|
||||||
anyhow::bail!("not implemented")
|
anyhow::bail!("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SAMPLE: &[u8] = include_bytes!("./samples/19.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part1() {
|
||||||
|
assert_eq!(part1(SAMPLE).unwrap(), "33");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user