Add solution for day 14 part 1

master
Nick Krichevsky 2019-12-14 18:55:05 -05:00
parent 9bc4cfb8ec
commit da0078e201
6 changed files with 224 additions and 0 deletions

60
day14/input.txt Normal file
View File

@ -0,0 +1,60 @@
11 BNMWF, 1 MRVFT, 10 PBNSF => 7 XSFVQ
149 ORE => 4 SMSB
1 XHQDX, 1 SVSTJ, 2 LDHX => 7 JMWQG
12 MJCLX => 9 PBNSF
132 ORE => 7 XPTXL
15 TZMWG, 1 LDHX, 1 PDVR => 7 LBQB
1 HJTD, 8 VFXHC => 2 SVSTJ
5 LBHQ, 6 MTQCB => 4 MHBZ
1 PRXT, 1 FWZN => 2 PBMPL
1 XPTXL => 1 HMRGM
10 XHPHR => 6 NSVJL
3 QZQLZ, 3 MTQCB => 4 TZMWG
5 LBHQ, 2 VPSDV => 3 ZFCD
13 WPFP => 6 ZXMGK
10 MHJMX, 75 LDHX, 52 JMWQG, 4 QWRB, 1 SVNVJ, 17 BNMWF, 18 GHVN => 1 FUEL
4 PFQRG, 14 XVNL => 5 PDCV
11 JMWQG, 10 ZBNCP => 6 NTJZH
14 PBMPL, 12 PRXT, 9 MJQS => 9 XVNL
9 GDNG, 13 LBQB => 9 QWRB
1 CXNM => 6 PFQRG
9 NTJZH, 7 BNMWF, 11 JCHP, 1 MHBZ, 1 SVSTJ, 9 XRDN => 5 SVNVJ
1 XHPHR, 1 GSMP => 4 THRVR
26 FWZN => 4 WPFP
35 VJTFJ, 2 XSFVQ, 6 HJVN, 1 NSVJL, 1 JCHP, 3 MJCLX, 1 QZNCK => 6 GHVN
1 WPFP, 3 XHPHR => 2 HJVN
5 SMSB => 7 HNCDS
111 ORE => 4 GSMP
6 LBHQ => 8 GDNG
2 GDNG, 5 MHBZ => 1 RNMKC
15 THRVR, 4 NWNSH, 1 NSVJL => 7 FDVH
2 HMRGM => 9 FWZN
6 MJQS, 5 JRZXM => 5 NWNSH
14 ZXMGK, 1 JTXWX => 6 DLWT
1 MJQS, 3 FWZN, 2 PRXT => 1 JTXWX
1 GSMP, 4 CXNM => 3 JRZXM
151 ORE => 9 ZNPRL
2 NTJZH, 1 DLWT, 3 ZBNCP => 9 MRVFT
14 SWZCB, 1 VPSDV => 7 XRDN
14 LBHQ, 16 FDVH, 9 PFQRG => 4 PRXT
22 CXNM => 9 HJTD
1 VFXHC, 1 MTQCB => 6 QZQLZ
6 SWZCB, 2 PDCV, 17 RNMKC => 9 LTHFW
4 ZNPRL => 6 CXNM
2 CXNM => 3 LBHQ
8 MHBZ, 2 QZQLZ, 2 LBQB => 3 VJTFJ
3 ZFCD => 1 XHQDX
1 VJTFJ, 7 MHBZ => 8 ZBNCP
5 CXNM => 2 VPSDV
7 MJQS => 9 VFXHC
2 LTHFW, 11 HJVN, 4 XRDN, 8 MRVFT, 3 NSVJL, 3 SVSTJ, 5 XSFVQ, 13 RNMKC => 8 MHJMX
2 HMRGM => 3 XHPHR
1 GDNG, 19 PDVR => 3 SWZCB
18 HMRGM, 10 HNCDS => 2 MJQS
6 HNCDS, 2 HMRGM, 1 LBHQ => 3 MTQCB
16 VJTFJ, 1 WPFP, 6 JMWQG => 6 BNMWF
3 TZMWG, 1 FWZN => 7 PDVR
10 ZXMGK => 4 QZNCK
32 LBQB, 1 ZBNCP => 1 JCHP
27 PDVR, 7 QZQLZ, 7 PBMPL => 3 MJCLX
5 MHBZ, 12 ZFCD => 4 LDHX

120
day14/py/main.py Normal file
View File

@ -0,0 +1,120 @@
import sys
import math
from dataclasses import dataclass
from typing import Dict, List, Tuple
# Element is a node in a graph used to represent the dependencies amongst reactions (not the quantities themselves)
class Element:
FUEL_ELEMENT = 'FUEL'
ORE_ELEMENT = 'ORE'
def __init__(self, name: str):
self.name = name
self.possible_inputs = set()
self.possible_outputs = set()
def __repr__(self) -> str:
return f'<Element: {self.name}>'
@dataclass
class Reaction:
# We can have many inputs
inputs: Dict[Element, int]
# We only have one output
output: Tuple[Element, int]
@classmethod
def from_input_str(cls, s: str):
REACTION_DELIM = ' => '
INPUT_DELIM = ', '
ELEMENT_DELIM = ' '
raw_inputs, raw_output = s.split(REACTION_DELIM)
split_output = raw_output.split(ELEMENT_DELIM)
output = (Element(split_output[1]), int(split_output[0]))
inputs = {}
for raw_input in raw_inputs.split(INPUT_DELIM):
split_input = raw_input.split(ELEMENT_DELIM)
inputs[Element(split_input[1])] = int(split_input[0])
return cls(inputs, output)
def __repr__(self) -> str:
inputs = ', '.join(f'{count} {element.name}' for element, count in self.inputs.items())
return inputs + f' => {self.output[1]} {self.output[0].name}'
# Parses all of the output, returns a list of all of the reactions and the FUEL element
def parse_reaction_list(input_lines: str) -> Tuple[List[Reaction], Element]:
elements = {Element.ORE_ELEMENT: Element(Element.ORE_ELEMENT)}
reactions = [Reaction.from_input_str(line) for line in input_lines]
for reaction in reactions:
output_element = reaction.output[0]
elements[output_element.name] = output_element
# Once we add all reactions, add neighbors for the elements
for reaction in reactions:
output_element = elements[reaction.output[0].name]
reaction_inputs = reaction.inputs.copy()
for reaction_input_element, quantity in reaction_inputs.items():
input_element = elements[reaction_input_element.name]
# Noramlize the elemnts in the reaction list to all point to the same instance of that element.
del reaction.inputs[reaction_input_element]
reaction.inputs[input_element] = quantity
output_element.possible_inputs.add(input_element)
input_element.possible_outputs.add(output_element)
return reactions, elements[Element.FUEL_ELEMENT]
def part1(reactions: List[Reaction], fuel_element: Element) -> int:
surplus_elements = {}
# Counts how many times a reaction with index i is run
reaction_counts = {}
# Maps a reaction's output to its reaction
reaction_map = {reaction.output[0].name: (i, reaction) for i, reaction in enumerate(reactions)}
def generate_reaction_counts(element: Element, num_required: int):
if element.name == Element.ORE_ELEMENT:
return
num_surplus = surplus_elements.get(element.name, 0)
i, reaction = reaction_map[element.name]
num_missing = num_required - num_surplus
# If we already have enough elements, we're done.
if num_missing <= 0:
# Store how many our new suplus is
surplus_elements[element.name] = num_surplus - num_required
return
reactions_required = int(math.ceil(num_missing / reaction.output[1]))
surplus_elements[element.name] = (num_surplus - num_required) + reactions_required * reaction.output[1]
reaction_count = reaction_counts.get(i, 0)
reaction_counts[i] = reaction_count + reactions_required
for input_element, count in reaction.inputs.items():
generate_reaction_counts(input_element, count * reactions_required)
# Run our recursive algorithm to calculate how many reactions are required
generate_reaction_counts(fuel_element, 1)
num_ore_required = 0
for i, count in reaction_counts.items():
for input_element, reaction_input_count in reactions[i].inputs.items():
if input_element.name == Element.ORE_ELEMENT:
num_ore_required += count * reaction_input_count
return num_ore_required
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: ./main.py in_file")
sys.exit(1)
with open(sys.argv[1]) as f:
lines = f.read().rstrip('\n').split('\n')
reactions, fuel_element = parse_reaction_list(lines)
print(part1(reactions, fuel_element))

6
day14/sample1.txt Normal file
View File

@ -0,0 +1,6 @@
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

9
day14/sample2.txt Normal file
View File

@ -0,0 +1,9 @@
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

12
day14/sample3.txt Normal file
View File

@ -0,0 +1,12 @@
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

17
day14/sample4.txt Normal file
View File

@ -0,0 +1,17 @@
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