mod-recipes | ||
README.org |
Factorio Recipe Analyzer
Intro
This is a simple Raku script which generates an analysis of each recipe into its component parts, and delivers insight into the balance and progression of a mod.
The .csv files used as input are generated in Factorio, by loading a new game with only base
and your chosen mod enabled, and running the following Lua code:
/c
local whitelist = {}
for _, k in pairs({
"iron-plate",
"copper-plate",
"steel-plate",
"copper-wire",
"iron-gear-wheel",
"iron-stick",
"pipe",
}) do whitelist[k] = true end
local parts = {}
for name, recipe in pairs(game.recipe_prototypes) do
local history = script.get_prototype_history("recipe", name)
if history.created == "base" then
local add = false
local ingredients = {}
for _, ingredient in pairs(recipe.ingredients) do
if whitelist[ingredient.name] then add = true end
ingredients[#ingredients+1] = ingredient.name .. "," .. ingredient.amount
end
if add then
parts[#parts+1] = name .. "," .. table.concat(ingredients, ",")
end
end
end
game.write_file("recipes.csv", table.concat(parts, "\n"), false)
This script
This is a literate script. The source code is embedded in these code blocks, and tangled into the Raku script using org-babel. This allows me to write a description of what I want to do, and comment on it without resorting to // /* */
ugly comments.
License
I don't own the source csv files generated by Factorio, nor the mods the script is pulling from. The Raku script itself is GPLv3.
TODO: include GPLv3 in the repo
Credits:
The following are mods from which .csv files have been generated. The recipe .csv files are included in the mod-recipes
directory.
The Code
Setup
Open csv file
Open (create if needed) output org file
I like org-mode, sue me. Also pseudocode is in Lisp.
For this, we'll likely want to include some metadata, like creation date, mod name, number of ingredients, maybe the total amount of raw mats needed to make one of everything?
Make a list of products
That's the first column in the .csv file. Read first column of the csv file and insert it into the .org (output) file.
For each product, create a templated section
Ideally we'd end up with Something like:
* product ** direct inputs - input and amount - input and amount ** raw ingredients + raw ingredient and amount + raw ingredient and amount
Parse the csv file:
For each line:
- First column becomes the top header
- Insert second header
- Insert each ingredient and its amount as a separate item
Parse the output.org file, filling it out recursively
- Open .org (output file)
-
Loop over output.org:
- Find product section.
- Find (next) ingredient lines in this product section.
-
Pass the product and each direct input item and its number to
raw-ingredients
. (We can distinguish direct inputs from raw ingredients easily because org-mode supports multiple characters for defining lists. So we can just look for lines beginning with-
and not really think about anything else.)This would look something like:
(raw-ingredients iron-gear-wheel iron-plate 2) (raw-ingredients yellow-belt iron-plate 1)
-
(raw-ingredients (product item number))
:-
Store in variables for clarity:
- product
- item
- number
-
Read .csv file:
-
If a recipe for this item exists in the csv file:
- Go to the line with the recipe (first column.
- For each
(item number)
pair, call(raw-ingredients (product new-item (* new-number old-number)))
.
-
-
If a recipe does not exist:
- Find
* product
section in the .org file. -
If the ingredient item already exists:
- Add new number we just got to the existing number.
- Else: write new raw ingredient line and number in this section.
- Find
-