From 1581f767fac35ccedbed5699635fe8878e77d45f Mon Sep 17 00:00:00 2001 From: dlawler489 <104159223@student.swin.edu.au> Date: Thu, 17 Sep 2026 13:27:58 +1000 Subject: [PATCH] Fill "any colour" slots last, not first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found on the live library: setting slot 2 of a four-colour bookmark to "any colour" made it take the one Jade White spool, leaving slot 4 — which asks for #FFFFFF — with nothing, and the verdict stuck at "needs 3 colours" when it should have improved to 2. The assignment sorts candidate pairs by colour distance and scored a colourless slot 0, a perfect match, so it always claimed a spool ahead of a slot that needed that exact colour. Colourless slots now sort last and take whatever is left over. Fixed in both the server and the browser copy, which mirror each other, and pinned by a test built from the reported case. Co-Authored-By: Claude Opus 5 --- lib/filaments.js | 4 +++- public/app.js | 4 +++- test/filaments.test.js | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/filaments.js b/lib/filaments.js index ce429e4..07eaaf6 100644 --- a/lib/filaments.js +++ b/lib/filaments.js @@ -68,7 +68,9 @@ function assignSpools(filaments, spools) { for (const slot of slots) { for (const spool of shelf) { if (spool.material !== slot.material) continue; - if (slot.colour === null) { pairs.push({ slot: slot.index, spool: spool.key, d: 0 }); continue; } + // A slot that takes any colour is filled last, from whatever is left: + // scoring it 0 would let it claim a spool an exact-match slot needs. + if (slot.colour === null) { pairs.push({ slot: slot.index, spool: spool.key, d: Number.MAX_SAFE_INTEGER }); continue; } const d = colourDistance(slot.colour, spool.colour); if (d !== null && d <= COLOUR_TOLERANCE) pairs.push({ slot: slot.index, spool: spool.key, d }); } diff --git a/public/app.js b/public/app.js index 5e2e352..eab9936 100644 --- a/public/app.js +++ b/public/app.js @@ -328,7 +328,9 @@ function printability(m) { for (const slot of slots) { for (const spool of shelf) { if (spool.material !== slot.material) continue; - if (slot.colour === null) { pairs.push({ slot: slot.index, spool: spool.key, d: 0 }); continue; } + // Filled last, from what's left: scoring it 0 would let an "any colour" + // slot take the spool an exact-match slot needs. + if (slot.colour === null) { pairs.push({ slot: slot.index, spool: spool.key, d: Number.MAX_SAFE_INTEGER }); continue; } const d = colourDistance(slot.colour, spool.colour); if (d !== null && d <= COLOUR_TOLERANCE) pairs.push({ slot: slot.index, spool: spool.key, d }); } diff --git a/test/filaments.test.js b/test/filaments.test.js index d2e26b5..4ae4b66 100644 --- a/test/filaments.test.js +++ b/test/filaments.test.js @@ -130,3 +130,19 @@ test('a slot with no colour is filled by any spool of that material', () => { assert.equal(filaments.isPrintable([{ type: 'PLA', colour: null }, { type: 'PLA', colour: null }], [{ id: 1, material: 'PLA', colour_hex: '#123456', colour: 'Anything', remaining_g: 200 }]), false); }); + +test('an "any colour" slot takes what’s left, not what another slot needs', () => { + // Reported from the live library: editing slot 2 of a bookmark to "any + // colour" stole the one white spool, leaving the slot that actually wanted + // #FFFFFF empty and the verdict no better than before. + const shelf = [{ id: 1, material: 'PLA', colour_hex: '#FFFFFF', colour: 'Jade White', remaining_g: 1000 }]; + const slots = filaments.assignSpools([{ type: 'PLA', colour: null }, { type: 'PLA', colour: '#FFFFFF' }], shelf); + assert.equal(slots[1].filled, true, 'the slot that asks for white gets the white spool'); + assert.equal(slots[1].by, 'Jade White'); + assert.equal(slots[0].filled, false, 'the any-colour slot goes without'); + + // With two spools, both are filled and the exact match still gets white. + const two = shelf.concat({ id: 2, material: 'PLA', colour_hex: '#123456', colour: 'Anything', remaining_g: 500 }); + const both = filaments.assignSpools([{ type: 'PLA', colour: null }, { type: 'PLA', colour: '#FFFFFF' }], two); + assert.deepEqual(both.map((s) => s.by), ['Anything', 'Jade White']); +});