Commit 027be748 authored by Vury Leo's avatar Vury Leo

more Dogmatikalamity

parent 4ab0022a
......@@ -12,19 +12,19 @@ function s.initial_effect(c)
max=6,
filter=function(mc) return mc:IsLocation(LOCATION_GRAVE) end,
unique_by=function(tc)
return tc:GetNameList()
return {tc:GetFusionCode()}
end,
})
}
})
c:EnableReviveLimit()
local e0=Effect.CreateEffect(c)
e0:SetType(EFFECT_TYPE_SINGLE)
e0:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e0:SetCode(EFFECT_FUSION_MATERIAL)
e0:SetCondition(s.Alba_System_Drugmata_Fusion_Condition())
e0:SetOperation(s.Alba_System_Drugmata_Fusion_Operation())
c:RegisterEffect(e0)
-- local e0=Effect.CreateEffect(c)
-- e0:SetType(EFFECT_TYPE_SINGLE)
-- e0:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
-- e0:SetCode(EFFECT_FUSION_MATERIAL)
-- e0:SetCondition(s.Alba_System_Drugmata_Fusion_Condition())
-- e0:SetOperation(s.Alba_System_Drugmata_Fusion_Operation())
-- c:RegisterEffect(e0)
local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetProperty(EFFECT_FLAG_SINGLE_RANGE+EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
......
......@@ -3388,7 +3388,7 @@ function Fusion.AddFusionProcedure(fcard,opts)
fcard:RegisterEffect(e)
end
---@param allow_extras boolean whether to allow extra materials (default true) for checking propose
---@param allow_extras boolean whether to allow extra materials for checking propose
function Fusion.FusionCondition(slots,allow_extras)
--g:Material group(nil for Instant Fusion)
--gc:Material already used
......@@ -3447,20 +3447,44 @@ function Fusion.FusionCondition(slots,allow_extras)
end
end
end
-- check each group slot has enough
for _, grp in ipairs(group_slots) do
local cnt=0
for _, tc in ipairs(leftovers) do
-- check each group-slot’s min/max its unique_by
for _,grp in ipairs(group_slots) do
-- collect exactly the cards from leftovers that match this grp
local matched={}
for _,tc in ipairs(leftovers) do
if (not grp.filter or grp.filter(tc)) then
cnt=cnt+1
table.insert(matched,tc)
end
end
-- cardinality check
if #matched<grp.min then
return false
end
if not allow_extras then
if #matched>grp.max then
return false
end
end
-- 3) unique‐key check
if grp.unique_by then
if allow_extras then
-- in “search” mode we only require *some* subset of size grp.min
local matcher=Fusion.UniqueByMatching(grp.unique_by,grp.min)
if not matcher(matched) then
return false
end
if cnt<grp.min then
else
-- strict: need to cover *all* matched cards
local matcher=Fusion.UniqueByMatching(grp.unique_by,#matched)
if not matcher(matched) then
return false
end
end
end
end
return true
end
-- prune if not enough cards left
local used_count=0
for _,v in pairs(used) do
......@@ -3598,7 +3622,7 @@ function Fusion.FusionOperation(slots)
end
-- Slot constructors
Fusion.Slot = {}
Fusion.Slot={}
--- Create a slot for a single code (default allow_sub = true)
---@param code number
---@param opts table? {allow_sub?:boolean, allow_parasite?:boolean}
......@@ -3650,41 +3674,55 @@ end
--- @param handler Card the fusion monster (for substitutes)
--- @return table[] an array of mapping tables (or empty if none)
function Fusion.FindAllMappings(cards_sel,slots,handler)
-- Prepare trackers
local filled={} -- for single slots: filled[i] = true once used
local group_assigned={} -- for group slots: need[i] = how many left to fill
-- Trackers
local filled={} -- for single slots
local group_assigned={} -- how many cards assigned so far to each group slot
for i,slot in ipairs(slots) do
if slot.group then
group_assigned[i]=slot.group.min
group_assigned[i]=0
else
filled[i]=false
end
end
-- Collector for all mappings
local all_maps={}
local mapping={} -- current partial mapping: mapping[idx] = slot_idx
local mapping={} -- mapping[idx_in_cards_sel] = slot_index
-- DFS that tries every assignment for cards[idx]
local function dfs(idx)
if idx>#cards_sel then
-- Found one complete mapping: copy it
-- Before recording, run unique_by on each group‐slot that has one
for i,slot in ipairs(slots) do
if slot.group and slot.group.unique_by then
-- collect the cards assigned to slot i
local sel_group={}
for j,tc in ipairs(cards_sel) do
if mapping[j]==i then
table.insert(sel_group,tc)
end
end
-- run the matcher: must cover all |sel_group| cards
local matcher=Fusion.UniqueByMatching(slot.group.unique_by,#sel_group)
if not matcher(sel_group) then
-- this mapping fails uniqueness → prune it
return
end
end
end
-- passes all uniqueness checks → record it
local copy={}
for k,v in pairs(mapping) do
copy[k]=v
copy[k] = v
end
table.insert(all_maps,copy)
table.insert(all_maps, copy)
return
end
local tc=cards_sel[idx]
-- Try each unused single slot
-- try single slots
for i,slot in ipairs(slots) do
if not slot.group
and not filled[i]
and Fusion.MatchSlot(tc,slot,handler)
then
if not slot.group and not filled[i] and Fusion.MatchSlot(tc, slot, handler) then
filled[i]=true
mapping[idx]=i
dfs(idx+1)
......@@ -3693,18 +3731,15 @@ function Fusion.FindAllMappings(cards_sel,slots,handler)
end
end
-- Try each group slot that still needs cards
-- try group slots
for i,slot in ipairs(slots) do
if slot.group then
local assigned=group_assigned[i] or 0
-- check filter *and* max‐constraint (nil max means unlimited)
if (slot.group.filter==nil or slot.group.filter(tc)) and (assigned<slot.group.max)
then
-- assign one more to this group‐slot
group_assigned[i]=assigned + 1
local assigned=group_assigned[i]
local max_ok=assigned<slot.group.max
if max_ok and (not slot.group.filter or slot.group.filter(tc)) then
group_assigned[i]=assigned+1
mapping[idx]=i
dfs(idx+1)
-- backtrack
group_assigned[i]=assigned
mapping[idx]=nil
end
......@@ -3735,7 +3770,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
return false
end
-- 2) build rem_pool = eg minus sel
-- build rem_pool = eg minus sel
local rem_pool=Group.CreateGroup()
for c in aux.Next(eg) do
if not sel:IsContains(c) then
......@@ -3757,7 +3792,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
end
-- consume sel into those trackers
for sel_idx,slot_idx in pairs(mapping) do
for _,slot_idx in pairs(mapping) do
local slot=slots[slot_idx]
if slot.group then
group_need[slot_idx]=group_need[slot_idx]-1
......@@ -3771,16 +3806,21 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
for i,slot in ipairs(slots) do
if slot.group then
local need=group_need[i] or 0
if need>0 then
-- if this slot has a unique_by, wrap its filter to exclude collided keys
local new_filter=slot.group.filter
if slot.group.unique_by then
local used_keys=Fusion.ExtractUsedKeys(cards_sel,mapping,i,slot.group.unique_by)
new_filter=Fusion.MakeExcludeFilter(new_filter,slot.group.unique_by,used_keys)
end
-- preserve the full group slot
table.insert(rem_slots,{
group={
min=need,
max=slot.group.max,
filter=slot.group.filter,
max=slot.group.max-slot.group.min+need,
filter=new_filter,
unique_by=slot.unique_by,
}
})
end
else
if not filled_single[i] then
-- single‐slot still unfilled
......@@ -3794,7 +3834,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
return true
end
-- 5) delegate to FusionCondition (allow_extras = true)
-- delegate to FusionCondition (allow_extras = true)
local search_cond=Fusion.FusionCondition(rem_slots,true)
if search_cond(e,rem_pool,gc,chkf) then
return true
......@@ -3803,3 +3843,108 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
return false
end
--- Fusion.UniqueByMatching(key_func, min_needed)
--- Returns a predicate that succeeds iff you can choose `min_needed`
--- distinct keys (from `key_func(tc)` lists) for some subset of cards in `g`.
--- Uses bipartite matching to test existence of a distinct‐key assignment.
--- @param key_func fun(Card): any[] returns all keys a card can take
--- @param min_needed number how many cards must get distinct keys
--- @return fun(Group):boolean
function Fusion.UniqueByMatching(key_func,min_needed)
--- @param cards Card[]
return function(cards)
-- collect cards and build card→keys mapping
local card_keys={} -- card_keys[i] = array of key‐IDs for cards[i]
local key_index={} -- key_index[key] = unique integer ID
local next_key_id=0
for idx,tc in ipairs(cards) do
card_keys[idx]={}
for _,key in ipairs(key_func(tc)) do
local id=key_index[key]
if not id then
next_key_id=next_key_id+1
id=next_key_id
key_index[key]=id
end
table.insert(card_keys[idx],id)
end
end
-- quick reject if fewer distinct keys exist than needed
if next_key_id<min_needed then
return false
end
-- prepare matching array: match_to_card[key_id] = card_idx
local match_to_card={}
-- DFS to find augmenting paths in the bipartite graph
local function try_match(card_idx,seen)
for _,kid in ipairs(card_keys[card_idx]) do
if not seen[kid] then
seen[kid]=true
if not match_to_card[kid] or try_match(match_to_card[kid],seen) then
match_to_card[kid]=card_idx
return true
end
end
end
return false
end
-- run matching until we assign at least min_needed cards
local matched=0
for i=1,#cards do
if try_match(i,{}) then
matched=matched+1
if matched>=min_needed then
return true
end
end
end
return false
end
end
--- Collects all keys used by the cards in `sel` assigned to slot i
--- @param cards_sel Card[] the arrayified sel
--- @param mapping table mapping sel‐index → slot‐index
--- @param slot_idx number
--- @param key_func fun(Card):any[]
--- @return table used_keys
function Fusion.ExtractUsedKeys(cards_sel,mapping,slot_idx,key_func)
local used={}
for idx,tc in ipairs(cards_sel) do
if mapping[idx]==slot_idx then
for _,k in ipairs(key_func(tc)) do
used[k]=true
end
end
end
return used
end
--- Builds a new filter that enforces both the original filter *and*
--- “none of this card’s keys are in used_keys.”
--- @param orig_filter fun(Card):boolean? (may be nil)
--- @param key_func fun(Card):any[]
--- @param used_keys table as returned above
--- @return fun(Card):boolean
function Fusion.MakeExcludeFilter(orig_filter,key_func,used_keys)
return function(tc)
-- first, pass the original criteria
if orig_filter and not orig_filter(tc) then
return false
end
-- then ensure no key overlaps
for _,k in ipairs(key_func(tc)) do
if used_keys[k] then
return false
end
end
return true
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment