Skip to content

Instantly share code, notes, and snippets.

@andyneff
Last active December 30, 2020 08:30
Show Gist options
  • Save andyneff/abe631d06881757b7d41cfd2373a8915 to your computer and use it in GitHub Desktop.
Save andyneff/abe631d06881757b7d41cfd2373a8915 to your computer and use it in GitHub Desktop.
import os
from glob import glob
import re
import numpy as np
from itertools import combinations
from fractions import Fraction
from math import gcd
class FoodFile:
def __init__(self, name):
self.filename = name
with open(self.filename, 'r') as fid:
self.data = fid.readlines()
self.name = self.get_line("LocDisplayName").split('"')[1]
self.calories = int(re.split("return (-?\d*);",
self.get_line("float Calories"))[1])
nutrients = self.get_line("new Nutrients")
self.carbs = int(re.split("Carbs *= *(\d*)", nutrients)[1])
self.fat = int(re.split("Fat *= *(\d*)", nutrients)[1])
self.protein = int(re.split("Protein *= *(\d*)", nutrients)[1])
self.vitamins = int(re.split("Vitamins *= *(\d*)", nutrients)[1])
try:
self.station = re.split(r"AddRecipe\(typeof\(([^)]*)\)",
self.get_line("CraftingComponent.AddRecipe"))[1]
except Exception:
self.station = "None"
self.weight = re.split(r"\[Weight\((\d*)\)\]", self.get_line("[Weight"))[1]
def get_line(self, pattern):
lines = [x for x in self.data if pattern in x]
assert len(lines) == 1
return [x for x in self.data if pattern in x][0]
class Foods:
def __init__(self, location=r"C:\Program Files (x86)\Steam\steamapps\common\Eco\Eco_Data\Server\Mods\AutoGen\Food"):
files = glob(os.path.join(location, '*.cs'))
self.foods = []
for f in files:
self.foods.append(FoodFile(f))
# math.lcm
def lcm(ints):
_lcm = ints[0]
for i in ints[1:]:
_lcm = _lcm*i//gcd(_lcm, i)
return _lcm
def main():
foods = Foods()
filtered_foods = [f for f in foods.foods if
f.station in ["None", "CampfireObject"]
# CastIronStoveObject KitchenObject BakeryOvenObject ButcheryTableObject MillObject StoveObject LaboratoryObject
and f.calories > 0
and f.carbs + f.fat + f.protein + f.vitamins >= 20
# and f.name in ["Jungle Campfire Salad", "Wild Stew", "Meaty Stew", "Campfire Roast"]
# and f.name in ["Jungle Campfire Salad", "Wild Stew", "Meaty Stew"]
and f.name not in ["Ecoylent"]
]
for c in combinations(filtered_foods, 2):
names = [f.name for f in c]
nutrients = np.array([[f.carbs for f in c],
[f.protein for f in c],
[f.fat for f in c],
[f.vitamins for f in c]])
calories = np.array([f.calories for f in c])
weighted_nutrients = nutrients*calories
mi = np.linalg.pinv(weighted_nutrients)
ans = mi.dot([[1],[1],[1],[1]])
# All Positive
if ans.min() < -1e-10:
continue
# Clean up floats
ans /= ans.max()
ans = [Fraction(f).limit_denominator() for f in ans.flatten()]
lcd = lcm([f.denominator for f in ans])
ans = [(a*lcd).numerator for a in ans]
average_nutrients = weighted_nutrients.dot(ans)/sum(ans*calories)
balance_modifier = sum(average_nutrients)/(2*max(average_nutrients))
# Max # of items and Max imbalance
if sum(ans) > 100 \
or balance_modifier < 1.9:
continue
print('\n', names)
print(ans)
print("Nutrition (mod):", average_nutrients, f"({balance_modifier})")
# for ff in foods.foods:
# print(f"{ff.name},{ff.station},{ff.calories},{ff.weight},{ff.carbs},"
# f"{ff.protein},{ff.fat},{ff.vitamins}")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment