Board, position, quarry, and memory.
Inputs for chooseSeekerStep. The same memory object is passed again
on the next tick.
False forgets a stored sighting. id is null when the sighting has a cell
but the caller never had an id for it.
Optionallegal?: Direction[]Directions the caller will accept. Omit for every open neighbor.
Optionallures?: Coord[]Cells to investigate before the last sighting. Omit when the game has none.
Optionalnow?: numberClock reading, in milliseconds, for SeekerStepArgs.pauseOnOverlapMs.
Defaults to Date.now().
OptionalpauseOnOverlapMs?: numberMilliseconds to wait before the next move when this seeker is standing on
a visible quarry. Omit or pass 0 to move on immediately.
Optionalrng?: () => numberQuarry the caller already decided this seeker can see, closest-search order.
One direction, or null when no legal step exists or an overlap pause is still running.
import { chooseSeekerStep, createNpcMemory, walkableUnlessTypes } from "@tamb/gamegrid/npc";
const memory = createNpcMemory();
const isWalkable = walkableUnlessTypes(["wall", "water"]);
const dir = chooseSeekerStep({
matrix,
isWalkable,
self: seeker.coord,
visibleQuarry: hidersInSight.map((hider) => ({ id: hider.id, coord: hider.coord })),
isQuarryActive: (id) => hiders.some((hider) => hider.id === id && hider.alive),
memory,
difficulty: "smart",
});
if (dir) stepActor(seeker, dir);
import { chooseSeekerStep } from "@tamb/gamegrid/npc";
chooseSeekerStep({
matrix,
isWalkable,
self: seeker.coord,
visibleQuarry: [],
isQuarryActive: () => false,
lures: alarms.map((alarm) => alarm.coord),
memory,
difficulty: "normal",
});
import { chooseSeekerStep, createNpcMemory, walkableUnlessTypes } from "@tamb/gamegrid/npc";
const matrix = [
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
[{ type: "wall" }, { type: "floor" }, { type: "floor" }, { type: "floor" }, { type: "floor" }],
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
];
const isWalkable = walkableUnlessTypes(["wall"]);
const memory = createNpcMemory();
chooseSeekerStep({
matrix,
isWalkable,
self: [2, 1],
visibleQuarry: [{ id: "hider", coord: [2, 1] }],
isQuarryActive: () => true,
lures: [[4, 1]],
memory,
difficulty: "smart",
legal: ["left", "right"],
pauseOnOverlapMs: 500,
now: 1000,
}); // null
memory.overlapSince; // 1000
chooseSeekerStep({
matrix,
isWalkable,
self: [2, 1],
visibleQuarry: [{ id: "hider", coord: [2, 1] }],
isQuarryActive: () => true,
lures: [[4, 1]],
memory,
difficulty: "smart",
legal: ["left", "right"],
pauseOnOverlapMs: 500,
now: 1500,
}); // "right"
memory.overlapSince; // 1000, until the seeker is no longer on that quarry
import { chooseSeekerStep, createNpcMemory, walkableUnlessTypes } from "@tamb/gamegrid/npc";
const matrix = [
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
[{ type: "wall" }, { type: "floor" }, { type: "floor" }, { type: "floor" }, { type: "floor" }],
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
];
const memory = createNpcMemory();
memory.lastSeen = [4, 1];
memory.lastSeenId = "hider";
memory.ttl = 3;
const dir = chooseSeekerStep({
matrix,
isWalkable: walkableUnlessTypes(["wall"]),
self: [2, 1],
visibleQuarry: [],
isQuarryActive: () => true,
memory,
difficulty: "normal",
});
// "right"
memory.ttl; // 2
import { chooseSeekerStep, createNpcMemory, walkableUnlessTypes } from "@tamb/gamegrid/npc";
const matrix = [
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
[{ type: "wall" }, { type: "floor" }, { type: "floor" }, { type: "floor" }, { type: "floor" }],
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
];
const memory = createNpcMemory();
memory.lastSeen = [4, 1];
memory.lastSeenId = "hider";
memory.ttl = 3;
const dir = chooseSeekerStep({
matrix,
isWalkable: walkableUnlessTypes(["wall"]),
self: [2, 1],
visibleQuarry: [],
isQuarryActive: () => false,
memory,
difficulty: "normal",
legal: ["right"],
});
// "right". A later fallback. The sighting itself is cleared.
memory.lastSeen; // null
import { chooseSeekerStep, createNpcMemory, walkableUnlessTypes } from "@tamb/gamegrid/npc";
const matrix = [
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
[{ type: "wall" }, { type: "floor" }, { type: "floor" }, { type: "floor" }, { type: "floor" }],
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
];
const memory = createNpcMemory();
const dir = chooseSeekerStep({
matrix,
isWalkable: walkableUnlessTypes(["wall"]),
self: [2, 1],
visibleQuarry: [{ id: "hider", coord: [4, 1] }],
isQuarryActive: () => true,
memory,
difficulty: "smart",
legal: ["left"],
});
// "left". The chase would be "right", which legal does not allow.
memory.lastSeenId; // "hider"
import { chooseSeekerStep, createNpcMemory, walkableUnlessTypes } from "@tamb/gamegrid/npc";
const matrix = [
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
[{ type: "wall" }, { type: "floor" }, { type: "floor" }, { type: "floor" }, { type: "floor" }],
[{ type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }, { type: "wall" }],
];
const memory = createNpcMemory();
memory.lastSeen = [2, 1];
memory.lastSeenId = "hider";
memory.ttl = 4;
memory.heading = "right";
const dir = chooseSeekerStep({
matrix,
isWalkable: walkableUnlessTypes(["wall"]),
self: [2, 1],
visibleQuarry: [],
isQuarryActive: () => true,
memory,
difficulty: "smart",
legal: ["left", "right"],
});
// "right"
memory.heading; // null
memory.investigating; // true
Decide a seeker's next step. Order is fixed: closest visible quarry, nearest lure, last-seen cell and its ring, a coverage sweep, an unvisited neighbor, then a random legal step. Standing on a visible quarry does not hold the cell unless SeekerStepArgs.pauseOnOverlapMs is set. Memory is mutated. Pass the same object next tick.