Skip to content

Commit 1b5d0e6

Browse files
bod09claude
andcommitted
Fix combine machine quantity halving (prismatic 2:1, alloy 2:1)
Two changes to quantity propagation: 1. Same-type combine machines (prismatic: 2 gems → 1, alloy: 2 bars → 1 alloy_bar) now correctly multiply demand for ALL edge kinds, including enhancement edges. Previously enhancement edges were exempted, preventing prismatic from halving quantities in the transmute chain. 2. Added forward supply propagation (Phase A2): After demand propagation, BFS from ore_source through main/enhancement edges sets supply-constrained quantities. Same-type combines halve the flow. This ensures quantities match actual ore supply (24 ores) rather than unconstrained demand. Result for Power Core with 24 ores: Ore x24 → Smelter x24 → Enhancement x24 → Prismatic x12 (halved!) → Gem to Bar x12 → Alloy Furnace x6 (halved!) → consumers x6 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent df2c2f6 commit 1b5d0e6

2 files changed

Lines changed: 45 additions & 11 deletions

File tree

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ <h2>Machine Connections</h2>
248248
<script src="js/data.js?v=367"></script>
249249
<script src="js/graph.js?v=367"></script>
250250
<script src="js/chain-solver.js?v=367"></script>
251-
<script src="js/graph-builder.js?v=367"></script>
251+
<script src="js/graph-builder.js?v=368"></script>
252252
<script src="js/graph-layout.js?v=367"></script>
253253
<script src="js/visualizer.js?v=367"></script>
254254
<script src="js/optimizer.js?v=367"></script>

js/graph-builder.js

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -446,9 +446,9 @@ class FlowGraphBuilder {
446446

447447
let demand = nd.quantity;
448448

449-
// Same-type combine: multiply demand only for MAIN edges (real production).
450-
// Enhancement edges pass through 1:1 (same items looping through value transform).
451-
if (isSameTypeCombine && edge.kind !== "enhancement") {
449+
// Same-type combine (prismatic 2:1, alloy 2:1): always multiply demand.
450+
// This is real physical consumption — 2 gems become 1 output, even in enhancement paths.
451+
if (isSameTypeCombine) {
452452
demand = nd.quantity * (machine.inputs?.length || 2);
453453
}
454454

@@ -462,13 +462,47 @@ class FlowGraphBuilder {
462462
}
463463
}
464464

465-
// Special: ore_source gets actualOreCount (externally known total)
466-
for (const n of nodes) {
467-
if (n.machine === "ore_source" && !n.machine?.startsWith?.("cheap_")) {
468-
// Only override non-cheap ore source
469-
const key = [...visited.entries()].find(([k, v]) => v === n.id)?.[0];
470-
if (key && !key.startsWith("cheap_")) {
471-
n.quantity = actualOreCount;
465+
// --- Phase A2: Forward supply propagation from ore_source ---
466+
// The demand propagation may produce quantities exceeding ore supply.
467+
// Fix: set ore_source to actualOreCount, then forward-propagate through
468+
// main/enhancement chain, halving at same-type combine machines.
469+
// This gives supply-constrained quantities that match what actually flows.
470+
const oreSourceNode = nodes.find(n => {
471+
if (n.machine !== "ore_source") return false;
472+
const key = [...visited.entries()].find(([k, v]) => v === n.id)?.[0];
473+
return key && !key.startsWith("cheap_");
474+
});
475+
if (oreSourceNode) {
476+
oreSourceNode.quantity = actualOreCount;
477+
// Forward BFS from ore_source through main/enhancement edges
478+
const supplyVisited = new Set([oreSourceNode.id]);
479+
const supplyQueue = [oreSourceNode.id];
480+
while (supplyQueue.length > 0) {
481+
const curId = supplyQueue.shift();
482+
const curNode = nodeById.get(curId);
483+
if (!curNode) continue;
484+
// Find edges FROM this node (it feeds downstream consumers)
485+
for (const edge of edges) {
486+
if (edge.from !== curId || edge.kind === "byproduct") continue;
487+
if (supplyVisited.has(edge.to)) continue;
488+
supplyVisited.add(edge.to);
489+
const downstream = nodeById.get(edge.to);
490+
if (!downstream) continue;
491+
// Don't override seller/QA — those are demand-driven (productQty)
492+
if (downstream.machine === "seller" || downstream.machine === "quality_assurance") continue;
493+
// Downstream gets same qty as supplier...
494+
let qty = curNode.quantity;
495+
// ...unless downstream is a same-type combine (halves)
496+
const dsMachine = registry.get(downstream.machine);
497+
const dsIsCombine = dsMachine?.effect === "combine" &&
498+
dsMachine.inputs?.length >= 2 &&
499+
new Set(dsMachine.inputs.flatMap(i => i.split("|"))).size === 1;
500+
if (dsIsCombine) {
501+
qty = Math.floor(qty / (dsMachine.inputs?.length || 2));
502+
}
503+
downstream.quantity = qty;
504+
edge.quantity = curNode.quantity; // Edge shows items flowing IN
505+
supplyQueue.push(edge.to);
472506
}
473507
}
474508
}

0 commit comments

Comments
 (0)