Initial conversion to NamedTuple representation
This commit is contained in:
parent
4b2f52e7d5
commit
27743d9e6d
@ -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"
|
||||
}
|
||||
]
|
||||
|
@ -21,4 +21,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
"type": [
|
||||
"machine"
|
||||
],
|
||||
"is": "miner",
|
||||
"alias": "miner",
|
||||
"machine": "_craft_bench",
|
||||
"power_usage": 5,
|
||||
"size": [
|
||||
|
@ -2,7 +2,7 @@
|
||||
"type": [
|
||||
"machine"
|
||||
],
|
||||
"is": "miner",
|
||||
"alias": "miner",
|
||||
"machine": "_craft_bench",
|
||||
"power_usage": 12,
|
||||
"size": [
|
||||
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
2
graph.py
2
graph.py
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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]:
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user