{"id":18972959,"url":"https://github.com/theokanning/satisfactoryoptimizer","last_synced_at":"2025-09-05T21:32:22.727Z","repository":{"id":87858426,"uuid":"331469675","full_name":"TheoKanning/SatisfactoryOptimizer","owner":"TheoKanning","description":"A recipe optimizer for Satisfactory www.satisfactorygame.com","archived":false,"fork":false,"pushed_at":"2021-05-10T00:50:33.000Z","size":515,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-06T13:51:51.259Z","etag":null,"topics":["optimization","or-tools","python","satisfactory"],"latest_commit_sha":null,"homepage":"https://theokanning.com/satisfactory-optimizer/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheoKanning.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-21T00:28:56.000Z","updated_at":"2025-01-27T22:14:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"1ba9fb80-fa74-4ed9-98be-d56afdc6331a","html_url":"https://github.com/TheoKanning/SatisfactoryOptimizer","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TheoKanning/SatisfactoryOptimizer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheoKanning%2FSatisfactoryOptimizer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheoKanning%2FSatisfactoryOptimizer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheoKanning%2FSatisfactoryOptimizer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheoKanning%2FSatisfactoryOptimizer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheoKanning","download_url":"https://codeload.github.com/TheoKanning/SatisfactoryOptimizer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheoKanning%2FSatisfactoryOptimizer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273826097,"owners_count":25175232,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["optimization","or-tools","python","satisfactory"],"created_at":"2024-11-08T15:10:34.564Z","updated_at":"2025-09-05T21:32:22.326Z","avatar_url":"https://github.com/TheoKanning.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Satisfactory Optimizer\nThis project uses Google's [OR-Tools](https://developers.google.com/optimization) to find optimal production ratios \nin [Satisfactory](http://www.satisfactorygame.com).\n\nData taken from [SatisfactoryTools](https://github.com/greeny/SatisfactoryTools/tree/dev/data)\n\nFull writeup at https://theokanning.com/satisfactory-optimizer/\n## Satisfactory\nSatisfactory is a game of automation.\nYou start by building machines to extract raw resources, then you combine resources and items into increasingly complex products.\nA Miner produces Iron Ore, and then a Smelter turns Iron Ore into Iron Ingots etc.\n\n![screenshot](assets/screenshot.jpeg)\n[source](https://www.satisfactorygame.com)\n\n## Recipes\nEach construction machine takes input items and creates new items based on a specified recipe.\nFor example, the default Iron Ingot recipe turns 30 Iron Ore into 30 Iron Ingots every minute.  \n\nMore advanced items can have up to four input items, and each recipe has unique input/output ratios, speeds, and by-products to consider.\nHere's a chart showing the steps to build a late-game item.  \n\n![picture](assets/flowchart.png)\n[source](https://www.reddit.com/r/SatisfactoryGame/comments/b7zv8h/satisfactory_production_flowchart_with_alternate/)\n\nQuite a lot to remember when building a factory!  \n\n## Alternate Recipes\nTo add even more complexity, many items have alternate recipes that may boost production depending on which starting resources are more plentiful.\nFor example, there are three Iron Ingot recipes:  \n- Iron Ingot: 30 Iron Ore to 30 Iron Ingots  \n- Pure Iron Ingot: 35 Iron Ore and 20 Water to 65 Iron Ingots  \n- Iron Alloy Ingot: 20 Iron Ore and 20 Copper Ore to 50 Iron Ingots  \n\nWhich recipe is the best? It depends on which resources are nearby.\nIf you have excess water/copper, and a shortage of iron, then the alternates will help.  \n\nThis Satisfactory Optimizer takes all alternate recipes into account and gives an optimal factory setup based on your available materials.\n\n## Dependencies\nInstall OR-tools with Pipenv  \n`pipenv install`\n\n## Usage\nExample resource calculation in `satisfactory.py`\n\nLoad recipes from the data file. For simplicity this example only uses default recipes. \n```\nrecipes = load_recipes()\ndefault_recipes = [r for r in recipes if not r.alternate]\n```\n\nSpecify the available resources in units/minute.  \n```\ninputs = {\n    \"Iron Ore\": 60\n}\n```\n\nGive a positive score to products you want to create.\n```\noutputs = {\n    \"Reinforced Iron Plate\": 1\n}\n```\n\nRun the optimizer\n```\noptimizer = Optimizer(default_recipes, inputs, outputs)\noptimizer.optimize()\n```\n\nThen run\n```\npipenv run python satisfactory.py\n```\n\nOutput:\n```\nSolution:\nObjective value: 4.93\n\nRecipes Used:\nIron Ingot: 2.00\nReinforced Iron Plate: 1.00\nIron Plate: 1.50\nIron Rod: 1.00\nScrew: 1.50\n\nInputs Remaining:\nIron Ore: 0.00\n\nProduced:\nReinforced Iron Plate: 5.00\n```\n`Recipes Used` shows how many machines need to run each recipe.  \n`Inputs Remaining` shows which resources run out first and limit production.  \n`Produced` shows all the produced components, not just those with a score.\n\n## Linear Optimization\nI modelled the recipe production ratios as a [linear programming](https://www.analyticsvidhya.com/blog/2017/02/lintroductory-guide-on-linear-programming-explained-in-simple-english/) problem.  \nA linear programming problem consists of _decision variables_, _constraints_, and an _objective function_.  \nThe optimizer modifies the decision variables to maximize the objective function while satisfying its constraints.\n\n### Decision Variables\nWe need to know how many machines should produce each recipe.\nTherefore, the recipe assignments are the decision variables.  \n\nx\u003csub\u003er\u003c/sub\u003e = # of machines producing recipe _r_\n\nx\u003csub\u003er\u003c/sub\u003e is a non-negative real number.\n\n### Objective Function\nWe want to create as many desirable products as possible, so the objective function is the score of each component multiplied by the total produced.\nIn order to eliminate extraneous recipes that don't contribute to the final score, each recipe incurs a small penalty.  \n\n![objective](assets/objective.jpg)\n\nwhere s\u003csub\u003ec\u003c/sub\u003e is the score for component _c_,  \nn\u003csub\u003ecr\u003c/sub\u003e is the quantity of _c_ produced by a single machine with recipe _r_,  \nand _p_ is a small, positive penalty.  \n\nn\u003csub\u003ecr\u003c/sub\u003e will be negative if _r_ consumes _c_ as an input.\n\n### Constraints\nFor this problem, the only constraint is that each component has a non-negative quantity, otherwise the optimizer could use recipes without having prerequisite materials.   \n\nFor each component _c_,  \n\n![constraint](assets/constraint.jpg)\n\nwhere input\u003csub\u003ec\u003c/sub\u003e is the specified input amount for component _c_.\n\n## Potential Improvements\n- Include energy costs in objective function","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheokanning%2Fsatisfactoryoptimizer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheokanning%2Fsatisfactoryoptimizer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheokanning%2Fsatisfactoryoptimizer/lists"}