借助单元测试修复了exppattern存在的诸多bug
This commit is contained in:
notify 2023-06-24 12:29:20 +08:00 committed by GitHub
parent ecf8ff447a
commit f7f1bb8537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 132 additions and 20 deletions

View File

@ -79,7 +79,7 @@ function Card:initialize(name, suit, number, color)
self.is_derived = true self.is_derived = true
end end
local name_splited = name:split("__") local name_splited = self.name:split("__")
self.trueName = name_splited[#name_splited] self.trueName = name_splited[#name_splited]
if suit == Card.Spade or suit == Card.Club then if suit == Card.Spade or suit == Card.Club then
@ -280,6 +280,29 @@ function Card:getTypeString()
return "notype" return "notype"
end end
local subtype_string_table = {
[Card.SubtypeArmor] = "armor",
[Card.SubtypeWeapon] = "weapon",
[Card.SubtypeTreasure] = "treasure",
[Card.SubtypeDelayedTrick] = "delayed_trick",
[Card.SubtypeDefensiveRide] = "defensive_ride",
[Card.SubtypeOffensiveRide] = "offensive_ride",
}
function Card:getSubtypeString()
local t = self.sub_type
local ret = subtype_string_table[t]
if ret == nil then
if self.type == Card.TypeTrick then
return "normal_trick"
elseif self.type == Card.TypeBasic then
return "basic"
end
else
return ret
end
end
--- 获取卡牌点数并返回点数文字描述仅限A/J/Q/K --- 获取卡牌点数并返回点数文字描述仅限A/J/Q/K
local function getNumberStr(num) local function getNumberStr(num)
if num == 1 then if num == 1 then

View File

@ -32,6 +32,8 @@
---@field public cardType string[] ---@field public cardType string[]
---@field public id integer[] ---@field public id integer[]
-- v0.2.6改动: cardType会被解析为trueName数组和name数组而不是自己单独成立
local numbertable = { local numbertable = {
["A"] = 1, ["A"] = 1,
["J"] = 11, ["J"] = 11,
@ -44,14 +46,34 @@ local placetable = {
[Card.PlayerEquip] = "equip", [Card.PlayerEquip] = "equip",
} }
local card_type_table = {}
local function fillCardTypeTable()
local tmp = {}
for _, cd in ipairs(Fk.cards) do
local t = cd:getTypeString()
local st = cd:getSubtypeString()
local tn = cd.trueName
-- TODO: local n = cd.name
if not tmp[tn] then
card_type_table[t] = card_type_table[t] or {}
card_type_table[st] = card_type_table[st] or {}
table.insertIfNeed(card_type_table[t], tn)
table.insertIfNeed(card_type_table[st], tn)
tmp[tn] = true
end
end
end
local function matchSingleKey(matcher, card, key) local function matchSingleKey(matcher, card, key)
local match = matcher[key] local match = matcher[key]
if not match then return true end if not match then return true end
local val = card[key] local val = card[key]
if key == "suit" then if key == "suit" then
val = card:getSuitString() val = card:getSuitString()
elseif key == "cardType" then -- elseif key == "cardType" then
val = card:getTypeString() -- val = card:getTypeString()
elseif key == "place" then elseif key == "place" then
val = placetable[Fk:currentRoom():getCardArea(card.id)] val = placetable[Fk:currentRoom():getCardArea(card.id)]
if not val then if not val then
@ -90,10 +112,31 @@ local function matchCard(matcher, card)
and matchSingleKey(matcher, card, "suit") and matchSingleKey(matcher, card, "suit")
and matchSingleKey(matcher, card, "place") and matchSingleKey(matcher, card, "place")
and matchSingleKey(matcher, card, "name") and matchSingleKey(matcher, card, "name")
and matchSingleKey(matcher, card, "cardType") -- and matchSingleKey(matcher, card, "cardType")
and matchSingleKey(matcher, card, "id") and matchSingleKey(matcher, card, "id")
end end
local function hasNegIntersection(a, b)
local neg_pass = false
-- 第一次比较: 比较neg和正常值如有不同即认为可以匹配
-- 比如 ^jink 可以匹配 slash,jink
for _, neg in ipairs(a.neg or Util.DummyTable) do
for _, e in ipairs(b) do
if type(neg) == "table" then
neg_pass = not table.contains(neg, e)
else
neg_pass = neg ~= e
end
if neg_pass then return true end
end
end
-- 第二次比较: 比较双方neg
-- 比如 ^jink 可以匹配 ^slash
-- 暂时想不出好方案
end
local function hasIntersection(a, b) local function hasIntersection(a, b)
if a == nil or b == nil then if a == nil or b == nil then
return true return true
@ -109,9 +152,9 @@ local function hasIntersection(a, b)
end end
end end
-- TODO: 判断含有neg的两个matcher local neg_pass = hasNegIntersection(a, b) or hasNegIntersection(b, a)
return false return neg_pass
end end
---@param a Matcher ---@param a Matcher
@ -123,7 +166,7 @@ local function matchMatcher(a, b)
"suit", "suit",
"place", "place",
"name", "name",
"cardType", -- "cardType",
"id", "id",
} }
@ -260,7 +303,27 @@ local function parseMatcher(str)
ret.suit = not table.contains(t[3], ".") and t[3] or nil ret.suit = not table.contains(t[3], ".") and t[3] or nil
ret.place = not table.contains(t[4], ".") and t[4] or nil ret.place = not table.contains(t[4], ".") and t[4] or nil
ret.name = not table.contains(t[5], ".") and t[5] or nil ret.name = not table.contains(t[5], ".") and t[5] or nil
ret.cardType = not table.contains(t[6], ".") and t[6] or nil -- ret.cardType = not table.contains(t[6], ".") and t[6] or nil
if table.empty(card_type_table) then
fillCardTypeTable()
end
for _, ctype in ipairs(t[6]) do
for _, n in ipairs(card_type_table[ctype] or Util.DummyTable) do
if not ret.trueName then ret.trueName = {} end
table.insertIfNeed(ret.trueName, n)
end
end
for _, neg in ipairs(t[6].neg or Util.DummyTable) do
if type(neg) ~= "table" then neg = { neg } end
if not ret.trueName then ret.trueName = {} end
if not ret.trueName.neg then ret.trueName.neg = {} end
local temp = {}
for _, ctype in ipairs(neg) do
table.insertTable(temp, card_type_table[ctype] or Util.DummyTable)
end
table.insert(ret.trueName.neg, temp)
end
if not table.contains(t[7], ".") then if not table.contains(t[7], ".") then
ret.id = parseRawNumTable(t[7]) ret.id = parseRawNumTable(t[7])

View File

@ -250,6 +250,10 @@ function table:assign(targetTbl)
end end
end end
function table.empty(t)
return next(t) == nil
end
-- allow a = "Hello"; a[1] == "H" -- allow a = "Hello"; a[1] == "H"
local str_mt = getmetatable("") local str_mt = getmetatable("")
str_mt.__index = function(str, k) str_mt.__index = function(str, k)

View File

@ -1,22 +1,44 @@
local exp1 = Exppattern:Parse("slash,jink")
local exp2 = Exppattern:Parse("peach,jink")
local exp3 = Exppattern:Parse(".|.|.|.|.|trick")
local exp4 = Exppattern:Parse("peach,ex_nihilo")
local slash = Fk:cloneCard("slash")
TestExppattern = { TestExppattern = {
testMatchExp = function() testMatchExp = function()
assert(exp1:matchExp(exp2)) local exp1 = Exppattern:Parse("slash,jink")
lu.assertTrue(exp1:matchExp("peack,jink"))
end, end,
testEasyMatchCard = function() testEasyMatchCard = function()
assert(exp1:match(slash)) local exp1 = Exppattern:Parse("slash,jink")
assert(not exp2:match(slash)) local exp2 = Exppattern:Parse("peach,jink")
local slash = Fk:cloneCard("slash")
lu.assertTrue(exp1:match(slash))
lu.assertFalse(exp2:match(slash))
end, end,
testMatchWithType = function() testMatchWithType = function()
assert(not exp3:matchExp(exp1)) local exp3 = Exppattern:Parse(".|.|.|.|.|normal_trick")
assert(exp3:matchExp(exp4)) lu.assertFalse(exp3:matchExp("slash,jink"))
lu.assertTrue(exp3:matchExp("peach,ex_nihilo"))
local basic = Exppattern:Parse(".|.|.|.|.|basic")
lu.assertFalse(basic:matchExp("nullification"))
lu.assertTrue(basic:matchExp("slash,vine"))
lu.assertTrue(Exppattern:Parse(".|.|.|.|.|armor"):matchExp("slash,vine"))
end,
testMatchNeg = function()
lu.assertError(function() Exppattern:Parse("^(a,|1)") end)
local not_nul = Exppattern:Parse("^nullification")
local not_slash_jink = Exppattern:Parse("^(slash,jink)")
local not_basic = Exppattern:Parse(".|.|.|.|.|^basic")
local slash_jink = Exppattern:Parse("slash,jink")
local slash = Fk:cloneCard("slash")
lu.assertFalse(not_nul:matchExp("nullification"))
lu.assertTrue(not_basic:matchExp("nullification"))
lu.assertFalse(not_slash_jink:matchExp("jink"))
lu.assertTrue(not_nul:match(slash))
lu.assertFalse(not_slash_jink:match(slash))
lu.assertFalse(not_basic:match(slash))
lu.assertTrue(not_nul:matchExp("peach"))
lu.assertFalse(not_slash_jink:matchExp(not_basic))
lu.assertFalse(slash_jink:matchExp(not_slash_jink))
end, end,
} }