diff options
author | sanine <sanine.not@pm.me> | 2023-03-14 22:22:20 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2023-03-14 22:22:20 -0500 |
commit | 7516044247663dabccc7db110703cfcf8545d95f (patch) | |
tree | 77b06170bdafad99e34a22447568fde557611b15 | |
parent | 344d6e68bee7f286f7c4b4b25518367c595b4619 (diff) |
add ecs.Filter
-rw-r--r-- | honey/ecs.lua | 100 | ||||
-rw-r--r-- | honey/ecs.test.lua | 51 |
2 files changed, 151 insertions, 0 deletions
diff --git a/honey/ecs.lua b/honey/ecs.lua new file mode 100644 index 0000000..ef682b5 --- /dev/null +++ b/honey/ecs.lua @@ -0,0 +1,100 @@ +local module = {} +setmetatable(module, {__index=_G}) +setfenv(1, module) + + +--===== filters =====-- + + +Filter = {} + +-- base filter creation +function Filter.new(_, operation, tbl) + local self = {} + self.keys = {} + self.filters = {} + self.op = operation + + for _, v in ipairs(tbl) do + if type(v) == "function" then + table.insert(self.filters, v) + elseif type(v) == "string" then + table.insert(self.keys, v) + end + end + + return function(entity) + return Filter.check(self, entity) + end +end +setmetatable(Filter, {__call=Filter.new}) + + +-- base filter checking +function Filter.check(self, entity) + local funcname = "check" .. self.op + return Filter[funcname](self, entity) +end + + +-- AND filter (all keys and subfilters must match) +function Filter.AND(tbl) + return Filter("AND", tbl) +end +function Filter.checkAND(self, entity) + for _, subfilter in ipairs(self.filters) do + if not subfilter(entity) then return false end + end + for _, key in ipairs(self.keys) do + if entity[key] == nil then return false end + end + return true +end + + +-- OR filter (at least one key or subfilter must match) +function Filter.OR(tbl) + return Filter("OR", tbl) +end +function Filter.checkOR(self, entity) + for _, subfilter in ipairs(self.filters) do + if subfilter(entity) then return true end + end + for _, key in ipairs(self.keys) do + if entity[key] ~= nil then return true end + end + return false +end + + +-- NAND filter (at least one key or subfilter must NOT match) +function Filter.NAND(tbl) + return Filter("NAND", tbl) +end +function Filter.checkNAND(self, entity) + for _, subfilter in ipairs(self.filters) do + if not subfilter(entity) then return true end + end + for _, key in ipairs(self.keys) do + if entity[key] == nil then return true end + end + return false +end + + +-- NOR filter (no keys or subfilters may match) +function Filter.NOR(tbl) + return Filter("NOR", tbl) +end +function Filter.checkNOR(self, entity) + for _, subfilter in ipairs(self.filters) do + if subfilter(entity) then return false end + end + for _, key in ipairs(self.keys) do + if entity[key] ~= nil then return false end + end + return true +end + + +return module diff --git a/honey/ecs.test.lua b/honey/ecs.test.lua new file mode 100644 index 0000000..7814097 --- /dev/null +++ b/honey/ecs.test.lua @@ -0,0 +1,51 @@ +local function test(msg, f) + local success, error = pcall(f) + if success then + print(msg .. "\t\t[OK]") + else + print(msg .. "\t\t[FAIL]") + print(error) + end +end + + +local ecs = require 'ecs' +local Filter = ecs.Filter + + +test("Filter.AND correctly matches basic keys", function() + local filter = Filter.AND{"hello", "world"} + + assert(filter{hello=true} == false) + assert(filter{world=true} == false) + assert(filter{hello=true, world=true} == true) + assert(filter{asm=true, hello=true, world=true} == true) +end) +test("Filter.AND correctly matches subfilters", function() + local subfilter = Filter.AND{"hello"} + local filter = Filter.AND{subfilter, "world"} + + assert(filter{hello=true} == false) + assert(filter{world=true} == false) + assert(filter{hello=true, world=true} == true) + assert(filter{asm=true, hello=true, world=true} == true) +end) + + +test("Filter.OR correctly matches basic keys", function() + local filter = Filter.OR{"hello", "world"} + + assert(filter{hello=true} == true) + assert(filter{world=true} == true) + assert(filter{hello=true, world=true} == true) + assert(filter{asm=true} == false) +end) +test("Filter.OR correctly matches subfilters", function() + local subfilter = Filter.OR{"hello"} + local filter = Filter.OR{subfilter, "world"} + + assert(filter{hello=true} == true) + assert(filter{world=true} == true) + assert(filter{hello=true, world=true} == true) + assert(filter{asm=true} == false) +end) |