Initial conversion to NamedTuple representation
This commit is contained in:
parent
4b2f52e7d5
commit
27743d9e6d
@ -3,6 +3,7 @@
|
|||||||
"component"
|
"component"
|
||||||
],
|
],
|
||||||
"machine": "assembler",
|
"machine": "assembler",
|
||||||
|
"stack_size": 100,
|
||||||
"recipes": [
|
"recipes": [
|
||||||
{
|
{
|
||||||
"input": {
|
"input": {
|
||||||
@ -14,7 +15,6 @@
|
|||||||
},
|
},
|
||||||
"crafting_time": 12,
|
"crafting_time": 12,
|
||||||
"clicks": 3,
|
"clicks": 3,
|
||||||
"stack_size": 100,
|
|
||||||
"requires": "caterium_electronics"
|
"requires": "caterium_electronics"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -21,4 +21,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -2,7 +2,7 @@
|
|||||||
"type": [
|
"type": [
|
||||||
"machine"
|
"machine"
|
||||||
],
|
],
|
||||||
"is": "miner",
|
"alias": "miner",
|
||||||
"machine": "_craft_bench",
|
"machine": "_craft_bench",
|
||||||
"power_usage": 5,
|
"power_usage": 5,
|
||||||
"size": [
|
"size": [
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"type": [
|
"type": [
|
||||||
"machine"
|
"machine"
|
||||||
],
|
],
|
||||||
"is": "miner",
|
"alias": "miner",
|
||||||
"machine": "_craft_bench",
|
"machine": "_craft_bench",
|
||||||
"power_usage": 12,
|
"power_usage": 12,
|
||||||
"size": [
|
"size": [
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"machine"
|
"machine"
|
||||||
],
|
],
|
||||||
"machine": "_craft_bench",
|
"machine": "_craft_bench",
|
||||||
|
"size": [ 6, 10, 10 ],
|
||||||
"power_usage": 50,
|
"power_usage": 50,
|
||||||
"recipes": [
|
"recipes": [
|
||||||
{
|
{
|
||||||
@ -12,8 +13,7 @@
|
|||||||
},
|
},
|
||||||
"output": {
|
"output": {
|
||||||
"smelter": 1
|
"smelter": 1
|
||||||
},
|
}
|
||||||
"size": [ 6, 10, 10 ]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"machine"
|
"machine"
|
||||||
],
|
],
|
||||||
"machine": "_craft_bench",
|
"machine": "_craft_bench",
|
||||||
|
"size": [ 6, 10, 10 ],
|
||||||
"power_usage": 4,
|
"power_usage": 4,
|
||||||
"recipes": [
|
"recipes": [
|
||||||
{
|
{
|
||||||
@ -12,8 +13,7 @@
|
|||||||
},
|
},
|
||||||
"output": {
|
"output": {
|
||||||
"smelter": 1
|
"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:
|
while remain:
|
||||||
output = remain.pop()
|
output = remain.pop()
|
||||||
|
|
||||||
for need in cookbook.recipes(output)[0]['input']:
|
for need in cookbook.recipes(output)[0].input:
|
||||||
print(f"{need} -> {output}")
|
print(f"{need} -> {output}")
|
||||||
if need not in seen:
|
if need not in seen:
|
||||||
remain.add(need)
|
remain.add(need)
|
||||||
|
@ -15,9 +15,9 @@ def basic_rate(recipe: Dict) -> Fraction:
|
|||||||
:param recipe:
|
:param recipe:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
for output, count in recipe['output'].items():
|
for output, count in recipe.output.items():
|
||||||
return Fraction(
|
return Fraction(
|
||||||
count, recipe['crafting_time']
|
count, recipe.crafting_time
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -48,17 +48,17 @@ def required_rates(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Assume we're using the default recipe
|
# 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
|
# Calculate the fraction of the base rate we need to satisfy, and
|
||||||
# append our (scaled) inputs to the request queue.
|
# append our (scaled) inputs to the request queue.
|
||||||
normal_rate = basic_rate(dst_recipe)
|
normal_rate = basic_rate(dst_recipe)
|
||||||
scale = dst_rate / normal_rate
|
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_rate = Fraction(
|
||||||
src_count,
|
src_count,
|
||||||
dst_recipe['crafting_time']
|
dst_recipe.crafting_time
|
||||||
) * scale
|
) * scale
|
||||||
remain.append({src_name: src_rate})
|
remain.append({src_name: src_rate})
|
||||||
|
|
||||||
@ -90,11 +90,11 @@ def required_machines(recipes: satisfactory.Cookbook, rates: Dict[str, Fraction]
|
|||||||
descriptor = recipes[name]
|
descriptor = recipes[name]
|
||||||
|
|
||||||
normal_rate = Fraction(
|
normal_rate = Fraction(
|
||||||
descriptor['recipes'][0]['output'][name],
|
descriptor.recipes[0].output[name],
|
||||||
descriptor['recipes'][0]['crafting_time']
|
descriptor.recipes[0].crafting_time
|
||||||
)
|
)
|
||||||
|
|
||||||
machine = descriptor['machine']
|
machine = descriptor.machine
|
||||||
required_machines[machine][name] += requested_rate / normal_rate
|
required_machines[machine][name] += requested_rate / normal_rate
|
||||||
|
|
||||||
return required_machines
|
return required_machines
|
||||||
@ -115,7 +115,8 @@ def required_power(recipes: satisfactory.Cookbook, machines: Dict[str, int]) ->
|
|||||||
for machine, buckets in machines.items():
|
for machine, buckets in machines.items():
|
||||||
for result, rate in buckets.items():
|
for result, rate in buckets.items():
|
||||||
count = int(math.ceil(rate))
|
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))
|
print(machine, result, math.ceil(rate))
|
||||||
|
|
||||||
return total
|
return total
|
||||||
@ -164,7 +165,7 @@ def main():
|
|||||||
|
|
||||||
# Create an initial name:rate request for all of the target items, then
|
# Create an initial name:rate request for all of the target items, then
|
||||||
# create a plan for their creation.
|
# 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)
|
plan(recipes, request)
|
||||||
|
|
||||||
|
@ -1,11 +1,34 @@
|
|||||||
import os
|
import os
|
||||||
import json
|
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):
|
class Cookbook(object):
|
||||||
__recipes: Dict[str, Dict]
|
__recipes: Dict[str, Item]
|
||||||
|
|
||||||
def __init__(self, root: str):
|
def __init__(self, root: str):
|
||||||
self.__recipes = dict()
|
self.__recipes = dict()
|
||||||
@ -14,8 +37,16 @@ class Cookbook(object):
|
|||||||
for f in files:
|
for f in files:
|
||||||
path = os.path.join(dirname, f)
|
path = os.path.join(dirname, f)
|
||||||
name, _ = os.path.splitext(f)
|
name, _ = os.path.splitext(f)
|
||||||
|
|
||||||
with open(path, 'r') as src:
|
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]:
|
def __getitem__(self, item: str) -> Dict[str, Dict]:
|
||||||
return self.__recipes[item]
|
return self.__recipes[item]
|
||||||
@ -31,14 +62,14 @@ class Cookbook(object):
|
|||||||
:param name: The target item name
|
:param name: The target item name
|
||||||
:return: A sequence of possible recipes for the target item
|
: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:
|
def is_component(self, name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
:param name: The name of an item
|
:param name: The name of an item
|
||||||
:return: Whether the item is a component; ie, craftable.
|
: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]:
|
def components(self) -> Generator[str, None, None]:
|
||||||
"""
|
"""
|
||||||
@ -51,7 +82,7 @@ class Cookbook(object):
|
|||||||
:param name: The name of an item
|
:param name: The name of an item
|
||||||
:return: Whether the item must have harvested (rather than crafted)
|
: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]:
|
def resources(self) -> Generator[str, None, None]:
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user