Commit 6c193bc3 authored by Vury Leo's avatar Vury Leo

tuning 白の枢機竜

parent 0d056a5a
...@@ -8,7 +8,26 @@ function s.initial_effect(c) ...@@ -8,7 +8,26 @@ function s.initial_effect(c)
Fusion.Slot.Group({ Fusion.Slot.Group({
min=3, min=3,
max=3, max=3,
unique_by=function(mc) return { mc:GetCode(),mc:GetFusionCode() } end, --- @param mc Card
unique_by=function(mc)
local function dedup_represent(code)
if code==78734254 then
return 17955766
elseif code==13857930 then
return 17732278
end
return code
end
local code=dedup_represent(mc:GetCode())
local res={code}
--- Add Fusion Tag names
for _,eff in ipairs({mc:IsHasEffect(EFFECT_ADD_FUSION_CODE)}) do
local fusion_tag_code=eff:GetValue()
assert(type(fusion_tag_code)=='number')
table.insert(res,dedup_represent(fusion_tag_code))
end
return res
end,
}) })
}, },
mat_filter=s.mat_filter, mat_filter=s.mat_filter,
......
...@@ -9,9 +9,25 @@ function s.initial_effect(c) ...@@ -9,9 +9,25 @@ function s.initial_effect(c)
Fusion.Slot.Group({ -- 6 monsters in your GY with different names Fusion.Slot.Group({ -- 6 monsters in your GY with different names
min=6, min=6,
max=6, max=6,
filter=function(mc) return mc:IsLocation(LOCATION_GRAVE) end, filter=function(mc,tc) return mc:IsLocation(LOCATION_GRAVE) end,
unique_by=function(tc) unique_by=function(mc)
return {tc:GetFusionCode()} local function dedup_represent(code)
if code==78734254 then
return 17955766
elseif code==13857930 then
return 17732278
end
return code
end
local code=dedup_represent(mc:GetCode())
local res={code}
--- Add Fusion Tag names
for _,eff in ipairs({mc:IsHasEffect(EFFECT_ADD_FUSION_CODE)}) do
local fusion_tag_code=eff:GetValue()
assert(type(fusion_tag_code)=='number')
table.insert(res,dedup_represent(fusion_tag_code))
end
return res
end, end,
}) })
} }
......
...@@ -3476,339 +3476,247 @@ end ...@@ -3476,339 +3476,247 @@ end
---@param allow_extras boolean whether to allow extra materials for checking propose ---@param allow_extras boolean whether to allow extra materials for checking propose
function Fusion.BasicCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,selected) function Fusion.BasicCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,selected)
--g:Material group(nil for Instant Fusion)
--gc:Material already used
--chkf: check field, default:PLAYER_NONE
--chkf&0x100: Not fusion summon, can use substitute (Hex-Sealed Fusion)
--chkf&0x200: Not fusion summon, can't use substitute ("Contact Fusion", Neos Fusion)
return function(e,g,gc,chkf) return function(e,g,gc,chkf)
if not g then return false end if not g then return false end
-- array
-- Collect cards and apply global mat_filter
local cards={} local cards={}
for mc in aux.Next(g) do for c in aux.Next(g) do
table.insert(cards,mc) if not mat_filter or mat_filter(c,tc) then
table.insert(cards,c)
end end
-- apply the global mat_filter if present
if mat_filter~=nil then
local tg={}
for _,mc in ipairs(cards) do
if mat_filter(mc,tc) then
table.insert(tg,mc)
end end
end
cards=tg -- Split slots into singles and (at most one) group
end local single_slots={}
if #cards<#slots then return false end local grp
-- split slots
local single_slots, group_slots = {}, {}
for _, slot in ipairs(slots) do for _, slot in ipairs(slots) do
if slot.group then if slot.group then
table.insert(group_slots,slot.group) assert(not grp, "only one group slot supported")
grp=slot.group
else else
table.insert(single_slots,slot) table.insert(single_slots,slot)
end end
end end
-- minimal total count -- Quick minimal‐count check
local total_req=#single_slots local total_min=#single_slots+(grp and grp.min or 0)
for _, grp in ipairs(group_slots) do if #cards<total_min then
total_req=total_req+grp.min end
if g:GetCount()<total_req then
return false return false
end end
-- prepare per-slot lock flags (lock only first matching slot per code or code list) -- Prepare locked flags for substitute materials
local locked_slots={} local locked = {}
if Fusion.LockedCodes then if Fusion.LockedCodes then
for _,code in ipairs(Fusion.LockedCodes) do for _, code in ipairs(Fusion.LockedCodes) do
for idx,slot in ipairs(single_slots) do for i,slot in ipairs(single_slots) do
-- lock slot if its match_code equals code -- direct match_code?
if slot.match_code==code then if slot.match_code==code then
locked_slots[idx]=true locked[i]=true
break break
end end
-- lock slot if it's a multi-code slot containing code -- or match_codes list?
if slot.match_codes then if slot.match_codes then
for _,c in ipairs(slot.match_codes) do for _,c2 in ipairs(slot.match_codes) do
if c==code then if c2==code then
locked_slots[idx]=true locked[i]=true
break break
end end
end end
if locked_slots[idx] then break end if locked[i] then
break
end
end end
end end
end end
end end
-- 5) DFS assign single‐slots
local used={} local used={}
local sub_count=0 local sub_count=0
-- DFS assign slots local function dfs_singles(i)
local function dfs(i)
if i>#single_slots then if i>#single_slots then
-- check group slots on leftovers -- Build base material group (selected + assigned singles)
local mg_base=selected and selected:Clone() or Group.CreateGroup()
for idx,flag in pairs(used) do
if flag then mg_base:AddCard(cards[idx]) end
end
-- Build leftovers list
local leftovers={} local leftovers={}
for idx,mc in ipairs(cards) do for idx, c in ipairs(cards) do
if not used[idx] then if not used[idx] then
table.insert(leftovers,mc) table.insert(leftovers,c)
end
end
-- if strict (no extra), ensure leftover only match group slots
if not allow_extras then
for _,mc in ipairs(leftovers) do
local ok=false
for _,grp in ipairs(group_slots) do
if (not grp.filter or grp.filter(mc)) then
ok=true
break
end
end
if not ok then
return false
end
end end
end end
-- check each group-slot’s min/max its unique_by
for _,grp in ipairs(group_slots) do -- No group slot? Just do final checks
-- collect exactly the cards from leftovers that match this grp if not grp then
local matched={} return Fusion.FinalCheck(e,mg_base,tc,fgoalcheck,chkf)
for _,mc in ipairs(leftovers) do
if (not grp.filter or grp.filter(mc)) then
table.insert(matched,mc)
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 end
-- unique‐key check
if grp.unique_by then -- Group slot exists: branch on allow_extras
if allow_extras then if allow_extras then
-- in “search” mode we only require *some* subset of size grp.min -- search mode: try to find some subset of size grp.min
local matcher=Fusion.UniqueByMatching(grp.unique_by,grp.min) return Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
if not matcher(matched) then
return false
end
else else
-- strict: need to cover *all* matched cards -- strict mode: leftovers must *all* satisfy grp
local matcher=Fusion.UniqueByMatching(grp.unique_by,#matched) return Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
if not matcher(matched) then
return false
end
end end
end end
-- has_same: each fn must overlap
if grp.has_same then
if allow_extras then
-- search-mode: find SOME subset of size grp.min satisfying both unique_by & all has_same
local n,k=#matched,grp.min
local comb,found={},false
local function check_subset() -- Prune if not enough cards remain
local S={} local used_count=0
for _,idx_sub in ipairs(comb) do for _,v in pairs(used) do
table.insert(S,matched[idx_sub]) if v then
end used_count=used_count+1
-- unique_by on S
if grp.unique_by then
local m=Fusion.UniqueByMatching(grp.unique_by,k)
if not m(S) then return false end
end
-- all has_same on S
for _,fn in ipairs(grp.has_same) do
local v0=fn(S[1],e:GetHandler())
if type(v0)=="number" then
local mask=v0
for j=2,#S do
mask=mask&fn(S[j],e:GetHandler())
if mask==0 then return false end
end
else
local common={}
for _, key in ipairs(v0) do common[key] = true end
for j=2,#S do
local next_common = {}
for _,key in ipairs(fn(S[j],e:GetHandler())) do
if common[key] then
next_common[key]=true
end
end
common=next_common
if next(common)==nil then return false end
end
end
end end
-- build mg
local mg=Group.FromCards(table.unpack(S))
-- merge selected
mg:Merge(selected)
-- merge in the DFS‐used cards
for idx,flag in pairs(used) do
if flag then
mg:AddCard(cards[idx])
end end
if (#cards-used_count)<(#single_slots-i+1) then
return false
end end
if fgoalcheck then local slot=single_slots[i]
if not fgoalcheck(mg) then for idx,c in ipairs(cards) do
return false if not used[idx] then
local ok,is_sub=Fusion.MatchSlot(c,slot,tc)
if ok and not (is_sub and locked[i]) then
used[idx]=true
local prev_sub=sub_count
if is_sub then
sub_count=sub_count+1 end
if sub_count<=1 and dfs_singles(i+1) then
return true
end end
used[idx]=false
sub_count=prev_sub
end end
if aux.FCheckAdditional then
if not aux.FCheckAdditional(tc:GetOwner(),mg,tc) then
return false
end end
end end
if aux.FGoalCheckAdditional then
if not aux.FGoalCheckAdditional(tc:GetOwner(),mg,tc) then
return false return false
end end
return dfs_singles(1)
end end
if not aux.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_F)(mg) then end
return false
end -- Final, post‐fusion checks (common to both modes)
-- ensure there's at least one free Monster Zone if chkf requests a field-checked summon function Fusion.FinalCheck(e,mg,tc,fgoalcheck,chkf)
if chkf&0xf~=PLAYER_NONE then if fgoalcheck and not fgoalcheck(mg) then return false end
if aux.FCheckAdditional and not aux.FCheckAdditional(tc:GetOwner(),mg,tc) then return false end
if aux.FGoalCheckAdditional and not aux.FGoalCheckAdditional(tc:GetOwner(),mg,tc) then return false end
if not aux.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_F)(mg) then return false end
if (chkf&0xf)~=PLAYER_NONE then
local tp=chkf&0xf local tp=chkf&0xf
if Duel.GetLocationCountFromEx(tp,tp,mg,tc)<=0 then if Duel.GetLocationCountFromEx(tp,tp,mg,tc)<=0 then
return false return false
end end
end end
return true return true
end end
local function dfs_comb(start)
if found then return end
if #comb==k then
if check_subset() then found = true end
return
end
for idx=start,n do
table.insert(comb,idx)
dfs_comb(idx+1)
table.remove(comb)
if found then return end
end
end
dfs_comb(1) -- Strict mode: *all* leftovers must fit grp, then final check
if not found then return false end function Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
-- filter leftovers by grp.filter
local matched={}
for _,c in ipairs(leftovers) do
if not grp.filter or grp.filter(c,tc) then
table.insert(matched,c)
else else
for _,fn in ipairs(grp.has_same) do
local v0=fn(matched[1],e:GetHandler())
if type(v0)=="number" then
-- bitmask path
local common_mask=v0
for j=2,#matched do
common_mask=common_mask&fn(matched[j],e:GetHandler())
if common_mask==0 then
return false return false
end end
end end
elseif type(v0)=="table" then -- cardinality
-- list-of-keys path if #matched<grp.min or #matched>grp.max then
local common={}
for _,k in ipairs(v0) do
common[k]=true
end
for j=2,#matched do
local next_common={}
for _, k in ipairs(fn(matched[j],e:GetHandler())) do
if common[k] then
next_common[k]=true
end
end
common=next_common
if next(common)==nil then
return false
end
end
else
error("unsupported return type of group.has_same")
return false return false
end end
end -- has_same on full matched
end if grp.has_same and not Fusion.CheckHasSame(grp,Group.FromCards(table.unpack(matched)),e) then
end
end
-- build mg
local mg=selected and selected:Clone() or Group.CreateGroup()
-- merge in the DFS‐used cards
for idx,flag in pairs(used) do
if flag then
mg:AddCard(cards[idx])
end
end
if fgoalcheck then
if not fgoalcheck(mg) then
return false return false
end end
end -- unique_by on full matched
if aux.FCheckAdditional then if grp.unique_by then
if not aux.FCheckAdditional(tc:GetOwner(),mg,tc) then local matcher=Fusion.UniqueByMatching(grp.unique_by,#matched)
if not matcher(matched) then
return false return false
end end
end end
if aux.FGoalCheckAdditional then -- merge and final
if not aux.FGoalCheckAdditional(tc:GetOwner(),mg,tc) then local mg=mg_base:Clone()
return false for _,c in ipairs(matched) do mg:AddCard(c) end
return Fusion.FinalCheck(e,mg,tc,fgoalcheck,chkf)
end
-- Search mode: find *some* size‐grp.min subset that passes
function Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
-- filter leftovers by grp.filter
local matched={}
for _,c in ipairs(leftovers) do
if not grp.filter or grp.filter(c,tc) then
table.insert(matched,c)
end end
end end
if not aux.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_F)(mg) then if #matched<grp.min then return false end
local comb={}
local function dfs_comb(start,depth)
if depth>grp.min then
-- subset built in comb[1..grp.min]
local subG=Group.FromCards(table.unpack(comb))
-- has_same
if grp.has_same and not Fusion.CheckHasSame(grp,subG,e) then
return false return false
end end
-- ensure there's at least one free Monster Zone if chkf requests a field-checked summon -- unique_by
if chkf&0xf~=PLAYER_NONE then if grp.unique_by then
local tp=chkf&0xf local matcher=Fusion.UniqueByMatching(grp.unique_by,grp.min)
if Duel.GetLocationCountFromEx(tp,tp,mg,tc)<=0 then if not matcher(comb) then
return false return false
end end
end end
return true -- merge & final
local mg=mg_base:Clone()
mg:Merge(subG)
return Fusion.FinalCheck(e,mg,tc,fgoalcheck,chkf)
end end
-- prune if not enough cards left for i=start,#matched-(grp.min-depth)+1 do
local used_count=0 comb[depth]=matched[i]
for _,v in pairs(used) do if dfs_comb(i+1,depth+1) then
if v then return true
used_count=used_count+1
end end
end end
if (#cards-used_count)<(#single_slots-i+1) then
return false return false
end end
-- try each card
local slot=single_slots[i] return dfs_comb(1,1)
for idx,mc in ipairs(cards) do end
if not used[idx] then
local match,is_sub=Fusion.MatchSlot(mc,slot,tc) -- Shared has_same checker (bitmask or key‐list)
if match==true then function Fusion.CheckHasSame(grp,group_obj,e)
-- skip sub material if slot is locked local cards={}
if not (is_sub and locked_slots[i]) then for c in aux.Next(group_obj) do table.insert(cards,c) end
-- commit material for _,fn in ipairs(grp.has_same) do
used[idx]=true local v0=fn(cards[1],e:GetHandler())
local prev_sub=sub_count if type(v0)=="number" then
if is_sub then sub_count=sub_count+1 end local mask=v0
if sub_count<=1 and dfs(i+1) then for j=2,#cards do
return true mask=mask&fn(cards[j],e:GetHandler())
end if mask==0 then return false end
-- backtrack
used[idx]=false
sub_count=prev_sub
end
end end
else
local common={}
for _,k in ipairs(v0) do common[k]=true end
for j=2,#cards do
local nextc={}
for _,k in ipairs(fn(cards[j],e:GetHandler())) do
if common[k] then nextc[k]=true end
end end
common=nextc
if not next(common) then return false end
end end
return false
end end
return dfs(1)
end end
return true
end end
--- Helper: check one card against a named slot --- Helper: check one card against a named slot
...@@ -3869,6 +3777,8 @@ end ...@@ -3869,6 +3777,8 @@ end
---@param filter fun(mc:Card,tc:Card):boolean ---@param filter fun(mc:Card,tc:Card):boolean
---@return table ---@return table
function Fusion.Slot.Filter(filter) function Fusion.Slot.Filter(filter)
local base_filter=filter
filter=aux.AND(base_filter,function(mc,tc) return not mc:IsHasEffect(6205579) end)
return { return {
filter=filter, filter=filter,
allow_sub=false allow_sub=false
...@@ -3881,25 +3791,27 @@ end ...@@ -3881,25 +3791,27 @@ end
function Fusion.Slot.Group(opts) function Fusion.Slot.Group(opts)
opts.min=opts.min or 1 opts.min=opts.min or 1
opts.max=opts.max or math.huge opts.max=opts.max or math.huge
opts.filter=opts.filter or aux.TRUE local base_filter=opts.filter or aux.TRUE
opts.filter=aux.AND(base_filter,function(mc,tc) return not mc:IsHasEffect(6205579) end)
return { return {
group=opts group=opts
} }
end end
--- FindAllMapping --- FindAllMappings
--- @param cards_sel Card[] currently picked materials --- @param cards_sel Card[] currently picked materials
--- @param slots table[] your original slots spec --- @param slots table[] your original slots spec
--- @param tc Card the fusion monster (for substitutes) --- @param tc Card the fusion monster (for substitutes)
--- @return table[] an array of mapping tables (or empty if none) --- @return table[] an array of mapping tables (or empty if none)
function Fusion.FindAllMappings(cards_sel,slots,tc) function Fusion.FindAllMappings(cards_sel, slots, tc)
--- empty selection, just return --- empty selection, just return one “empty” mapping
if #cards_sel==0 then if #cards_sel==0 then
return {{}} return {{}}
end end
-- Trackers
local filled={} -- for single slots -- Trackers: single‐slots vs group‐slots
local group_assigned={} -- how many cards assigned so far to each group slot local filled={} -- filled[i] = true if single slot i is already taken
local group_assigned={} -- group_assigned[i] = count assigned to slots[i].group
for i,slot in ipairs(slots) do for i,slot in ipairs(slots) do
if slot.group then if slot.group then
group_assigned[i]=0 group_assigned[i]=0
...@@ -3908,16 +3820,19 @@ function Fusion.FindAllMappings(cards_sel,slots,tc) ...@@ -3908,16 +3820,19 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end end
end end
-- prepare locked_slots for this mapping -- Prepare locked_slots for substitute‐material restrictions
local locked_slots={} local locked_slots={}
if Fusion.LockedCodes then if Fusion.LockedCodes then
for _,code in ipairs(Fusion.LockedCodes) do for _, code in ipairs(Fusion.LockedCodes) do
for idx,slot in ipairs(slots) do for idx, slot in ipairs(slots) do
local matched=false local matched=false
if slot.match_code==code then matched=true -- direct code match?
if slot.match_code==code then
matched=true
-- or inside match_codes?
elseif slot.match_codes then elseif slot.match_codes then
for _,c in ipairs(slot.match_codes) do for _,c2 in ipairs(slot.match_codes) do
if c==code then if c2==code then
matched=true matched=true
break break
end end
...@@ -3925,41 +3840,42 @@ function Fusion.FindAllMappings(cards_sel,slots,tc) ...@@ -3925,41 +3840,42 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end end
if matched then if matched then
locked_slots[idx]=true locked_slots[idx]=true
break break -- stop scanning slots for this code
end end
end end
end end
end end
local all_maps={} local all_maps={}
local mapping={} -- mapping[idx_in_cards_sel] = slot_index local mapping={} -- mapping[j] = slot index assigned to cards_sel[j]
--- Depth‐first search over cards_sel
local function dfs(idx,sub_count) local function dfs(idx,sub_count)
-- prune: no more than 1 substitute -- never use more than 1 substitute material
if sub_count>1 then if sub_count>1 then
return return
end end
-- all cards assigned: check per‐group unique_by, then record
if idx>#cards_sel then if idx>#cards_sel then
-- Before recording, run unique_by on each group‐slot that has one
for i,slot in ipairs(slots) do for i,slot in ipairs(slots) do
if slot.group and slot.group.unique_by then local assigned=group_assigned[i]
-- collect the cards assigned to slot i if slot.group and slot.group.unique_by and assigned>0 then
-- collect the cards mapped to slot i
local sel_group={} local sel_group={}
for j,tc in ipairs(cards_sel) do for j,mc in ipairs(cards_sel) do
if mapping[j]==i then if mapping[j]==i then
table.insert(sel_group,tc) table.insert(sel_group,mc)
end end
end end
-- run the matcher: must cover all |sel_group| cards -- run the uniqueness matcher on that set
local matcher=Fusion.UniqueByMatching(slot.group.unique_by,#sel_group) local matcher=Fusion.UniqueByMatching(slot.group.unique_by,#sel_group)
if not matcher(sel_group) then if not matcher(sel_group) then
-- this mapping fails uniqueness → prune it return -- fails unique_by → abandon this mapping
return
end end
end end
end end
-- passed all unique_by checks → save it
-- passes all uniqueness checks → record it
local copy={} local copy={}
for k,v in pairs(mapping) do for k,v in pairs(mapping) do
copy[k]=v copy[k]=v
...@@ -3969,15 +3885,13 @@ function Fusion.FindAllMappings(cards_sel,slots,tc) ...@@ -3969,15 +3885,13 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end end
local mc=cards_sel[idx] local mc=cards_sel[idx]
local any_match=false -- track if we managed to assign tc local any_match=false
-- try single slots -- try singleslots
for i,slot in ipairs(slots) do for i,slot in ipairs(slots) do
if not slot.group and not filled[i] then if not slot.group and not filled[i] then
local match,is_sub=Fusion.MatchSlot(mc,slot,tc) local ok,is_sub = Fusion.MatchSlot(mc,slot,tc)
if match then if ok and not (is_sub and locked_slots[i]) then
-- skip if substitute and this slot is locked
if not (is_sub and locked_slots[i]) then
local new_sub=sub_count+(is_sub and 1 or 0) local new_sub=sub_count+(is_sub and 1 or 0)
if new_sub<=1 then if new_sub<=1 then
any_match=true any_match=true
...@@ -3990,44 +3904,38 @@ function Fusion.FindAllMappings(cards_sel,slots,tc) ...@@ -3990,44 +3904,38 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end end
end end
end end
end
-- try group slots -- try the group‐slot, if any
for i,slot in ipairs(slots) do for i,slot in ipairs(slots) do
if slot.group then if slot.group then
local assigned=group_assigned[i] local assigned=group_assigned[i]
if assigned<slot.group.max then if assigned<slot.group.max then
-- base filter -- filter check
if not slot.group.filter or slot.group.filter(mc,tc) then if not slot.group.filter or slot.group.filter(mc,tc) then
-- has_same check: only if there's already ≥1 in this slot -- has_same check (if this isn’t the first in the group)
local ok=true local ok=true
if slot.group.has_same and assigned>0 then if slot.group.has_same and assigned > 0 then
for _,fn in ipairs(slot.group.has_same) do for _, fn in ipairs(slot.group.has_same) do
-- start intersection with this candidate
local v0=fn(mc,tc) local v0=fn(mc,tc)
if type(v0)=="number" then if type(v0)=="number" then
-- bitmask path
local mask=v0 local mask=v0
-- AND with each already‐assigned card
for j=1,idx-1 do for j=1,idx-1 do
if mapping[j]==i then if mapping[j]==i then
mask=mask&fn(cards_sel[j],tc) mask=mask&fn(cards_sel[j],tc)
if mask==0 then break end if mask == 0 then break end
end end
end end
if mask==0 then ok=false end if mask==0 then ok=false end
else else
-- list-of-keys path
local common={} local common={}
for _,k in ipairs(v0) do common[k]=true end for _,key in ipairs(v0) do common[key]=true end
-- intersect with each already-assigned card
for j=1,idx-1 do for j=1,idx-1 do
if mapping[j]==i then if mapping[j]==i then
local next_c={} local nextc={}
for _,k in ipairs(fn(cards_sel[j],tc)) do for _, key in ipairs(fn(cards_sel[j],tc)) do
if common[k] then next_c[k]=true end if common[key] then nextc[key]=true end
end end
common=next_c common=nextc
if not next(common) then break end if not next(common) then break end
end end
end end
...@@ -4039,7 +3947,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc) ...@@ -4039,7 +3947,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
if ok then if ok then
any_match=true any_match=true
group_assigned[i]=assigned + 1 group_assigned[i]=assigned+1
mapping[idx]=i mapping[idx]=i
dfs(idx+1,sub_count) dfs(idx+1,sub_count)
group_assigned[i]=assigned group_assigned[i]=assigned
...@@ -4050,7 +3958,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc) ...@@ -4050,7 +3958,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end end
end end
-- If we couldn’t assign tc to any slot, prune this branch -- if nothing matched, abandon this branch
if not any_match then if not any_match then
return return
end end
...@@ -4060,6 +3968,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc) ...@@ -4060,6 +3968,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
return all_maps return all_maps
end end
--- “Given all mappings of sel into slots, can any one of them be completed by drawing from eg?” --- “Given all mappings of sel into slots, can any one of them be completed by drawing from eg?”
--- @param sel Group currently picked materials --- @param sel Group currently picked materials
--- @param eg Group the full pool (e.g. your material group) --- @param eg Group the full pool (e.g. your material group)
...@@ -4145,7 +4054,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc, ...@@ -4145,7 +4054,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
-- if this slot has a has_same, wrap its filter to include only sames -- if this slot has a has_same, wrap its filter to include only sames
if slot.group.has_same then if slot.group.has_same then
-- only if there is at least one already‐selected card for this slot… -- only if there is at least one already‐selected card for this slot…
local has_sel = false local has_sel=false
for _,mapped_i in pairs(mapping) do for _,mapped_i in pairs(mapping) do
if mapped_i==i then if mapped_i==i then
has_sel=true has_sel=true
...@@ -4181,12 +4090,12 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc, ...@@ -4181,12 +4090,12 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
local prev=new_filter local prev=new_filter
new_filter=function(mc,p_tc) new_filter=function(mc,p_tc)
-- original criteria -- original criteria
if prev and not prev(mc,tc) then if prev and not prev(mc,p_tc) then
return false return false
end end
-- for each fn in has_same, check against the precomputed overlap -- for each fn in has_same, check against the precomputed overlap
for fn,overlap in pairs(used_overlap) do for fn,overlap in pairs(used_overlap) do
local v=fn(mc,tc) local v=fn(mc,p_tc)
if type(overlap)=="number" then if type(overlap)=="number" then
-- bitmask path -- bitmask path
if (overlap&v)==0 then if (overlap&v)==0 then
...@@ -4232,7 +4141,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc, ...@@ -4232,7 +4141,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
-- if nothing remains, we exhausted slots, check fgoal -- if nothing remains, we exhausted slots, check fgoal
if #rem_slots==0 then if #rem_slots==0 then
if (fgoalcheck==nil or fgoalcheck(sel)==true) and (aux.FGoalCheckAdditional==nil or aux.FGoalCheckAdditional(tc:GetOwner(),sel,tc)) and aux.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_F)(sel) then if Fusion.FinalCheck(e,sel,tc,fgoalcheck,chkf) then
Fusion.LockedCodes=old_locked Fusion.LockedCodes=old_locked
return true return true
else else
...@@ -4241,7 +4150,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc, ...@@ -4241,7 +4150,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
end end
end end
-- delegate to FusionCondition (allow_extras = true) -- delegate to FusionCondition (allow_extras=true)
local search_cond=Fusion.BasicCondition(tc,rem_slots,mat_filter,fgoalcheck,true,sel) local search_cond=Fusion.BasicCondition(tc,rem_slots,mat_filter,fgoalcheck,true,sel)
if search_cond(e,rem_pool,gc,chkf) then if search_cond(e,rem_pool,gc,chkf) then
Fusion.LockedCodes=old_locked Fusion.LockedCodes=old_locked
......
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