From 822b5241cfc04c1a0e41e5973cc6e8b1706c157b Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Mon, 19 Dec 2022 18:14:00 +0530 Subject: [PATCH] Added day 19 --- src/day19/1.rs | 210 +++++++++++++++++++++++++++++++++++++++++++ src/day19/2.rs | 210 +++++++++++++++++++++++++++++++++++++++++++ src/day19/input.txt | 30 +++++++ src/day19/sample.txt | 2 + 4 files changed, 452 insertions(+) create mode 100644 src/day19/input.txt create mode 100644 src/day19/sample.txt diff --git a/src/day19/1.rs b/src/day19/1.rs index e69de29..a997108 100644 --- a/src/day19/1.rs +++ b/src/day19/1.rs @@ -0,0 +1,210 @@ +#![feature(test)] +extern crate test; + +use std::collections::HashMap; + +const INPUTS: [&[u8]; 2] = [ + include_bytes!("./sample.txt"), + include_bytes!("./input.txt"), +]; + +fn parse(input: &[u8]) -> Vec> { + input + .split(|&b| b == b'\n') + .filter(|c| !c.is_empty()) + .map(|line| { + let mut out = vec![]; + for set in line.split(|&c| c == b' ') { + let set: Vec = set + .iter() + .filter(|&c| (b'0'..=b'9').contains(c)) + .cloned() + .collect(); + + if set.is_empty() { + continue; + } + + out.push(set.iter().fold(0, |a, x| (a * 10) + (x - b'0') as usize)); + } + + out + }) + .collect() +} + +fn solution(input: Vec>) -> usize { + input + .iter() + .map(|ip| { + let mut memo = HashMap::new(); + solve(&mut memo, ip, (0, 0, 0, 0), (1, 0, 0, 0), 0) * ip[0] + }) + .sum() +} + +type Store = (usize, usize, usize, usize); + +const UPTO_MINUTE: usize = 24; + +fn solve( + memo: &mut HashMap<(usize, Store, Store), usize>, + costs: &[usize], + (mut ia, mut ib, ic, id): Store, + (ra, rb, rc, rd): Store, + m: usize, +) -> usize { + if m >= UPTO_MINUTE { + return id; + } + + if let Some(v) = memo.get(&(m, (ia, ib, ic, id), (ra, rb, rc, rd))) { + return *v; + } + + let maximum_ore = std::cmp::max( + std::cmp::max(costs[1], costs[2]), + std::cmp::max(costs[3], costs[5]), + ); + let maximum_clay = costs[4]; + let maximum_obsidian = costs[6]; + + let mut answer = 0; + for min in m..=UPTO_MINUTE { + let oia = ia; + let oib = ib; + + let mut built_a_robot = false; + + // Geode robot + let [ore, _, obsidian] = find_cost(costs, 3); + let count = std::cmp::min(ia / ore, ic / obsidian); + let remain_ia = ia - (count * ore); + let remain_ic = ic - (count * obsidian); + + if count > 0 { + built_a_robot = true; + } + + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (remain_ia + ra, ib + rb, remain_ic + rc, id + rd), + (ra, rb, rc, rd + count), + min + 1, + ), + ); + + if built_a_robot { + continue; + } + + // Obsidian robot + if rc < maximum_obsidian { + let [ore, clay, _] = find_cost(costs, 2); + while ia >= ore && ib >= clay { + ia -= ore; + ib -= clay; + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (ia + ra, ib + rb, ic + rc, id + rd), + (ra, rb, rc + 1, rd), + min + 1, + ), + ); + } + built_a_robot = true; + ia = oia; + ib = oib; + } + + if rb < maximum_clay { + let [ore, _, _] = find_cost(costs, 1); + while ia >= ore { + ia -= ore; + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (ia + ra, ib + rb, ic + rc, id + rd), + (ra, rb + 1, rc, rd), + min + 1, + ), + ); + } + ia = oia; + built_a_robot = true; + } + + // Make robots + if ra < maximum_ore { + let [ore, _, _] = find_cost(costs, 0); + while ia >= ore { + ia -= ore; + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (ia + ra, ib + rb, ic + rc, id + rd), + (ra + 1, rb, rc, rd), + min + 1, + ), + ); + } + ia = oia; + built_a_robot = true; + } + + if !built_a_robot { + // Increase resource without doing any thing else + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (ia + ra, ib + rb, ic + rc, id + rd), + (ra, rb, rc, rd), + min + 1, + ), + ); + } + } + + memo.insert((m, (ia, ib, ic, id), (ra, rb, rc, rd)), answer); + + answer +} + +#[inline] +const fn find_cost(costs: &[usize], i: usize) -> [usize; 3] { + match i { + 0 => [costs[1], 0, 0], + 1 => [costs[2], 0, 0], + 2 => [costs[3], costs[4], 0], + 3 => [costs[5], 0, costs[6]], + _ => unreachable!(), + } +} + +fn main() { + for input in INPUTS.iter() { + let output = parse(input); + let score = solution(output); + println!("{}", score); + } +} +#[bench] +fn solution_bench(b: &mut test::Bencher) { + b.iter(|| { + let input = parse(INPUTS[1]); + let result = solution(input); + test::black_box(result); + }) +} diff --git a/src/day19/2.rs b/src/day19/2.rs index e69de29..479ac70 100644 --- a/src/day19/2.rs +++ b/src/day19/2.rs @@ -0,0 +1,210 @@ +#![feature(test)] +extern crate test; +use std::collections::HashMap; + +const INPUTS: [&[u8]; 2] = [ + include_bytes!("./sample.txt"), + include_bytes!("./input.txt"), +]; + +fn parse(input: &[u8]) -> Vec> { + input + .split(|&b| b == b'\n') + .filter(|c| !c.is_empty()) + .map(|line| { + let mut out = vec![]; + for set in line.split(|&c| c == b' ') { + let set: Vec = set + .iter() + .filter(|&c| (b'0'..=b'9').contains(c)) + .cloned() + .collect(); + + if set.is_empty() { + continue; + } + + out.push(set.iter().fold(0, |a, x| (a * 10) + (x - b'0') as usize)); + } + + out + }) + .collect() +} + +fn solution(input: Vec>) -> usize { + input + .iter() + .take(3) + .map(|ip| { + let mut memo = HashMap::new(); + solve(&mut memo, ip, (0, 0, 0, 0), (1, 0, 0, 0), 0) + }) + .product() +} + +type Store = (usize, usize, usize, usize); + +const UPTO_MINUTE: usize = 32; + +fn solve( + memo: &mut HashMap<(usize, Store, Store), usize>, + costs: &[usize], + (mut ia, mut ib, ic, id): Store, + (ra, rb, rc, rd): Store, + m: usize, +) -> usize { + if m >= UPTO_MINUTE { + return id; + } + + if let Some(v) = memo.get(&(m, (ia, ib, ic, id), (ra, rb, rc, rd))) { + return *v; + } + + let maximum_ore = std::cmp::max( + std::cmp::max(costs[1], costs[2]), + std::cmp::max(costs[3], costs[5]), + ); + let maximum_clay = costs[4]; + let maximum_obsidian = costs[6]; + + let mut answer = 0; + for min in m..=UPTO_MINUTE { + let oia = ia; + let oib = ib; + + let mut built_a_robot = false; + + // Geode robot + let [ore, _, obsidian] = find_cost(costs, 3); + let count = std::cmp::min(ia / ore, ic / obsidian); + let remain_ia = ia - (count * ore); + let remain_ic = ic - (count * obsidian); + + if count > 0 { + built_a_robot = true; + } + + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (remain_ia + ra, ib + rb, remain_ic + rc, id + rd), + (ra, rb, rc, rd + count), + min + 1, + ), + ); + + if built_a_robot { + continue; + } + + // Obsidian robot + if rc < maximum_obsidian { + let [ore, clay, _] = find_cost(costs, 2); + while ia >= ore && ib >= clay { + ia -= ore; + ib -= clay; + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (ia + ra, ib + rb, ic + rc, id + rd), + (ra, rb, rc + 1, rd), + min + 1, + ), + ); + } + built_a_robot = true; + ia = oia; + ib = oib; + } + + if rb < maximum_clay { + let [ore, _, _] = find_cost(costs, 1); + while ia >= ore { + ia -= ore; + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (ia + ra, ib + rb, ic + rc, id + rd), + (ra, rb + 1, rc, rd), + min + 1, + ), + ); + } + ia = oia; + built_a_robot = true; + } + + // Make robots + if ra < maximum_ore { + let [ore, _, _] = find_cost(costs, 0); + while ia >= ore { + ia -= ore; + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (ia + ra, ib + rb, ic + rc, id + rd), + (ra + 1, rb, rc, rd), + min + 1, + ), + ); + } + ia = oia; + built_a_robot = true; + } + + if !built_a_robot { + // Increase resource without doing any thing else + answer = std::cmp::max( + answer, + solve( + memo, + costs, + (ia + ra, ib + rb, ic + rc, id + rd), + (ra, rb, rc, rd), + min + 1, + ), + ); + } + } + + memo.insert((m, (ia, ib, ic, id), (ra, rb, rc, rd)), answer); + + answer +} + +#[inline] +const fn find_cost(costs: &[usize], i: usize) -> [usize; 3] { + match i { + 0 => [costs[1], 0, 0], + 1 => [costs[2], 0, 0], + 2 => [costs[3], costs[4], 0], + 3 => [costs[5], 0, costs[6]], + _ => unreachable!(), + } +} + +fn main() { + for input in INPUTS.iter() { + let output = parse(input); + let score = solution(output); + println!("{}", score); + } +} +#[bench] +fn solution_bench(b: &mut test::Bencher) { + b.iter(|| { + let input = parse(INPUTS[1]); + let result = solution(input); + test::black_box(result); + }) +} diff --git a/src/day19/input.txt b/src/day19/input.txt new file mode 100644 index 0000000..7d276bf --- /dev/null +++ b/src/day19/input.txt @@ -0,0 +1,30 @@ +Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 4 ore and 9 obsidian. +Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 17 clay. Each geode robot costs 2 ore and 10 obsidian. +Blueprint 3: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 4 ore and 13 obsidian. +Blueprint 4: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 4 ore and 8 obsidian. +Blueprint 5: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 5 clay. Each geode robot costs 2 ore and 10 obsidian. +Blueprint 6: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 8 clay. Each geode robot costs 3 ore and 19 obsidian. +Blueprint 7: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 8 clay. Each geode robot costs 4 ore and 14 obsidian. +Blueprint 8: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 6 clay. Each geode robot costs 2 ore and 14 obsidian. +Blueprint 9: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 6 clay. Each geode robot costs 2 ore and 16 obsidian. +Blueprint 10: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 19 clay. Each geode robot costs 2 ore and 18 obsidian. +Blueprint 11: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 14 clay. Each geode robot costs 4 ore and 10 obsidian. +Blueprint 12: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 3 ore and 15 obsidian. +Blueprint 13: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 13 clay. Each geode robot costs 3 ore and 7 obsidian. +Blueprint 14: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 16 clay. Each geode robot costs 4 ore and 17 obsidian. +Blueprint 15: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 15 clay. Each geode robot costs 3 ore and 20 obsidian. +Blueprint 16: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 18 clay. Each geode robot costs 4 ore and 20 obsidian. +Blueprint 17: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 2 ore and 11 obsidian. +Blueprint 18: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 14 clay. Each geode robot costs 3 ore and 14 obsidian. +Blueprint 19: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 2 ore and 7 obsidian. +Blueprint 20: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 19 clay. Each geode robot costs 3 ore and 10 obsidian. +Blueprint 21: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 7 clay. Each geode robot costs 2 ore and 19 obsidian. +Blueprint 22: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 18 clay. Each geode robot costs 2 ore and 19 obsidian. +Blueprint 23: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 2 ore and 15 obsidian. +Blueprint 24: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 13 clay. Each geode robot costs 3 ore and 11 obsidian. +Blueprint 25: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 2 ore and 12 obsidian. +Blueprint 26: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 3 ore and 15 obsidian. +Blueprint 27: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 3 ore and 13 obsidian. +Blueprint 28: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 17 clay. Each geode robot costs 2 ore and 13 obsidian. +Blueprint 29: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 4 ore and 9 obsidian. +Blueprint 30: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 6 clay. Each geode robot costs 3 ore and 16 obsidian. diff --git a/src/day19/sample.txt b/src/day19/sample.txt new file mode 100644 index 0000000..f39c094 --- /dev/null +++ b/src/day19/sample.txt @@ -0,0 +1,2 @@ +Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian. +Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian.