diff --git a/2022/rust/src/solutions/day19.rs b/2022/rust/src/solutions/day19.rs index d7fa58a..fd2879c 100644 --- a/2022/rust/src/solutions/day19.rs +++ b/2022/rust/src/solutions/day19.rs @@ -1,32 +1,131 @@ -use regex::{CaptureMatches, Captures, Regex, SubCaptureMatches}; +use std::collections::HashSet; +use regex::{Captures, Regex}; use crate::utils; pub fn run() -> () { - let data = parse_data(&utils::read_lines(utils::Source::Day(-1))); + let data = parse_data(&utils::read_lines(utils::Source::Day(19))); - println!("Day X"); + println!("Day 19"); println!("Part 1: {}", solve1(&data)); println!("Part 2: {}", solve2(&data)); } -#[derive(Debug)] struct Ore(i32); -#[derive(Debug)] struct Clay(i32); -#[derive(Debug)] struct Obsidian(i32); +type Ore = i32; +type Clay = i32; +type Obsidian = i32; +type Geode = i32; + #[derive(Debug)] struct Blueprint { - id: usize, + id: i32, ore: Ore, clay: Ore, obsidian: (Ore, Clay), geode: (Ore, Obsidian), } +#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Debug)] +struct State { + time_left: i32, + // Bot count + bot_ore: i32, + bot_cla: i32, + bot_obs: i32, + bot_geo: i32, + // Inventory count + inv_ore: Ore, + inv_cla: Clay, + inv_obs: Obsidian, + inv_geo: Geode, +} + + +fn explore(blueprint: &Blueprint, start: State) -> i32 { + let mut visited: HashSet = HashSet::new(); + let mut pending: Vec = Vec::new(); + pending.push(start); + + let max_req_ore = blueprint.geode.0.max(blueprint.obsidian.0).max(blueprint.clay).max(blueprint.ore); + let max_req_cla = blueprint.obsidian.1; + let max_req_obs = blueprint.geode.1; + + let mut max_geodes = 0; + while let Some(state) = pending.pop() { + match visited.contains(&state) { + true => continue, + false => visited.insert(state), + }; + if state.time_left == 0 { + max_geodes = max_geodes.max(state.inv_geo); + continue + } + + if state.inv_ore >= blueprint.geode.0 && state.inv_obs >= blueprint.geode.1 { + pending.push(State { + time_left: state.time_left - 1, + bot_geo: state.bot_geo + 1, + inv_ore: state.inv_ore + state.bot_ore - blueprint.geode.0, + inv_cla: state.inv_cla + state.bot_cla, + inv_obs: state.inv_obs + state.bot_obs - blueprint.geode.1, + inv_geo: state.inv_geo + state.bot_geo, + ..state + }); + }; + + if state.inv_ore >= blueprint.ore && state.bot_ore < max_req_ore { + pending.push(State { + time_left: state.time_left - 1, + bot_ore: state.bot_ore + 1, + inv_ore: state.inv_ore + state.bot_ore - blueprint.ore, + inv_cla: state.inv_cla + state.bot_cla, + inv_obs: state.inv_obs + state.bot_obs, + inv_geo: state.inv_geo + state.bot_geo, + ..state + }); + } + if state.inv_ore >= blueprint.clay && state.bot_cla < max_req_cla { + pending.push(State { + time_left: state.time_left - 1, + bot_cla: state.bot_cla + 1, + inv_ore: state.inv_ore + state.bot_ore - blueprint.clay, + inv_cla: state.inv_cla + state.bot_cla, + inv_obs: state.inv_obs + state.bot_obs, + inv_geo: state.inv_geo + state.bot_geo, + ..state + }) + } + if state.inv_ore >= blueprint.obsidian.0 && state.inv_cla >= blueprint.obsidian.1 && state.bot_obs < max_req_obs { + pending.push(State { + time_left: state.time_left - 1, + bot_obs: state.bot_obs + 1, + inv_ore: state.inv_ore + state.bot_ore - blueprint.obsidian.0, + inv_cla: state.inv_cla + state.bot_cla - blueprint.obsidian.1, + inv_obs: state.inv_obs + state.bot_obs, + inv_geo: state.inv_geo + state.bot_geo, + ..state + }); + } + if state.inv_ore < max_req_ore && state.inv_cla < max_req_cla && state.inv_obs < max_req_obs { + pending.push(State { + inv_ore: state.inv_ore + state.bot_ore, + inv_cla: state.inv_cla + state.bot_cla, + inv_obs: state.inv_obs + state.bot_obs, + inv_geo: state.inv_geo + state.bot_geo, + time_left: state.time_left - 1, + ..state + }); + } + } + max_geodes +} fn solve1(data: &[Blueprint]) -> i32 { - println!("{:?}", data); - 1 + let start_state = State { time_left: 24, bot_ore: 1, ..Default::default() }; + data.iter() + .map(|blueprint| blueprint.id * explore(blueprint, start_state)) + .sum() } fn solve2(data: &[Blueprint]) -> i32 { @@ -43,13 +142,13 @@ fn parse_data>(data: &[T]) -> Vec { ).unwrap(); data.iter() .map(|line| { - let mut cap = re.captures(line.as_ref()).unwrap(); + let cap = re.captures(line.as_ref()).unwrap(); Blueprint { - id: extract(&cap, 1) as usize, - ore: Ore(extract(&cap, 2)), - clay: Ore(extract(&cap, 3)), - obsidian: (Ore(extract(&cap, 4)), Clay(extract(&cap, 5))), - geode: (Ore(extract(&cap, 6)), Obsidian(extract(&cap, 7))), + id: extract(&cap, 1), + ore: extract(&cap, 2), + clay: extract(&cap, 3), + obsidian: (extract(&cap, 4), extract(&cap, 5)), + geode: (extract(&cap, 6), extract(&cap, 7)), } }) .collect() @@ -67,7 +166,7 @@ mod tests { #[test] fn part1() { - assert_eq!(1, solve1(&parse_data(DATA))); + assert_eq!(33, solve1(&parse_data(DATA))); } #[test]