nc-planner/scripts/solver.js

135 lines
5.5 KiB
JavaScript

import { emitEvent, listenTo } from "./events.js";
import {
getPlannerCellDom,
getPlannerCellsDom,
getPlannerDom,
getPlannerMultiblockSize,
getPlannerMultiblockType
} from "./planner.js";
import { checkEquivalence, findFullEntry, findFullEntryFromAtlasMetadata } from "./ncpf-utils.js";
import { getMetadata, setCellMetadata, setDomMetadata } from "./metadata.js";
import { registerLoadCallback } from "./main.js";
import { getAtlasMetadata } from "./atlas.js";
import { initialize3dArray } from "./js-utils.js";
registerLoadCallback(() => {
listenTo("fileLoad:end", runSolver);
listenTo("planner:cell:change", runSolver);
});
export function resetSolver(design = undefined, designConfiguration) {
const planner = getPlannerDom();
if (design && designConfiguration) {
planner.dataset.type = design.type;
if (design.type === "nuclearcraft:overhaul_sfr") {
// design has coolant_recipe and block_recipes
const designCoolantRecipe = designConfiguration.coolant_recipes[design.coolant_recipe];
const fullCoolantRecipe = findFullEntry(
"coolant_recipes",
designCoolantRecipe,
{ configurationHint: design.type },
);
setDomMetadata(planner, { coolant_recipe: fullCoolantRecipe });
const designBlockRecipes = design.block_recipes.flat(3);
for (let x = 0; x < design.dimensions[0]; x++) {
for (let y = 0; y < design.dimensions[1]; y++) {
for (let z = 0; z < design.dimensions[2]; z++) {
const block = designConfiguration.blocks[design.design[x][y][z]];
if (!block || !block.modules || !block.modules["ncpf:block_recipes"]) continue;
const blockRecipeIndex = designBlockRecipes.shift();
const blockRecipe = block.modules["ncpf:block_recipes"].recipes[blockRecipeIndex];
setCellMetadata(getPlannerCellDom(x, y, z), "block_recipe", blockRecipe);
}
}
}
}
}
emitEvent("solver:reset:done");
}
const sixAxes = [
{x: -1, y: 0, z: 0},
{x: 0, y: -1, z: 0},
{x: 0, y: 0, z: -1},
{x: 1, y: 0, z: 0},
{x: 0, y: 1, z: 0},
{x: 0, y: 0, z: 1},
]
function *travelUntil(grid, { x, y, z }, {x: dirX = 0, y: dirY = 0, z: dirZ = 0}, shouldStop = (pos) => false) {
x = Number(x);
y = Number(y);
z = Number(z);
while (!shouldStop({x, y, z})
&& x > 0 && y > 0 && z > 0
&& x < grid.length - 1 && y < grid[0].length - 1 && z < grid[0][0].length - 1) {
x += dirX;
y += dirY;
z += dirZ;
yield grid[x][y][z];
}
}
export function runSolver() {
emitEvent("solver:begin")
const multiblockType = getPlannerMultiblockType();
const plannerBlocks = getPlannerCellsDom()
.map(b => ({ dom: b, ...b.dataset }))
.filter(b => b.tile !== "-1")
.map(b => (b.metadata ? { ...b, metadata: getMetadata(b.metadata) } : b));
const tileMap = Object.fromEntries([...new Set(plannerBlocks.map(b => b.tile))]
.map(idx => [idx, getAtlasMetadata(idx)])
.map(([idx, md]) => [idx, findFullEntry("blocks", md, { configurationHint: multiblockType })]));
plannerBlocks.forEach(v => v.tile = tileMap[v.tile]);
const plannerBlocksGrid = initialize3dArray(...getPlannerMultiblockSize());
plannerBlocks.forEach(b => {
plannerBlocksGrid[b.x][b.y][b.z] = b;
});
if (multiblockType === "nuclearcraft:overhaul_sfr") {
const fuelCells = plannerBlocks.filter(b => b.tile.modules && b.tile.modules["nuclearcraft:overhaul_sfr:fuel_cell"]);
// const neutronSources = plannerBlocks.filter(b => b.tile.modules && b.tile.modules["nuclearcraft:overhaul_sfr:neutron_source"]);
// const reflectors = plannerBlocks.filter(b => b.tile.modules && b.tile.modules["nuclearcraft:overhaul_sfr:reflector"]);
// const shields = plannerBlocks.filter(b => b.tile.modules && b.tile.modules["nuclearcraft:overhaul_sfr:neutron_shield"]);
// const moderators = plannerBlocks.filter(b => b.tile.modules && b.tile.modules["nuclearcraft:overhaul_sfr:moderator"]);
// const coolers = plannerBlocks.filter(b => b.tile.modules && b.tile.modules["nuclearcraft:overhaul_sfr:heat_sink"]);
// const irradiators = plannerBlocks.filter(b => b.tile.modules && b.tile.modules["nuclearcraft:overhaul_sfr:irradiator"]);
// const conductors = plannerBlocks.filter(b => b.tile.modules && b.tile.modules["nuclearcraft:overhaul_sfr:conductor"]);
fuelCells.forEach(cell => {
const recipeList = cell.tile.modules["ncpf:block_recipes"].recipes;
cell.recipe = recipeList.find(r => checkEquivalence(r, cell.metadata.block_recipe));
cell.axes = sixAxes.map(dir => [...travelUntil(
plannerBlocksGrid,
cell,
dir,
({x, y, z}) => {
const block = plannerBlocksGrid[x][y][z];
if (block === cell) {
return false;
}
if (!block) {
return false;
}
if (block.tile.modules) {
if (block.tile.modules["nuclearcraft:overhaul_sfr:fuel_cell"]) return true;
if (block.tile.modules["nuclearcraft:overhaul_sfr:reflector"]) return true;
}
return false;
}
)]);
if (cell.recipe.modules["nuclearcraft:overhaul_sfr:fuel_stats"].self_priming) {
cell.primer = cell;
} else if (cell.axes.some(a => (a[a.length - 1]?.tile?.modules ?? {})["nuclearcraft:overhaul_sfr:neutron_source"])) {
const primerAxis = cell.axes.find(a => (a[a.length - 1]?.tile?.modules ?? {})["nuclearcraft:overhaul_sfr:neutron_source"]);
cell.primer = primerAxis[primerAxis.length - 1];
}
});
console.log(fuelCells);
}
}