Grains resting on anything built cast no shadow (t37)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 20:21:31 -04:00
co-authored by Claude Opus 5.5
parent 7d1be16094
commit f19facbe5c
4 changed files with 45 additions and 6 deletions
+1 -1
View File
@@ -352,7 +352,7 @@ Drawing (src/render/): browser only. This file: the renderer state R, colour tab
- functions: glowIndex, thermIdx, pipeCellColor, pipeBodyCell, thinPipeColor, beltLike, buildSky, initRender, resizeRender, viewCells, updateCamera, snapCamera, screenToWorld, worldToScreenPx, renderMonoFont - functions: glowIndex, thermIdx, pipeCellColor, pipeBodyCell, thinPipeColor, beltLike, buildSky, initRender, resizeRender, viewCells, updateCamera, snapCamera, screenToWorld, worldToScreenPx, renderMonoFont
- variables: R, GLOW_W, GLOW_R, GLOW_G, GLOW_B, THERM, PC, TREE_R, TREE_G, TREE_B, BG, SKY_R, SKY_G, SKY_B - variables: R, GLOW_W, GLOW_R, GLOW_G, GLOW_B, THERM, PC, TREE_R, TREE_G, TREE_B, BG, SKY_R, SKY_G, SKY_B
### src/render/light.js (104 lines) ### src/render/light.js (103 lines)
Propagated coloured light from glowing and burning cells. Propagated coloured light from glowing and burning cells.
- functions: builtForLight, looseForLight, computeLight - functions: builtForLight, looseForLight, computeLight
+9
View File
@@ -4,6 +4,15 @@ What agents have done, newest first. Add an entry for every piece of work: the d
note or request it was for, what changed, the files touched, the tests run, and anything left note or request it was for, what changed, the files touched, the tests run, and anything left
open or not verified. Keep each entry short; the git history has the details. open or not verified. Keep each entry short; the git history has the details.
## 2026-10-25: t37 follow-up: grains on built things cast no shadows (Claude Code, Codex)
- The owner saw a flickering shadow under a grinder fed by a stream: grains resting on its
housing for a moment shaded. `looseForLight` (`src/render/light.js`) now treats a loose stack
that rests on any `builtForLight` cell, or ends in air or gas, as see-through. Stacks on natural
ground or deeper than 12 cells still shade.
- `test/t_light.js` (a grinder stream checked for 180 ticks in both lighting modes);
`run_all.py --browser` ALL PASSED.
## 2026-10-25: t37 follow-up: falling grains cast no shadows (Claude Code, Codex) ## 2026-10-25: t37 follow-up: falling grains cast no shadows (Claude Code, Codex)
- The owner saw a single falling grain darken a column of sky. `onBeltForLight` became - The owner saw a single falling grain darken a column of sky. `onBeltForLight` became
+1 -2
View File
@@ -8,8 +8,7 @@ function builtForLight(i, x, y) {
function looseForLight(i) { function looseForLight(i) {
for (let depth = 0; depth <= 12 && i < N; depth++, i += W) { for (let depth = 0; depth <= 12 && i < N; depth++, i += W) {
const m = mat[i], ph = PH[m]; const m = mat[i], ph = PH[m];
if (m === BELTL || m === BELTR || part[i] === P_FILTER) return true; if (builtForLight(i, i % W, (i / W) | 0)) return true;
if (part[i]) return false;
if (ph !== PH_POWDER && ph !== PH_LIQUID) return m === EMPTY || ph === PH_GAS; if (ph !== PH_POWDER && ph !== PH_LIQUID) return m === EMPTY || ph === PH_GAS;
} }
return false; return false;
+34 -3
View File
@@ -97,9 +97,10 @@ for (const [name, support, depth, gap, expected] of [
['12 falling grains', '', 12, '', true], ['12 falling grains', '', 12, '', true],
['13 falling grains', '', 13, '', false], ['13 falling grains', '', 13, '', false],
['natural ledge', 'mat[i] = STONE; flags[i] = F_NAT', 3, '', false], ['natural ledge', 'mat[i] = STONE; flags[i] = F_NAT', 3, '', false],
['wall floor', 'mat[i] = STONE', 3, '', false], ['deep natural heap', 'mat[i] = SAND; flags[i] = F_NAT', 13, '', false],
['tube', 'part[i] = P_TR', 3, '', false], ['wall floor', 'mat[i] = STONE', 3, '', true],
['loaded tube', 'mat[i] = SAND; part[i] = P_TR', 3, '', false], ['tube', 'part[i] = P_TR', 3, '', true],
['loaded tube', 'mat[i] = SAND; part[i] = P_TR', 3, '', true],
]) { ]) {
run(` run(`
for (let y = 40; y <= 53; y++) { const i = y * W + 300; mat[i] = SAND; part[i] = 0; flags[i] = 0; } for (let y = 40; y <= 53; y++) { const i = y * W + 300; mat[i] = SAND; part[i] = 0; flags[i] = 0; }
@@ -112,4 +113,34 @@ run('mat[40 * W + 300] = SAND; mat[41 * W + 300] = EMPTY;');
check('a single grain in mid-air is see-through', run('looseForLight(40 * W + 300)')); check('a single grain in mid-air is see-through', run('looseForLight(40 * W + 300)'));
run('mat[(H - 1) * W + 300] = SAND;'); run('mat[(H - 1) * W + 300] = SAND;');
check('loose cell detection stops at the world bottom', run('!looseForLight((H - 1) * W + 300)')); check('loose cell detection stops at the world bottom', run('!looseForLight((H - 1) * W + 300)'));
flatWorld(run, 320, 200, 160);
run(`
bot.lamp = false; stats.refined = 0;
placeBlock(BP_GRIND, 0, 20, 20, true);
for (let bx = 8; bx < 30; bx++) placeBlock(BP_BELT, 1, bx, 36, true);
setCell(79 * W + 80, SAND, AMB[79], 0);
`);
check('sand resting on grinder housing is see-through', run('looseForLight(79 * W + 80)'));
for (const mode of ['full', 'fast']) {
const result = run(`(() => {
SET.lighting = '${mode}';
let mismatches = 0, first = '';
for (let t = 0; t < 180; t++) {
if (t % 4 === 0) setCell(48 * W + 80, SAND, AMB[48], 0);
simTick();
computeLight();
for (const a of [R.lr, R.lg, R.lb]) for (let x = 76; x < 88; x += 2) {
const below = lightAt(a, x, 160), open = lightAt(a, 152, 160);
if (Math.abs(below - open) > 1e-6) {
mismatches++;
if (!first) first = 'tick ' + tick + ', x ' + x + ': ' + below + ' / ' + open;
}
}
}
return { mismatches, first };
})()`);
check(`${mode}: streaming grinder leaves ground in daylight for 180 consecutive ticks`, result.mismatches === 0, result.first || 'no shadow');
}
check('the streaming grinder actually processes its input', run('stats.refined > 0'), run('stats.refined'));
done(); done();