|
|
@@ -0,0 +1,73 @@
|
|
|
+import {cachedFetchJSON} from './cache';
|
|
|
+
|
|
|
+render();
|
|
|
+
|
|
|
+async function render(): Promise<void> {
|
|
|
+ const loader = document.querySelector('#loader') as HTMLElement;
|
|
|
+ loader.style.display = 'block';
|
|
|
+ try {
|
|
|
+ await _render();
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e);
|
|
|
+ }
|
|
|
+ loader.style.display = 'none';
|
|
|
+}
|
|
|
+
|
|
|
+async function _render(): Promise<void> {
|
|
|
+ const allRecipes: readonly RecipeFull[] = await cachedFetchJSON('https://api.prunplanner.org/data/recipes/');
|
|
|
+ const cols = ratRecipes(allRecipes);
|
|
|
+ document.querySelector('#cols')!.innerHTML = cols.map((col) =>
|
|
|
+ `<div class="col">${Array.from(col).map((input) => `<div class="mat">${input}</div>`).join('')}</div>`
|
|
|
+ ).join('');
|
|
|
+}
|
|
|
+
|
|
|
+function ratRecipes(allRecipes: readonly RecipeFull[]): Set<string>[] {
|
|
|
+ const ratRecipes = allRecipes.filter((recipe) =>
|
|
|
+ recipe.building_ticker === 'FP' && recipe.outputs.length === 1 && recipe.outputs[0].material_ticker === 'RAT');
|
|
|
+ const recipes: Recipe[] = ratRecipes.map((recipe) => {
|
|
|
+ return {
|
|
|
+ inputs: recipe.inputs.map((input) => input.material_ticker),
|
|
|
+ catalogued: false,
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ const cols: Set<string>[] = [new Set(), new Set(), new Set()];
|
|
|
+ const seenInputs = new Set<string>();
|
|
|
+ recipes[0].inputs.forEach((input, index) => {
|
|
|
+ cols[index].add(input);
|
|
|
+ seenInputs.add(input);
|
|
|
+ });
|
|
|
+ recipes[0].catalogued = true;
|
|
|
+ let allCatalogued;
|
|
|
+ do {
|
|
|
+ allCatalogued = true;
|
|
|
+ for (const recipe of recipes) {
|
|
|
+ if (recipe.catalogued) continue;
|
|
|
+ const inputs = new Set(recipe.inputs);
|
|
|
+ const newInputs = inputs.difference(seenInputs);
|
|
|
+ if (newInputs.size === 1) {
|
|
|
+ const newInput = newInputs.keys().next().value!;
|
|
|
+ const seenCols = Array.from(inputs.difference(newInputs)).map((oldInput) =>
|
|
|
+ cols.findIndex((col) => col.has(oldInput)));
|
|
|
+ const newCol = new Set([0, 1, 2]).difference(new Set(seenCols)).keys().next().value!;
|
|
|
+ cols[newCol].add(newInput);
|
|
|
+ seenInputs.add(newInput);
|
|
|
+ recipe.catalogued = true;
|
|
|
+ } else if (newInputs.size === 0)
|
|
|
+ recipe.catalogued = true;
|
|
|
+ else
|
|
|
+ allCatalogued = false;
|
|
|
+ }
|
|
|
+ } while (!allCatalogued);
|
|
|
+ return cols;
|
|
|
+}
|
|
|
+
|
|
|
+interface RecipeFull {
|
|
|
+ building_ticker: string;
|
|
|
+ inputs: Array<{material_ticker: string}>
|
|
|
+ outputs: Array<{material_ticker: string}>
|
|
|
+}
|
|
|
+interface Recipe {
|
|
|
+ readonly inputs: Array<string>
|
|
|
+ catalogued: boolean;
|
|
|
+}
|