mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
115 lines
3.6 KiB
Lua
115 lines
3.6 KiB
Lua
-- Ice-aware Bot:slideRest / planPath. Self-contained:
|
|
-- luajit tests/gen2_ice_pathfind_test.lua
|
|
--
|
|
-- The engine half (CheckForced latch) lives in gen2_world_test.lua. This file
|
|
-- proves the planner's graph is over REST positions: a press on ice ends where
|
|
-- the slide stops, so a cell the player would skate past is not a node.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local S = require("tests.harness").suite("gen2 ice pathfind")
|
|
local check, eq = S.check, S.eq
|
|
|
|
local Permissions = require("src.world.gen2.Permissions")
|
|
local Bot = dofile("tests/drivers/gold/bot.lua")
|
|
local A = Bot.adapter
|
|
|
|
local COLL_FLOOR, COLL_ICE, COLL_WALL = 0x00, 0x23, 0x07
|
|
|
|
local function fakeMap(cells)
|
|
return {
|
|
id = "ICE_TEST",
|
|
inBounds = function(_, x, y)
|
|
return x >= 0 and y >= 0 and x < 20 and y < 20
|
|
end,
|
|
cellCollision = function(_, x, y)
|
|
return cells[y * 100 + x] or COLL_FLOOR
|
|
end,
|
|
}
|
|
end
|
|
|
|
-- A bot stub that only needs passable / slideRest / planPath / wallCost.
|
|
local function stubBot(map, sx, sy, cells)
|
|
local g = { _map = map, _x = sx, _y = sy }
|
|
local bot = setmetatable({
|
|
g = g,
|
|
walls = {},
|
|
surfKnown = false,
|
|
}, Bot)
|
|
-- Adapter seams the planner reads. Keep them on A so the real methods run.
|
|
local realMap, realPos, realWalkable, realIsIce, realIsWater, realNpcAt,
|
|
realIsWarp, realSurfing =
|
|
A.map, A.pos, A.walkable, A.isIce, A.isWater, A.npcAt, A.isWarpTile, A.surfing
|
|
A.map = function() return map end
|
|
A.pos = function() return g._x, g._y end
|
|
A.mapId = function() return map.id end
|
|
A.walkable = function(_, m, x, y)
|
|
if not m:inBounds(x, y) then return false end
|
|
return Permissions.isWalkable(m:cellCollision(x, y))
|
|
end
|
|
A.isIce = function(m, x, y)
|
|
return Permissions.isIce(m:cellCollision(x, y))
|
|
end
|
|
A.isWater = function() return false end
|
|
A.npcAt = function() return nil end
|
|
A.isWarpTile = function() return false end
|
|
A.surfing = function() return false end
|
|
bot._restore = function()
|
|
A.map, A.pos, A.walkable, A.isIce, A.isWater, A.npcAt, A.isWarpTile, A.surfing =
|
|
realMap, realPos, realWalkable, realIsIce, realIsWater, realNpcAt,
|
|
realIsWarp, realSurfing
|
|
end
|
|
return bot
|
|
end
|
|
|
|
-- Corridor of ice ending at a wall: press right from floor rests on the last ice.
|
|
do
|
|
local cells = {
|
|
[5 * 100 + 3] = COLL_ICE,
|
|
[5 * 100 + 4] = COLL_ICE,
|
|
[5 * 100 + 5] = COLL_ICE,
|
|
[5 * 100 + 6] = COLL_WALL,
|
|
}
|
|
local map = fakeMap(cells)
|
|
local bot = stubBot(map, 2, 5)
|
|
local rx, ry, steps = bot:slideRest(map, 2, 5, "right")
|
|
eq(rx, 5, "slideRest stops on the last ice cell")
|
|
eq(ry, 5, "same row")
|
|
eq(steps, 3, "three cells of travel")
|
|
check(bot:slideRest(map, 5, 5, "right") == nil,
|
|
"pressing into the wall from the rest cell is no edge")
|
|
bot._restore()
|
|
end
|
|
|
|
-- Mid-corridor ice is not a rest node: planPath to it must fail.
|
|
do
|
|
local cells = {
|
|
[5 * 100 + 3] = COLL_ICE,
|
|
[5 * 100 + 4] = COLL_ICE,
|
|
[5 * 100 + 5] = COLL_ICE,
|
|
[5 * 100 + 6] = COLL_WALL,
|
|
}
|
|
local map = fakeMap(cells)
|
|
local bot = stubBot(map, 2, 5)
|
|
check(bot:planPath(4, 5) == nil,
|
|
"a cell the slide skates past is unreachable as a rest")
|
|
local path = bot:planPath(5, 5)
|
|
check(path ~= nil, "the rest against the wall is reachable")
|
|
eq(#path, 1, "one press")
|
|
eq(path[1], "right", "to the east")
|
|
bot._restore()
|
|
end
|
|
|
|
-- Off ice, planPath is still ordinary adjacency.
|
|
do
|
|
local map = fakeMap({})
|
|
local bot = stubBot(map, 2, 5)
|
|
local path = bot:planPath(4, 5)
|
|
check(path ~= nil, "dry floor still paths")
|
|
eq(#path, 2, "two single-cell presses")
|
|
eq(path[1], "right", "first step")
|
|
eq(path[2], "right", "second step")
|
|
bot._restore()
|
|
end
|
|
|
|
S.finish()
|