Advertisement
Guest User

Untitled

a guest
Dec 14th, 2019
206
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.40 KB | None | 0 0
  1. from collections import defaultdict
  2. import sys
  3. from typing import Dict, NewType, List, Union
  4.  
  5. Reactions = NewType("Reactions", Dict[str, Dict[str, Union[int, Dict[str, int]]]])
  6.  
  7. def parse_input(puzzle_input: str) -> Reactions:
  8.     reactions = {}
  9.     for line in puzzle_input.split("\n"):
  10.         split_line = line.split("=>")
  11.        
  12.         output_chem = split_line[1].strip().split(" ")[1]
  13.         output_count = int(split_line[1].strip().split(" ")[0])
  14.         reactions[output_chem] = {"count": output_count}
  15.  
  16.         reactions[output_chem]["elements"] = {}
  17.         input_chem_counts = split_line[0].split(",")
  18.         for chem_count in input_chem_counts:
  19.             input_chem = chem_count.strip().split(" ")[1]
  20.             input_count = int(chem_count.strip().split(" ")[0])
  21.             reactions[output_chem]["elements"][input_chem] = input_count
  22.  
  23.     reactions["START"] = {"count": 1, "elements": {"FUEL": 1}}
  24.     return reactions
  25.  
  26. def reactions_from_storage(chem: str, count: int, storage, reactions: Reactions) -> (int, int):
  27.     raw_reaction_count = (count // reactions[chem]["count"])
  28.     if count % reactions[chem]["count"] != 0:
  29.         raw_reaction_count += 1
  30.     possible_reactions_from_storage = min([storage[key] // val for key, val in reactions[chem]["elements"].items()])
  31.     return raw_reaction_count, min(raw_reaction_count, possible_reactions_from_storage) # how many reactions do i need and how many can i do from storage
  32.  
  33. def need(reactions: Reactions, storage: defaultdict) -> (Dict[str, int], defaultdict):
  34.     needed = {"START": 1}
  35.     done = False
  36.     while not done:
  37.         for need_chem in list(needed.keys()):
  38.             if need_chem == "ORE":
  39.                 continue
  40.             need_count = needed[need_chem]
  41.             reactions_needed, reactions_storage = reactions_from_storage(need_chem, need_count, storage, reactions)
  42.             produced_count = reactions[need_chem]["count"] * (reactions_needed - reactions_storage)
  43.             storage[need_chem] = storage[need_chem] + max(0, produced_count - need_count)
  44.  
  45.             for reaction_chem, reaction_count in reactions[need_chem]["elements"].items():
  46.                 # Do reactions from storage
  47.                 current_storage = storage[reaction_chem]
  48.                 storage[reaction_chem] = current_storage - (reactions_storage * reaction_count)
  49.                 if storage[reaction_chem] < 0:
  50.                     raise ValueError("Nope")
  51.  
  52.                 # Add new elements that aren't in storage to need list
  53.                 needed_reaction_chem_count = reaction_count * (reactions_needed - reactions_storage)
  54.                 current_needed = needed.get(reaction_chem, 0)
  55.                 needed[reaction_chem] = current_needed + max(0, needed_reaction_chem_count - storage[reaction_chem])
  56.                 storage[reaction_chem] = max(0, storage[reaction_chem] - needed_reaction_chem_count)
  57.                 if storage[reaction_chem] < 0:
  58.                     raise ValueError("Also nope")
  59.  
  60.             needed.pop(need_chem)
  61.        
  62.         if list(needed.keys()) == ["ORE"]:
  63.             done = True
  64.     return needed, storage
  65.  
  66. def solve_1(puzzle_input: str) -> int:
  67.     parsed = parse_input(puzzle_input)
  68.     storage = defaultdict(int)
  69.     return need(parsed, storage)[0]["ORE"]
  70.  
  71. def get_ore(last_chem: str, chem: str, reactions: Reactions) -> int:
  72.     if chem == "ORE":
  73.         return 1
  74.     ore = 0
  75.     for reaction_chem, reaction_val in reactions[chem]["elements"].items():
  76.         ore = ore + ((reaction_val / reactions[chem]["count"]) * get_ore(chem, reaction_chem, reactions))
  77.     return ore
  78.  
  79. def solve_2(puzzle_input: str)-> (int, int):
  80.     parsed = parse_input(puzzle_input)
  81.     print(get_ore("X", "FUEL", parsed))
  82.  
  83. def solve_not(puzzle_input: str)-> (int, int):
  84.     parsed = parse_input(puzzle_input)
  85.     storage = defaultdict(int)
  86.     total_ore = 0
  87.     fuel = 0
  88.     while True:
  89.         if fuel % 1000 == 0:
  90.             print(total_ore, fuel)
  91.         #if fuel == 5:
  92.         #    break
  93.         needed, storage = need(parsed, storage)
  94.         #print(storage)
  95.         ore_needed = needed.pop("ORE")
  96.         if total_ore + ore_needed > 1000000000000:
  97.             break
  98.         else:
  99.             total_ore += ore_needed
  100.             fuel += 1
  101.     return total_ore, fuel
  102.  
  103. if __name__ == "__main__":
  104.     puzzle_input = sys.stdin.read()
  105.     print(solve_1(puzzle_input))
  106.     print(solve_2(puzzle_input))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement