Initial conversion to NamedTuple representation

This commit is contained in:
Danny Robson 2019-07-14 13:17:28 +10:00
parent 4b2f52e7d5
commit 27743d9e6d
9 changed files with 57 additions and 25 deletions

View File

@ -3,6 +3,7 @@
"component"
],
"machine": "assembler",
"stack_size": 100,
"recipes": [
{
"input": {
@ -14,7 +15,6 @@
},
"crafting_time": 12,
"clicks": 3,
"stack_size": 100,
"requires": "caterium_electronics"
}
]

View File

@ -21,4 +21,4 @@
}
}
]
}
}

View File

@ -2,7 +2,7 @@
"type": [
"machine"
],
"is": "miner",
"alias": "miner",
"machine": "_craft_bench",
"power_usage": 5,
"size": [

View File

@ -2,7 +2,7 @@
"type": [
"machine"
],
"is": "miner",
"alias": "miner",
"machine": "_craft_bench",
"power_usage": 12,
"size": [

View File

@ -3,6 +3,7 @@
"machine"
],
"machine": "_craft_bench",
"size": [ 6, 10, 10 ],
"power_usage": 50,
"recipes": [
{
@ -12,8 +13,7 @@
},
"output": {
"smelter": 1
},
"size": [ 6, 10, 10 ]
}
}
]
}

View File

@ -3,6 +3,7 @@
"machine"
],
"machine": "_craft_bench",
"size": [ 6, 10, 10 ],
"power_usage": 4,
"recipes": [
{
@ -12,8 +13,7 @@
},
"output": {
"smelter": 1
},
"size": [ 6, 10, 10 ]
}
}
]
}

View File

@ -16,7 +16,7 @@ def graph(cookbook: satisfactory.Cookbook, targets: Iterable[str]):
while remain:
output = remain.pop()
for need in cookbook.recipes(output)[0]['input']:
for need in cookbook.recipes(output)[0].input:
print(f"{need} -> {output}")
if need not in seen:
remain.add(need)

View File

@ -15,9 +15,9 @@ def basic_rate(recipe: Dict) -> Fraction:
:param recipe:
:return:
"""
for output, count in recipe['output'].items():
for output, count in recipe.output.items():
return Fraction(
count, recipe['crafting_time']
count, recipe.crafting_time
)
@ -48,17 +48,17 @@ def required_rates(
continue
# Assume we're using the default recipe
dst_recipe = recipes[dst_name]['recipes'][0]
dst_recipe = recipes[dst_name].recipes[0]
# Calculate the fraction of the base rate we need to satisfy, and
# append our (scaled) inputs to the request queue.
normal_rate = basic_rate(dst_recipe)
scale = dst_rate / normal_rate
for src_name, src_count in dst_recipe['input'].items():
for src_name, src_count in dst_recipe.input.items():
src_rate = Fraction(
src_count,
dst_recipe['crafting_time']
dst_recipe.crafting_time
) * scale
remain.append({src_name: src_rate})
@ -90,11 +90,11 @@ def required_machines(recipes: satisfactory.Cookbook, rates: Dict[str, Fraction]
descriptor = recipes[name]
normal_rate = Fraction(
descriptor['recipes'][0]['output'][name],
descriptor['recipes'][0]['crafting_time']
descriptor.recipes[0].output[name],
descriptor.recipes[0].crafting_time
)
machine = descriptor['machine']
machine = descriptor.machine
required_machines[machine][name] += requested_rate / normal_rate
return required_machines
@ -115,7 +115,8 @@ def required_power(recipes: satisfactory.Cookbook, machines: Dict[str, int]) ->
for machine, buckets in machines.items():
for result, rate in buckets.items():
count = int(math.ceil(rate))
total += count * recipes[machine]['power_usage']
source = recipes[machine]
total += count * source.power_usage
print(machine, result, math.ceil(rate))
return total
@ -164,7 +165,7 @@ def main():
# Create an initial name:rate request for all of the target items, then
# create a plan for their creation.
request = [{n: basic_rate(recipes[n]['recipes'][0]) for n in args.item}]
request = [{n: basic_rate(recipes[n].recipes[0]) for n in args.item}]
plan(recipes, request)

View File

@ -1,11 +1,34 @@
import os
import json
import logging
from typing import Dict, Generator, Iterable
from typing import Dict, Generator, Iterable, NamedTuple, Set, List, Optional
class Recipe(NamedTuple):
input: Dict[str, int]
output: Dict[str, int]
crafting_time: Optional[int] = None
clicks: Optional[int] = None
stage: Optional[str] = None
requires: Optional[str] = None
class Item(NamedTuple):
type: Set[str]
machine: str
recipes: List[Recipe]
alias: Optional[str] = None
stack_size: Optional[int] = None
power_usage: Optional[int] = None
size: Optional[List[int]] = None
requires: Optional[str] = None
class Cookbook(object):
__recipes: Dict[str, Dict]
__recipes: Dict[str, Item]
def __init__(self, root: str):
self.__recipes = dict()
@ -14,8 +37,16 @@ class Cookbook(object):
for f in files:
path = os.path.join(dirname, f)
name, _ = os.path.splitext(f)
with open(path, 'r') as src:
self.__recipes[name] = json.load(src)
j = json.load(src)
try:
recipes = list(Recipe(**r) for r in j['recipes'])
j['recipes'] = recipes
self.__recipes[name] = Item(**j)
except Exception as ex:
logging.error(f"Could not load {name}: {ex}")
def __getitem__(self, item: str) -> Dict[str, Dict]:
return self.__recipes[item]
@ -31,14 +62,14 @@ class Cookbook(object):
:param name: The target item name
:return: A sequence of possible recipes for the target item
"""
return self.__recipes[name]['recipes']
return self.__recipes[name].recipes
def is_component(self, name: str) -> bool:
"""
:param name: The name of an item
:return: Whether the item is a component; ie, craftable.
"""
return 'component' in self.__recipes[name]['type']
return 'component' in self.__recipes[name].type
def components(self) -> Generator[str, None, None]:
"""
@ -51,7 +82,7 @@ class Cookbook(object):
:param name: The name of an item
:return: Whether the item must have harvested (rather than crafted)
"""
return 'resource' in self.__recipes[name]['type']
return 'resource' in self.__recipes[name].type
def resources(self) -> Generator[str, None, None]:
"""