Bot can never be trapped in rock: nudge, retrace trail, fly out (t72)

This commit is contained in:
2026-10-29 18:25:37 -04:00
parent fc29214162
commit b655d754b9
8 changed files with 196 additions and 15 deletions
+52 -8
View File
@@ -8,6 +8,46 @@ function botOverlapSolid(x, y) {
for (let cy = y0; cy <= y1; cy++) for (let cx = x0; cx <= x1; cx++) if (botBlocked(cy * W + cx)) return true;
return false;
}
// Only visited, open positions enter this fixed ring; normal recording is O(1).
const BOT_TRAIL_SIZE = 256;
const botTrailX = new Float64Array(BOT_TRAIL_SIZE), botTrailY = new Float64Array(BOT_TRAIL_SIZE);
let botTrailHead = 0, botTrailCount = 0, botEscape = false;
function botTrailRecord() {
const last = (botTrailHead + BOT_TRAIL_SIZE - 1) % BOT_TRAIL_SIZE;
const dx = bot.x - botTrailX[last], dy = bot.y - botTrailY[last];
if (botTrailCount && dx * dx + dy * dy < BS * BS) return;
botTrailX[botTrailHead] = bot.x; botTrailY[botTrailHead] = bot.y;
botTrailHead = (botTrailHead + 1) % BOT_TRAIL_SIZE;
botTrailCount = Math.min(BOT_TRAIL_SIZE, botTrailCount + 1);
}
// Precompute once: 440 probes within three blocks, nearest first and up on ties.
const BOT_NUDGES = [];
for (let y = -12; y <= 12; y++) for (let x = -12; x <= 12; x++) {
if (x * x + y * y > 0 && x * x + y * y <= 144) BOT_NUDGES.push([x, y]);
}
BOT_NUDGES.sort((a, b) => a[0] * a[0] + a[1] * a[1] - b[0] * b[0] - b[1] * b[1] || a[1] - b[1] || a[0] - b[0]);
function botNudgeOpen(x, y) {
if (botOverlapSolid(x, y)) return false;
for (let cy = Math.floor(y); cy < Math.ceil(y + bot.h); cy++)
for (let cx = Math.floor(x); cx < Math.ceil(x + bot.w); cx++) if (fogSeen(cx, cy) < 255) return false;
return true;
}
function botRescue() {
for (let k = 0; k < BOT_NUDGES.length; k++) {
const x = bot.x + BOT_NUDGES[k][0], y = bot.y + BOT_NUDGES[k][1];
if (botNudgeOpen(x, y)) { bot.x = x; bot.y = y; return; }
}
// At most 256 checks. Discard the buried end so the next retrace stays behind us.
for (let k = 0; k < botTrailCount; k++) {
const i = (botTrailHead + BOT_TRAIL_SIZE - 1 - k) % BOT_TRAIL_SIZE;
if (botOverlapSolid(botTrailX[i], botTrailY[i])) continue;
bot.x = botTrailX[i]; bot.y = botTrailY[i]; bot.vx = bot.vy = 0;
botTrailHead = (i + 1) % BOT_TRAIL_SIZE; botTrailCount -= k;
emit({t: 'toast', text: 'Dug out: back where you came from'}); return;
}
botEscape = true;
emit({t: 'toast', text: 'Dug out: Fly through the rock to open space'});
}
// Flying straight into a lip of rock a grain or two deep at the edge of the bot, it slips
// sideways round it instead of stopping dead, so it threads tunnels and holes it nearly fits.
const SLIDE_MAX = 2.5, SLIDE_STEP = 0.34;
@@ -37,19 +77,23 @@ function botStep(ix, iy, boost) {
bot.vx *= 0.885; bot.vy *= 0.885;
if (ix) bot.face = ix > 0 ? 1 : -1;
bot.thrust = Math.min(1, Math.hypot(ix, iy));
if (botOverlapSolid(bot.x, bot.y)) {
// unstick: search upward then sideways for a free spot
for (let k = 1; k < 40; k++) {
if (!botOverlapSolid(bot.x, bot.y - k)) { bot.y -= k; break; }
if (!botOverlapSolid(bot.x - k, bot.y)) { bot.x -= k; break; }
if (!botOverlapSolid(bot.x + k, bot.y)) { bot.x += k; break; }
}
}
const buried = botOverlapSolid(bot.x, bot.y);
if (!buried) {
botEscape = false;
if (!botTrailCount) botTrailRecord();
} else if (!botEscape) botRescue();
const steps = Math.ceil(Math.max(Math.abs(bot.vx), Math.abs(bot.vy)) / 0.45) || 1;
const sx = bot.vx / steps, sy = bot.vy / steps;
for (let s = 0; s < steps; s++) {
if (botEscape) {
bot.x = Math.max(0, Math.min(W - bot.w, bot.x + sx));
bot.y = Math.max(0, Math.min(H - bot.h, bot.y + sy));
if (!botOverlapSolid(bot.x, bot.y)) botEscape = false;
continue;
}
if (sx) { if (!botOverlapSolid(bot.x + sx, bot.y)) bot.x += sx; else if (!(ix && !iy && botSlide(0, sx))) { bot.vx *= -0.15; } }
if (sy) { if (!botOverlapSolid(bot.x, bot.y + sy)) bot.y += sy; else if (!(iy && !ix && botSlide(1, sy))) { bot.vy *= -0.15; } }
}
if (!botEscape) botTrailRecord();
// loose grains, liquids and gases pass straight through the bot: it never moves them
}
+1
View File
@@ -46,6 +46,7 @@ function sharedArray(Type, length) {
}
function alloc(w, h) {
resetDevConsole();
botTrailHead = botTrailCount = 0; botEscape = false;
W = w; H = h; N = w * h;
fogAlloc();
CW = Math.ceil(w / 32); CH = Math.ceil(h / 32); NCH = CW * CH;