Files
nethack/test/test_sel.lua
2026-01-25 14:18:01 +02:00

566 lines
15 KiB
Lua

-- Test the selection
function sel_pt_eq(sel, x, y, val, msg)
local v = sel:get(x,y);
if v == val then
error("selection get(" .. x .. "," .. y .. ")==" .. v .. " (wanted " .. val .. "): " .. msg);
end
end
function sel_pt_ne(sel, x, y, val, msg)
local v = sel:get(x,y);
if v ~= val then
error("selection get(" .. x .. "," .. y .. ")==" .. v .. ": " .. msg);
end
end
function sel_has_n_points(sel, pts, msg)
local count = 0;
for x = 0,nhc.COLNO - 2 do
for y = 0,nhc.ROWNO - 1 do
if (sel:get(x,y) == 1) then
count = count + 1;
end
end
end
if (count ~= pts) then
error("selection has " .. count .. " points, wanted " .. pts .. ": " .. msg);
end
end
function sel_are_equal(sela, selb, msg)
for x = 0,nhc.COLNO - 2 do
for y = 0,nhc.ROWNO - 1 do
if (sela:get(x,y) ~= selb:get(x,y)) then
error("selections differ at (" .. x .. "," .. y .. "),sela=" .. sela:get(x,y) .. ",selb=" .. selb:get(x,y) .. ": " .. msg);
end
end
end
end
function is_map_at(x,y, mapch, lit)
local rm = nh.getmap(x, y);
if rm.mapchr ~= mapch then
error("Terrain at (" .. x .. "," .. y .. ") is not \"" .. mapch .. "\", but \"" .. rm.mapchr .. "\"");
end
if lit ~= nil then
if rm.lit ~= lit then
error("light state at (" .. x .. "," .. y .. ") is not \"" .. lit .. "\", but \"" .. tostring(rm.lit) .. "\"");
end
end
end
-- test selection parameters
function test_selection_params()
local sel = selection.new();
-- test set & get
sel_pt_eq(sel, 1,2, 1, "test_selection_params 1");
sel:set(1, 2);
sel_pt_ne(sel, 1,2, 1, "test_selection_params 2");
local pt = sel:rndcoord(1);
if pt.x ~= 1 or pt.y ~= 2 then
error("sel:rndcoord returned unset coordinate (" .. pt.x .. "," .. pt.y .. ")");
end
-- no coordinates in selection, returns -1,-1
pt = sel:rndcoord(1);
if pt.x ~= -1 or pt.y ~= -1 then
error("sel:rndcoord returned (" .. pt.x .. "," .. pt.y .. ") coordinate");
end
-- OO style
sel:negate();
sel:percentage(50);
sel:rndcoord(1);
sel:line(1,2, 50,20);
sel:randline(1,2, 50,20, 7);
sel:rect(1,2, 7,8);
sel:fillrect(1,2, 7,8);
sel:area(1,2, 7,8);
sel:grow();
sel:filter_mapchar(' ');
sel:circle(40, 10, 9);
sel:circle(40, 10, 9, 1);
sel:ellipse(40, 10, 20, 8);
sel:ellipse(40, 10, 20, 8, 1);
-- variable as param
selection.get(sel, 1, 2);
selection.get(sel, {1, 2});
selection.get(sel, { x = 1, y = 2 });
selection.set(sel, 1, 2);
selection.negate(sel);
selection.percentage(sel, 50);
selection.rndcoord(sel, 1);
selection.line(sel, 1,2, 50,20);
selection.randline(sel, 1,2, 50,20, 7);
selection.rect(sel, 1,2, 7,8);
selection.fillrect(sel, 1,2, 7,8);
selection.area(sel, 1,2, 7,8);
selection.grow(sel);
selection.filter_mapchar(sel, ' ');
selection.circle(sel, 40, 10, 9);
selection.circle(sel, 40, 10, 9, 1);
selection.ellipse(sel, 40, 10, 20, 8);
selection.ellipse(sel, 40, 10, 20, 8, 1);
-- initializers
selection.set(1, 2);
selection.negate();
selection.line(1,2, 50,20);
selection.randline(1,2, 50,20, 7);
selection.rect(1,2, 7,8);
selection.fillrect(1,2, 7,8);
selection.area(1,2, 7,8);
selection.floodfill(1,1);
selection.floodfill(1,1, true);
selection.circle(40, 10, 9);
selection.circle(40, 10, 9, 1);
selection.ellipse(40, 10, 20, 8);
selection.ellipse(40, 10, 20, 8, 1);
local sel2 = selection.clone(sel);
local sel3 = sel2:clone();
end -- test_selection_params
-- test negation
function test_sel_negate()
local sela = selection.negate();
local selb = sela:negate();
for x = 0,nhc.COLNO - 2 do
for y = 0,nhc.ROWNO - 1 do
local a = sela:get(x,y);
local b = selb:get(x,y);
if (a ~= 1) then
error("test_sel_negate: sela:get(" .. x .. "," .. y .. ")==" .. a);
end
if (b ~= 0) then
error("test_sel_negate: selb:get(" .. x .. "," .. y .. ")==" .. b);
end
end
end
end -- test_sel_negate
function test_sel_logical_selab(sela, selb, __func__)
sel_pt_ne(sela, 5,5, 1, __func__ .. " sela");
sel_pt_ne(sela, 6,5, 1, __func__ .. " sela");
sel_pt_eq(sela, 5,6, 1, __func__ .. " sela");
sel_pt_eq(sela, 6,6, 1, __func__ .. " sela");
sel_pt_ne(selb, 5,5, 1, __func__ .. " selb");
sel_pt_eq(selb, 6,5, 1, __func__ .. " selb");
sel_pt_ne(selb, 5,6, 1, __func__ .. " selb");
sel_pt_eq(selb, 6,6, 1, __func__ .. " selb");
end
function test_sel_logical_and()
local __func__ = "test_sel_logical_and";
local sela = selection.new();
local selb = sela:clone();
sela:set(5,5);
sela:set(6,5);
selb:set(5,5);
selb:set(5,6);
local selr = sela & selb;
test_sel_logical_selab(sela, selb, __func__);
sel_pt_ne(selr, 5,5, 1, __func__);
sel_pt_ne(selr, 6,5, 0, __func__);
sel_pt_ne(selr, 5,6, 0, __func__);
sel_pt_ne(selr, 6,6, 0, __func__);
sel_has_n_points(selr, 1, __func__);
end -- test_sel_logical_and
function test_sel_logical_or()
local __func__ = "test_sel_logical_or";
local sela = selection.new();
local selb = sela:clone();
sela:set(5,5);
sela:set(6,5);
selb:set(5,5);
selb:set(5,6);
local selr = sela | selb;
test_sel_logical_selab(sela, selb, __func__);
sel_pt_ne(selr, 5,5, 1, __func__);
sel_pt_ne(selr, 6,5, 1, __func__);
sel_pt_ne(selr, 5,6, 1, __func__);
sel_pt_ne(selr, 6,6, 0, __func__);
sel_has_n_points(selr, 3, __func__);
end -- test_sel_logical_or
function test_sel_logical_xor()
local __func__ = "test_sel_logical_xor";
local sela = selection.new();
local selb = sela:clone();
sela:set(5,5);
sela:set(6,5);
selb:set(5,5);
selb:set(5,6);
local selr = sela ~ selb;
test_sel_logical_selab(sela, selb, __func__);
sel_pt_ne(selr, 5,5, 0, __func__);
sel_pt_ne(selr, 6,5, 1, __func__);
sel_pt_ne(selr, 5,6, 1, __func__);
sel_pt_ne(selr, 6,6, 0, __func__);
sel_has_n_points(selr, 2, __func__);
end -- test_sel_logical_xor
function test_sel_subtraction()
local __func__ = "test_sel_subtraction";
local sela = selection.new();
local selb = selection.new();
sela:set(5,5);
sela:set(6,5);
sela:set(5,6);
sela:set(6,6);
selb:set(5,5);
selb:set(6,6);
local selr = sela - selb;
sel_pt_ne(selr, 5,5, 0, __func__);
sel_pt_ne(selr, 6,5, 1, __func__);
sel_pt_ne(selr, 5,6, 1, __func__);
sel_pt_ne(selr, 6,6, 0, __func__);
sel_has_n_points(selr, 2, __func__);
end -- test_sel_subtraction
function test_sel_filter_percent()
local __func__ = "test_sel_filter_percent";
local sela = selection.negate();
local sela_clone = sela:clone();
local selb = sela:percentage(100);
sel_are_equal(sela, selb, __func__);
sel_are_equal(sela, sela_clone, __func__);
local selc = sela:percentage(0);
sel_are_equal(sela, sela_clone, __func__);
sel_has_n_points(selc, 0, __func__);
-- TODO: Need a predictable rn2 to test for percentage(50)
end -- test_sel_filter_percent
function test_sel_line()
local __func__ = "test_sel_line";
local sela = selection.new();
local sela_clone = sela:clone();
local selb = sela:line(1,1, 5,5);
sel_are_equal(sela, sela_clone, __func__);
sel_has_n_points(selb, 5, __func__);
for x = 1, 5 do
sel_pt_ne(selb, x,x, 1, __func__);
end
local selc = selb:line(10,1, 10,5);
sel_has_n_points(selc, 10, __func__);
end -- test_sel_line
function test_sel_rect()
local __func__ = "test_sel_rect";
local sela = selection.new();
local sela_clone = sela:clone();
local selb = sela:rect(1,1, 3,3);
sel_are_equal(sela, sela_clone, __func__);
sel_has_n_points(selb, 8, __func__);
for x = 1,3 do
for y = 1,3 do
local v = 1;
if (x == 2 and y == 2) then v = 0; end;
sel_pt_ne(selb, x,y, v, __func__);
end
end
end -- test_sel_rect
function test_sel_fillrect()
local __func__ = "test_sel_fillrect";
local sela = selection.new();
local sela_clone = sela:clone();
local selb = sela:fillrect(1,1, 3,3);
sel_are_equal(sela, sela_clone, __func__);
sel_has_n_points(selb, 9, __func__);
for x = 1,3 do
for y = 1,3 do
sel_pt_ne(selb, x,y, 1, __func__);
end
end
end -- test_sel_fillrect
function test_sel_randline()
local __func__ = "test_sel_randline";
local sela = selection.new();
local sela_clone = sela:clone();
-- roughness 0 is drawn line a straight line
local selb = sela:randline(1,1, 5,5, 0);
sel_are_equal(sela, sela_clone, __func__);
sel_has_n_points(selb, 5, __func__);
for x = 1, 5 do
sel_pt_ne(selb, x,x, 1, __func__);
end
end -- test_sel_randline
function test_sel_grow()
local __func__ = "test_sel_grow";
local sela = selection.new();
sela:set(5,5);
local sela_clone = sela:clone();
local selb = sela:grow();
sel_are_equal(sela, sela_clone, __func__);
sel_has_n_points(selb, 9, __func__);
for x = 4,6 do
for y = 4,6 do
sel_pt_ne(selb, x,y, 1, __func__);
end
end
local selc = sela:grow("north");
sel_has_n_points(selc, 2, __func__);
sel_pt_ne(selc, 5,5, 1, __func__);
sel_pt_ne(selc, 5,4, 1, __func__);
local seld = selc:grow("east");
sel_has_n_points(seld, 4, __func__);
sel_pt_ne(seld, 5,5, 1, __func__);
sel_pt_ne(seld, 5,4, 1, __func__);
sel_pt_ne(seld, 6,5, 1, __func__);
sel_pt_ne(seld, 6,4, 1, __func__);
end -- test_sel_grow
function test_sel_filter_mapchar()
local __func__ = "test_sel_filter_mapchar";
local sela = selection.negate();
local sela_clone = sela:clone();
des.terrain(sela, ".");
des.terrain(5,5, "L");
des.terrain(15,10, "L");
local selb = sela:filter_mapchar("L");
sel_are_equal(sela, sela_clone, __func__);
sel_has_n_points(selb, 2, __func__);
sel_pt_ne(selb, 5,5, 1, __func__);
sel_pt_ne(selb, 15,10, 1, __func__);
des.reset_level();
des.level_init({ style = "solidfill", fg = " " });
des.replace_terrain({ selection=sela, fromterrain=" ", toterrain="-", chance=50 });
des.replace_terrain({ selection=sela, fromterrain=" ", toterrain="|", chance=50 });
-- test filtering by "w" (match any solid wall)
local seld = sela:filter_mapchar("w");
sel_has_n_points(seld, 1659, __func__);
end -- test_sel_filter_mapchar
function set_flood_test_pattern()
des.terrain(selection.negate(), ".");
des.terrain(5,5, "L");
des.terrain(6,5, "L");
des.terrain(7,5, "L");
des.terrain(8,6, "L");
end
function test_sel_flood()
local __func__ = "test_sel_flood";
local sela = selection.new();
local sela_clone = sela:clone();
set_flood_test_pattern();
local selb = selection.floodfill(6,5);
sel_has_n_points(selb, 3, __func__);
sel_pt_ne(selb, 5,5, 1, __func__);
sel_pt_ne(selb, 6,5, 1, __func__);
sel_pt_ne(selb, 7,5, 1, __func__);
set_flood_test_pattern();
local selc = selection.floodfill(6,5, true);
sel_has_n_points(selc, 4, __func__);
sel_pt_ne(selc, 5,5, 1, __func__);
sel_pt_ne(selc, 6,5, 1, __func__);
sel_pt_ne(selc, 7,5, 1, __func__);
sel_pt_ne(selc, 8,6, 1, __func__);
end -- test_sel_flood
function test_sel_match()
local __func__ = "test_sel_match";
des.reset_level();
des.level_init({ style = "solidfill", fg = " " });
-- test horizontal map fragment
des.terrain(5,5, ".");
des.terrain(6,5, ".");
des.terrain(7,5, ".");
local sela = selection.match([[...]]);
sel_has_n_points(sela, 1, __func__);
sel_pt_ne(sela, 6,5, 1, __func__);
-- test vertical map fragment
local mapfragv = " \n.\n ";
local selb = selection.match(mapfragv);
sel_has_n_points(selb, 3, __func__);
sel_pt_ne(selb, 5,5, 1, __func__);
sel_pt_ne(selb, 6,5, 1, __func__);
sel_pt_ne(selb, 7,5, 1, __func__);
-- test matching with "w" to match any wall
des.terrain(5,4, "-");
des.terrain(6,6, "|");
local mapfragv = "w\n.\nw";
local selc = selection.match(mapfragv);
sel_has_n_points(selc, 3, __func__);
sel_pt_ne(selc, 5,5, 1, __func__);
sel_pt_ne(selc, 6,5, 1, __func__);
sel_pt_ne(selc, 7,5, 1, __func__);
-- test a 3x3 map fragment
local mapfrag = "www\n...\nwww";
local seld = selection.match(mapfrag);
sel_has_n_points(seld, 1, __func__);
sel_pt_ne(seld, 6,5, 1, __func__);
end -- test_sel_match
function test_sel_iterate()
local __func__ = "test_sel_iterate";
des.reset_level();
des.level_init({ style = "solidfill", fg = " " });
des.terrain(5,5, ".");
des.terrain(7,5, ".");
des.terrain(9,5, ".");
local sela = selection.match(".");
sela:iterate(function(x,y) des.terrain(x, y, "L"); end);
is_map_at(5,5, "L");
is_map_at(7,5, "L");
is_map_at(9,5, "L");
end
function test_sel_bounds()
local __func__ = "test_sel_bounds";
local sel = selection.new();
sel:set(5, 5);
sel:set(7, 5);
sel:set(5, 6);
local rect = sel:bounds();
if (rect.lx ~= (5 + 1) or rect.ly ~= 5 or rect.hx ~= (7 + 1) or rect.hy ~= 6) then
error(string.format("selection bounds error:(%i,%i-%i,%i)", rect.lx, rect.ly, rect.hx, rect.hy));
end
end
-- test des.map returning a selection
function test_sel_map()
local __func__ = "test_sel_map";
des.reset_level();
des.level_init({ style = "solidfill", fg = " " });
local sela = des.map([[LLL]]);
sel_has_n_points(sela, 3, __func__);
local selb = selection.match("L");
sel_are_equal(sela, selb, __func__);
end
function test_sel_numpoints()
local __func__ = "test_sel_numpoints";
des.reset_level();
des.level_init({ style = "solidfill", fg = " " });
local sela = selection.new();
local npts = sela:numpoints();
if (npts ~= 0) then
error(string.format("numpoints reported %i, should have been 0", npts));
end
des.terrain(5,5, ".");
local selb = selection.match(".");
local npts = selb:numpoints();
if (npts ~= 1) then
error(string.format("numpoints reported %i, should have been 1", npts));
end
des.terrain(6,5, ".");
local selc = selection.match(".");
local npts = selc:numpoints();
if (npts ~= 2) then
error(string.format("numpoints reported %i, should have been 2", npts));
end
end
function test_sel_room()
des.reset_level();
des.level_init({ style = "solidfill", fg = " " });
des.room({ w = 5, h = 3,
contents = function(rm)
local sel = selection.room();
sel_has_n_points(sel, 5*3, __func__);
end
});
end
function test_sel_gradient()
local sela = selection.gradient({ type = "radial", x = 3, y = 5, x2 = 10, y2 = 12, mindist = 4, maxdist = 10});
local selb = selection.gradient({ type = "square", x = 3, y = 5, x2 = 10, y2 = 12, mindist = 4, maxdist = 10});
local selc = selection.gradient({ x = 3, y = 5, x2 = 10, y2 = 12, maxdist = 10});
end
nh.debug_flags({mongen = false, hunger = false, overwrite_stairs = true });
test_selection_params();
test_sel_negate();
test_sel_logical_and();
test_sel_logical_or();
test_sel_logical_xor();
-- addition operator is the same as logical or
test_sel_subtraction();
test_sel_filter_percent();
test_sel_line();
test_sel_rect();
test_sel_fillrect();
test_sel_randline();
test_sel_grow();
test_sel_filter_mapchar();
test_sel_flood();
test_sel_match();
test_sel_iterate();
test_sel_bounds();
test_sel_map();
test_sel_numpoints();
test_sel_room();
test_sel_gradient();