diff --git a/Cargo.toml b/Cargo.toml index c440e63..c59f6f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" authors = ["Stefan Schwarz "] edition = "2018" - -[profile.release] -debug = true - [[bin]] name = "day1" path = "src/day1/main.rs" @@ -47,7 +43,3 @@ path = "src/day11/main.rs" [[bin]] name = "day12" path = "src/day12/main.rs" - -[[bin]] -name = "day14" -path = "src/day14/main.rs" diff --git a/input14 b/input14 deleted file mode 100644 index ea6fb95..0000000 --- a/input14 +++ /dev/null @@ -1,56 +0,0 @@ -18 FHWM => 1 XGQNZ -4 FVPWN, 9 CQGW => 7 QGHT -22 KZMS, 1 DMCJL => 8 TWGCK -1 LMGQN, 1 DSWDM, 1 GKGZ => 1 TGPH -22 WCSW => 1 LVTG -13 JSWR => 4 GKGZ -162 ORE => 3 FVPWN -59 CQGW, 15 MSNG, 6 XGKRF, 10 LJRQ, 1 HRKGV, 15 RKVC => 1 FUEL -5 DMCJL => 1 QBLH -2 XDRJ, 2 RKVC => 8 CTCNL -1 QXHX => 5 GFPSK -22 QGHT, 6 GFPSK, 5 DHTPL => 3 CSDR -4 QGHT, 2 HFXD => 4 XDRJ -10 WQCGV, 1 JSWR, 21 RHTLN => 7 VTPC -11 CQGW, 1 FVPWN => 3 HFXD -5 VTPC => 2 NCXW -8 LDZVS => 6 DQLH -117 ORE => 2 KWZNB -3 TGPH, 1 JPFQ, 2 WHWLK, 5 RKVC, 16 DQLH => 9 LJRQ -14 KWZNB, 2 CQGW => 8 MLPK -6 LDZVS => 2 JSWR -1 RKVC, 8 HCGT, 9 DHTPL => 6 FHWM -3 DHTPL, 1 HWSR, 36 LDZVS => 6 DSWDM -5 WHWLK, 1 LJHWT, 8 HSTHS => 7 VMPX -22 ZJCDZ, 3 WQCGV => 5 DHTPL -10 LJHWT, 32 GFPSK, 2 RHTLN => 4 HFRMP -2 FKVD, 3 TWGCK, 1 HWSR => 1 RNLZW -2 CSDR, 3 DQLH, 2 HSTHS => 9 JPFQ -1 JSWR, 1 PCWS, 1 HFRMP => 3 XGKRF -2 QGHT, 9 LVTG, 3 QBLH => 7 RHTLN -10 LJHWT, 4 CTCNL => 8 QXHX -16 MLPK, 1 HFXD => 9 ZJCDZ -6 QGHT => 9 WCSW -4 HWSR, 4 MLPK, 1 KZMS => 3 BGZHQ -12 MLPK => 8 RKVC -1 HWSR, 1 VNWFS => 7 BGFJ -7 FHWM, 11 CTDF, 1 LDZVS => 2 VNWFS -4 CTDF => 4 HSTHS -2 ZJCDZ => 6 LJHWT -1 VMPX, 1 NCXW, 1 HSTHS, 41 XGKRF, 30 HLNG, 1 GKGZ => 7 HRKGV -1 XGQNZ, 10 PCWS, 3 BGFJ => 8 FKVD -1 GFPSK, 1 DMCJL, 1 LVTG => 5 XDTZB -3 WCSW => 5 KZMS -6 TWGCK, 1 QXHX, 4 BGFJ => 2 LMGQN -1 WCSW => 7 LDZVS -1 XDTZB, 9 VNWFS => 3 WHWLK -3 HFXD, 4 WCSW, 1 MLPK => 5 WQCGV -2 BGFJ, 1 HSTHS, 22 MDCB, 10 HWSR, 6 RNLZW, 8 GKGZ => 5 MSNG -4 QGHT, 1 FKVD => 7 MDCB -9 MLPK, 3 LJHWT => 7 DMCJL -121 ORE => 2 CQGW -9 DHTPL, 2 BGZHQ => 8 CTDF -2 JSWR, 30 RHTLN => 7 HLNG -2 QBLH => 7 PCWS -14 LVTG => 8 HWSR -7 DMCJL => 1 HCGT diff --git a/src/day14/main.rs b/src/day14/main.rs deleted file mode 100644 index b36d8be..0000000 --- a/src/day14/main.rs +++ /dev/null @@ -1,385 +0,0 @@ -use std::cmp::Ordering; -use std::collections::HashMap; -use std::convert::*; -use std::fs::File; -use std::io::{BufRead, BufReader}; - -type Resource = String; -type Pipeline = HashMap; - -#[derive(Debug)] -struct ResourceBuilder { - requirements: Vec, - out_count: usize, -} - -impl From<(Vec, usize)> for ResourceBuilder { - fn from(build: (Vec, usize)) -> Self { - ResourceBuilder { - requirements: build.0, - out_count: build.1, - } - } -} - -#[derive(Default, Debug)] -struct NanoFactory { - pipeline: Pipeline, - ordered: Vec, -} - -#[derive(Debug)] -enum NanoFactoryBuildState { - InputCount, - InputResource, - OutputArrow, - OutputCount, - OutputResource, -} - -impl NanoFactory { - /// sort resources - fn resolve_order(&mut self) { - self.ordered = vec![Resource::from("ORE")]; - let mut sortable: HashMap> = self - .pipeline - .iter() - .map(|(k, v)| (k.clone(), v.requirements.clone())) - .collect(); - while sortable.len() > 0 { - sortable = sortable - .into_iter() - .filter_map(|(k, v)| { - if v.iter().all(|i| self.ordered.contains(i)) { - self.ordered.push(k); - None - } else { - Some((k, v)) - } - }) - .collect(); - } - self.ordered.reverse(); - self.ordered.retain(|res| res != "ORE"); - } - - /// calculate how much ores are required for required_fuel - fn resource_usage(&self, required_fuel: u128) -> usize { - // create storage to track leftover resources - let mut storage: HashMap = HashMap::new(); - storage.insert(Resource::from("FUEL"), required_fuel); - - // calculate resource costs - self.ordered.iter().for_each(|res| { - let rb = self.pipeline.get(res).unwrap(); - let count = (storage.get(res).unwrap().clone() + (rb.out_count as u128) - 1) - / (rb.out_count as u128); - rb.requirements.iter().for_each(|req| { - storage - .entry(req.clone()) - .and_modify(|v| *v += count) - .or_insert(count); - storage.insert(res.clone(), 0); - }) - }); - - // return cost for ore - println!("{:?}", storage); - *storage.get("ORE").unwrap() as usize - } - - /// generate a single fuel - fn generate_fuel(&self) -> usize { - let mut storage: HashMap = HashMap::new(); - self.lookup_resource(&mut storage, "FUEL") - } - - /// recursively calculate the cost of a resource in ores - fn lookup_resource(&self, storage: &mut HashMap, resource: &str) -> usize { - if resource == "ORE" { - return 1; - } - - // use from storage - if let Some(count) = storage.get_mut(resource) { - if *count > 0 { - *count -= 1; - return 0; - } - } - - // initialize storage with zero - if storage.get(resource).is_none() { - storage.insert(resource.into(), 0); - } - - // build resource and and to storage - let required = self - .pipeline - .get(resource) - .expect("unable to find resource"); - let cost = required.requirements.iter().fold(0, |mut acc, c| { - acc += self.lookup_resource(storage, c); - acc - }); - - // update storage - let stored = storage.get_mut(resource).unwrap(); - *stored += required.out_count - 1; - - cost - } -} - -impl From for NanoFactory -where - T: BufRead, -{ - fn from(bufreader: T) -> Self { - let mut f = NanoFactory::default(); - let mut state = NanoFactoryBuildState::InputCount; - bufreader.split(b'\n').enumerate().for_each(|(nr, line)| { - let line = line.unwrap(); - let mut line = line.into_iter().peekable(); - let mut count_var = 0; - let mut cur_requirements = Vec::new(); - loop { - match state { - // numeric input - NanoFactoryBuildState::InputCount | NanoFactoryBuildState::OutputCount => { - while let Some(c) = next_if_in_range(&mut line, 48..=57) { - count_var = count_var * 10 + (c as usize) - 48; - } - assert_eq!(line.next().unwrap(), b' '); - state = match state { - NanoFactoryBuildState::InputCount => { - NanoFactoryBuildState::InputResource - } - NanoFactoryBuildState::OutputCount => { - NanoFactoryBuildState::OutputResource - } - _ => unreachable!(), - } - } - // input resouce name - NanoFactoryBuildState::InputResource => { - let mut r = Resource::new(); - while let Some(c) = next_if_in_range(&mut line, 65..=90) { - r.push(c.into()); - } - for _ in 0..count_var { - cur_requirements.push(r.clone()); - } - r.truncate(0); - count_var = 0; - let next = line.next(); - match next { - Some(b',') => { - assert_eq!(line.next().unwrap(), b' '); - state = NanoFactoryBuildState::InputCount; - } - Some(b' ') => state = NanoFactoryBuildState::OutputArrow, - _ => panic!( - "invalid format in line {}, expected ' ' or ',', got '{:?}'", - nr, next - ), - } - } - // output resource name - NanoFactoryBuildState::OutputResource => { - let mut r = Resource::new(); - while let Some(c) = next_if_in_range(&mut line, 65..=90) { - r.push(c.into()); - } - f.pipeline - .insert(r, ResourceBuilder::from((cur_requirements, count_var))); - state = NanoFactoryBuildState::InputCount; - return; - } - // arrow between input and output ' => ' - NanoFactoryBuildState::OutputArrow => { - assert_eq!(line.next().unwrap(), b'='); - assert_eq!(line.next().unwrap(), b'>'); - assert_eq!(line.next().unwrap(), b' '); - state = NanoFactoryBuildState::OutputCount - } - }; - } - }); - f - } -} - -fn next_if_in_range( - peekable: &mut std::iter::Peekable, - range: std::ops::RangeInclusive, -) -> Option -where - I: std::iter::Iterator, - T: Copy + std::cmp::PartialOrd, -{ - if let Some(peeked) = peekable.peek() { - if range.contains(peeked) { - peekable.next() - } else { - None - } - } else { - None - } -} - -fn main() { - let f = File::open("input14").unwrap(); - let bufreader = BufReader::new(f); - let mut factory = NanoFactory::from(bufreader); - - // part1 - println!("ores: {}", factory.generate_fuel()); - - // part2 as binary search - factory.resolve_order(); - let mut min = 1; - let mut max = 1_000_000_000_000; - let mut fuel; - loop { - fuel = (min + max) / 2; - let ore = factory.resource_usage(fuel); - match 1_000_000_000_000.cmp(&ore) { - Ordering::Less => max = fuel - 1, - Ordering::Greater => { - min = fuel + 1; - if min > max { - break; - } - } - Ordering::Equal => { - break; - } - }; - } - println!("ammount: {}", fuel); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn example1() { - let bufreader = BufReader::new( - "10 ORE => 10 A -1 ORE => 1 B -7 A, 1 B => 1 C -7 A, 1 C => 1 D -7 A, 1 D => 1 E -7 A, 1 E => 1 FUEL -" - .trim() - .as_bytes(), - ); - let mut factory = NanoFactory::from(bufreader); - factory.resolve_order(); - assert_eq!(factory.generate_fuel(), 31); - assert_eq!(factory.resource_usage(1), 31); - } - - #[test] - fn example2() { - let bufreader = BufReader::new( - " -9 ORE => 2 A -8 ORE => 3 B -7 ORE => 5 C -3 A, 4 B => 1 AB -5 B, 7 C => 1 BC -4 C, 1 A => 1 CA -2 AB, 3 BC, 4 CA => 1 FUEL -" - .trim() - .as_bytes(), - ); - let mut factory = NanoFactory::from(bufreader); - factory.resolve_order(); - assert_eq!(factory.generate_fuel(), 165); - assert_eq!(factory.resource_usage(1), 165); - } - - #[test] - fn example3() { - let bufreader = BufReader::new( - " -157 ORE => 5 NZVS -165 ORE => 6 DCFZ -44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL -12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ -179 ORE => 7 PSHF -177 ORE => 5 HKGWZ -7 DCFZ, 7 PSHF => 2 XJWVT -165 ORE => 2 GPVTF -3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT -" - .trim() - .as_bytes(), - ); - let factory = NanoFactory::from(bufreader); - assert_eq!(factory.generate_fuel(), 13312); - } - - #[test] - fn example4() { - let bufreader = BufReader::new( - " -2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG -17 NVRVD, 3 JNWZP => 8 VPVL -53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL -22 VJHF, 37 MNCFX => 5 FWMGM -139 ORE => 4 NVRVD -144 ORE => 7 JNWZP -5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC -5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV -145 ORE => 6 MNCFX -1 NVRVD => 8 CXFTF -1 VJHF, 6 MNCFX => 4 RFSQX -176 ORE => 6 VJHF -" - .trim() - .as_bytes(), - ); - let mut factory = NanoFactory::from(bufreader); - factory.resolve_order(); - assert_eq!(factory.generate_fuel(), 180697); - assert_eq!(factory.resource_usage(1), 180697); - } - - #[test] - fn example5() { - let bufreader = BufReader::new( - " -171 ORE => 8 CNZTR -7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL -114 ORE => 4 BHXH -14 VRPVC => 6 BMBT -6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL -6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT -15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW -13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW -5 BMBT => 4 WPTQ -189 ORE => 9 KTJDG -1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP -12 VRPVC, 27 CNZTR => 2 XDBXC -15 KTJDG, 12 BHXH => 5 XCVML -3 BHXH, 2 VRPVC => 7 MZWV -121 ORE => 7 VRPVC -7 XCVML => 6 RJRHP -5 BHXH, 4 VRPVC => 5 LTCX -" - .trim() - .as_bytes(), - ); - let mut factory = NanoFactory::from(bufreader); - factory.resolve_order(); - assert_eq!(factory.generate_fuel(), 2210736); - assert_eq!(factory.resource_usage(1), 2210736); - } -}