Commit 4b8db707 authored by POLYMER's avatar POLYMER

fix

parent 93ecc3e4
......@@ -157,7 +157,7 @@ function cm.thop(e,tp,eg,ep,ev,re,r,rp)
e3:SetCode(EVENT_CHAIN_SOLVED)
e3:SetCountLimit(1)
e3:SetProperty(EFFECT_FLAG_IGNORE_IMMUNE)
e3:SetLabelObject(tc)
e3:SetLabelObject(e2)
e3:SetCondition(cm.descon)
e3:SetOperation(cm.desop)
Duel.RegisterEffect(e3,tp)
......@@ -165,8 +165,8 @@ function cm.thop(e,tp,eg,ep,ev,re,r,rp)
end
end
function cm.descon(e,tp,eg,ep,ev,re,r,rp)
local tc=e:GetLabelObject()
if tc:GetFlagEffect(m)~=0 then
local te=e:GetLabelObject()
if te and te:GetHandler() and te:GetHandler():GetFlagEffect(m)~=0 then
return true
else
e:Reset()
......@@ -174,6 +174,8 @@ function cm.descon(e,tp,eg,ep,ev,re,r,rp)
end
end
function cm.desop(e,tp,eg,ep,ev,re,r,rp)
local tc=e:GetLabelObject()
local te=e:GetLabelObject()
local tc=te:GetHandler()
te:Reset()
if tc:GetFlagEffect(m)~=0 and tc:GetFlagEffect(11451905)==0 then Duel.SendtoDeck(tc,nil,2,REASON_EFFECT) end
end
\ No newline at end of file
......@@ -90,18 +90,29 @@ function cm.smfilter11(c)
end
function cm.smfilter(c,e,tp,fg)
local eset1={c:IsHasEffect(EFFECT_LIMIT_SUMMON_PROC)}
local eset2={c:IsHasEffect(EFFECT_SUMMON_PROC)}
local eset3={c:IsHasEffect(EFFECT_SET_PROC)}
local eset2={c:IsHasEffect(EFFECT_LIMIT_SET_PROC)}
local eset3={c:IsHasEffect(EFFECT_SUMMON_PROC)}
local eset4={c:IsHasEffect(EFFECT_SET_PROC)}
local e1,e2=Effect.CreateEffect(c),Effect.CreateEffect(c)
local _CheckTribute=Duel.CheckTribute
local _GetLocationCount=Duel.GetLocationCount
local _GetMZoneCount=Duel.GetMZoneCount
if aux.GetValueType(fg)=="Group" then
function Duel.CheckTribute(c,mi,ma,mg,top,...)
function Duel.CheckTribute(c,mi,ma,mg,top,...)
local g=mg or Duel.GetTributeGroup(c)
return _CheckTribute(c,mi,ma,g-fg,top,...)
end
function Duel.GetLocationCount(p,loc,...)
if loc~=LOCATION_MZONE then return _GetLocationCount(p,loc,...) end
return _GetMZoneCount(p,fg,...)
end
function Duel.GetMZoneCount(p,lg,...)
if lg then return _GetMZoneCount(p,fg+lg,...) end
return _GetMZoneCount(p,fg,...)
end
end
if #eset1==0 and #eset2==0 and #eset3==0 then
local mi,ma=c:GetTributeRequirement()
local mi,ma=c:GetTributeRequirement()
if #eset1==0 then
--summon
e1:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e1:SetType(EFFECT_TYPE_SINGLE)
......@@ -110,6 +121,8 @@ function cm.smfilter(c,e,tp,fg)
e1:SetCondition(cm.ttcon)
if mi>0 then e1:SetValue(SUMMON_TYPE_ADVANCE) end
c:RegisterEffect(e1,true)
end
if #eset2==0 then
e2:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e2:SetType(EFFECT_TYPE_SINGLE)
e2:SetCode(EFFECT_LIMIT_SET_PROC)
......@@ -118,9 +131,38 @@ function cm.smfilter(c,e,tp,fg)
c:RegisterEffect(e2,true)
end
local res=c:IsSummonable(true,nil) or c:IsMSetable(true,nil)
Duel.CheckTribute=_CheckTribute
e1:Reset()
e2:Reset()
if not res then
if #eset1==0 and #eset3>0 then
for _,te in pairs(eset3) do
local te1=te:Clone()
te1:SetType(EFFECT_TYPE_SINGLE)
te1:SetCode(EFFECT_LIMIT_SUMMON_PROC)
te1:SetRange(nil)
c:RegisterEffect(te1,true)
res=res or c:IsSummonable(true,nil)
te1:Reset()
if res then break end
end
end
if #eset2==0 and #eset4>0 then
for _,te in pairs(eset4) do
local te1=te:Clone()
te1:SetType(EFFECT_TYPE_SINGLE)
te1:SetCode(EFFECT_LIMIT_SET_PROC)
te1:SetRange(nil)
c:RegisterEffect(te1,true)
res=res or c:IsMSetable(true,nil)
te1:Reset()
if res then break end
end
end
end
Duel.CheckTribute=_CheckTribute
Duel.GetLocationCount=_GetLocationCount
Duel.GetMZoneCount=_GetMZoneCount
--Debug.Message(res)
return res
end
function cm.ttcon(e,c,minc)
......
......@@ -72,30 +72,19 @@ function cm.hspgcheck(lv,tp)
return cm.fselect(g,lv,tp) --g:CheckSubGroup(cm.fselect,1,#g,lv,tp)
end
end
function cm.CheckGroupRecursiveCapture(bool,sg,g,f,min,max,ext_params)
local eg=g:Clone()
if bool then cm.esg=sg:Clone() end
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) then
for sc in aux.Next(sg-cm.esg) do
Auxiliary.SubGroupCaptured:Merge(eg:Filter(cm.slfilter,nil,sc))
end
end
if #sg<max then cm.CheckGroupRecursiveCapture(false,sg,eg,f,min,max,ext_params) end
end
sg:RemoveCard(c)
eg:Sub(eg:Filter(cm.slfilter,nil,c))
end
end
function cm.slfilter(c,sc)
return cm.lvplus(c)==cm.lvplus(sc)
return cm.lvplus(c)==cm.lvplus(sc) and cm.filter4(c)==cm.filter4(sc)
end
--subgroup optimization
function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
local min=min or 1
local max=max or #g
local ext_params={...}
--classif: function to classify cards, e.g. function(c,tc) return c:GetLevel()==tc:GetLevel() end
--sortif: function of subgroup search order, high to low. e.g. Card.GetLevel
--passf: cards that do not require check, e.g. function(c) return c:IsLevel(1) end
--goalstop: do you want to backtrack after reaching the goal? true/false
--check: do you want to return true after reaching the goal firstly? true/false
local classif,sortf,passf,goalstop,check=table.unpack(cm.SubGroupParams)
min=min or 1
max=max or #g
local sg=Group.CreateGroup()
local fg=Duel.GrabSelectedCard()
if #fg>max or min>max or #(g+fg)<min then return nil end
......@@ -103,13 +92,146 @@ function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
fg:SelectUnselect(sg,tp,false,false,min,max)
end
sg:Merge(fg)
local mg,iisg,tmp,stop,iter,ctab,rtab,gtab
--main check
local finish=(#sg>=min and #sg<=max and f(sg,...))
while #sg<max do
Auxiliary.SubGroupCaptured=Group.CreateGroup()
cm.CheckGroupRecursiveCapture(true,sg,g,f,min,max,ext_params)
local cg=Auxiliary.SubGroupCaptured:Clone()
Auxiliary.SubGroupCaptured:Clear()
mg=g-sg
iisg=sg:Clone()
if passf then
aux.SubGroupCaptured=mg:Filter(passf,nil,sg,g)
else
aux.SubGroupCaptured=Group.CreateGroup()
end
ctab,rtab,gtab={},{},{1}
for tc in aux.Next(mg) do
ctab[#ctab+1]=tc
end
--high to low
if sortf then
for i=1,#ctab-1 do
for j=1,#ctab-1-i do
if sortf(ctab[j])<sortf(ctab[j+1]) then
tmp=ctab[j]
ctab[j]=ctab[j+1]
ctab[j+1]=tmp
end
end
end
end
--classify
if classif then
--make similar cards adjacent
for i=1,#ctab-2 do
for j=i+2,#ctab do
if classif(ctab[i],ctab[j]) then
tmp=ctab[j]
ctab[j]=ctab[i+1]
ctab[i+1]=tmp
end
end
end
--rtab[i]: what category does the i-th card belong to
--gtab[i]: What is the first card's number in the i-th category
for i=1,#ctab-1 do
rtab[i]=#gtab
if not classif(ctab[i],ctab[i+1]) then
gtab[#gtab+1]=i+1
end
end
rtab[#ctab]=#gtab
--iter record all cards' number in sg
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
--prune if too much cards
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
--skip check if no new cards
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:Merge(mg:Filter(classif,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
--last card isn't in the last category
if code and code<gtab[#gtab] then
if stop then
--backtrack and add 1 card from next category
iter[#iter]=gtab[rtab[code]+1]
sg:RemoveCard(ctab[code])
sg:AddCard(ctab[(iter[#iter])])
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
--last card is in the last category
elseif code then
if stop or code>=#ctab then
--clear all cards in the last category
while #iter>0 and iter[#iter]>=gtab[#gtab] do
sg:RemoveCard(ctab[(iter[#iter])])
iter[#iter]=nil
end
--backtrack and add 1 card from next category
local code2=iter[#iter]
if code2 then
iter[#iter]=gtab[rtab[code2]+1]
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[(iter[#iter])])
end
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
end
end
--classification is essential for efficiency, and this part is only for backup
else
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:AddCard(sc) --Merge(mg:Filter(class,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
if code<#ctab then
if stop then
iter[#iter]=nil
sg:RemoveCard(ctab[code])
end
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
else
local code2=iter[#iter-1]
iter[#iter]=nil
sg:RemoveCard(ctab[code])
if code2 and code2>0 then
iter[#iter]=code2+1
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[code2+1])
end
end
end
end
--finish searching
sg=iisg
local cg=aux.SubGroupCaptured:Clone()
aux.SubGroupCaptured:Clear()
cg:Sub(sg)
--Debug.Message(cm[0])
finish=(#sg>=min and #sg<=max and f(sg,...))
if #cg==0 then break end
local cancel=not finish and cancelable
......@@ -175,9 +297,11 @@ function cm.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
local sg=Duel.GetMatchingGroup(cm.filter3,tp,LOCATION_DECK,0,nil,e,tp)
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(sc),tp)
local tc=mg:CheckSubGroup(cm.hspcheck,1,#mg,cm.lvplus(sc),tp)
local tc=cm.SelectSubGroup(mg,tp,cm.fselect,false,1,#mg,cm.lvplus(sc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if tc then return true end
end
return false
......@@ -191,9 +315,11 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
local sg=Duel.GetMatchingGroup(cm.filter3,tp,LOCATION_DECK,0,nil,e,tp)
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(sc),tp)
local tc=mg:CheckSubGroup(cm.hspcheck,1,#mg,cm.lvplus(sc),tp)
local tc=cm.SelectSubGroup(mg,tp,cm.fselect,false,1,#mg,cm.lvplus(sc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if tc then tg:AddCard(sc) end
end
if not tg or #tg==0 then return end
......@@ -203,11 +329,14 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
tc=tg:Select(tp,1,1,nil):GetFirst()
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE)
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(tc),tp)
rg=cm.SelectSubGroup(mg,tp,cm.hspcheck,true,1,#mg,cm.lvplus(tc),tp)
rg=cm.SelectSubGroup(mg,tp,cm.fselect,true,1,#mg,cm.lvplus(tc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
end
Duel.ConfirmCards(1-tp,rg:Filter(Card.IsFacedown,nil))
tc:SetMaterial(rg)
local tg=rg:Filter(cm.filter5,nil)
if not tg or #tg==0 then
if Duel.Remove(rg,POS_FACEUP,REASON_EFFECT)>0 then Duel.SpecialSummon(tc,0,tp,tp,false,false,POS_FACEUP) end
......
......@@ -68,30 +68,19 @@ function cm.hspgcheck(lv,tp)
return cm.fselect(g,lv,tp)
end
end
function cm.CheckGroupRecursiveCapture(bool,sg,g,f,min,max,ext_params)
local eg=g:Clone()
if bool then cm.esg=sg:Clone() end
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) then
for sc in aux.Next(sg-cm.esg) do
Auxiliary.SubGroupCaptured:Merge(eg:Filter(cm.slfilter,nil,sc))
end
end
if #sg<max then cm.CheckGroupRecursiveCapture(false,sg,eg,f,min,max,ext_params) end
end
sg:RemoveCard(c)
eg:Sub(eg:Filter(cm.slfilter,nil,c))
end
end
function cm.slfilter(c,sc)
return cm.lvplus(c)==cm.lvplus(sc)
return cm.lvplus(c)==cm.lvplus(sc) and cm.filter4(c)==cm.filter4(sc)
end
--subgroup optimization
function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
local min=min or 1
local max=max or #g
local ext_params={...}
--classif: function to classify cards, e.g. function(c,tc) return c:GetLevel()==tc:GetLevel() end
--sortif: function of subgroup search order, high to low. e.g. Card.GetLevel
--passf: cards that do not require check, e.g. function(c) return c:IsLevel(1) end
--goalstop: do you want to backtrack after reaching the goal? true/false
--check: do you want to return true after reaching the goal firstly? true/false
local classif,sortf,passf,goalstop,check=table.unpack(cm.SubGroupParams)
min=min or 1
max=max or #g
local sg=Group.CreateGroup()
local fg=Duel.GrabSelectedCard()
if #fg>max or min>max or #(g+fg)<min then return nil end
......@@ -99,13 +88,146 @@ function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
fg:SelectUnselect(sg,tp,false,false,min,max)
end
sg:Merge(fg)
local mg,iisg,tmp,stop,iter,ctab,rtab,gtab
--main check
local finish=(#sg>=min and #sg<=max and f(sg,...))
while #sg<max do
Auxiliary.SubGroupCaptured=Group.CreateGroup()
cm.CheckGroupRecursiveCapture(true,sg,g,f,min,max,ext_params)
local cg=Auxiliary.SubGroupCaptured:Clone()
Auxiliary.SubGroupCaptured:Clear()
mg=g-sg
iisg=sg:Clone()
if passf then
aux.SubGroupCaptured=mg:Filter(passf,nil,sg,g)
else
aux.SubGroupCaptured=Group.CreateGroup()
end
ctab,rtab,gtab={},{},{1}
for tc in aux.Next(mg) do
ctab[#ctab+1]=tc
end
--high to low
if sortf then
for i=1,#ctab-1 do
for j=1,#ctab-1-i do
if sortf(ctab[j])<sortf(ctab[j+1]) then
tmp=ctab[j]
ctab[j]=ctab[j+1]
ctab[j+1]=tmp
end
end
end
end
--classify
if classif then
--make similar cards adjacent
for i=1,#ctab-2 do
for j=i+2,#ctab do
if classif(ctab[i],ctab[j]) then
tmp=ctab[j]
ctab[j]=ctab[i+1]
ctab[i+1]=tmp
end
end
end
--rtab[i]: what category does the i-th card belong to
--gtab[i]: What is the first card's number in the i-th category
for i=1,#ctab-1 do
rtab[i]=#gtab
if not classif(ctab[i],ctab[i+1]) then
gtab[#gtab+1]=i+1
end
end
rtab[#ctab]=#gtab
--iter record all cards' number in sg
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
--prune if too much cards
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
--skip check if no new cards
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:Merge(mg:Filter(classif,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
--last card isn't in the last category
if code and code<gtab[#gtab] then
if stop then
--backtrack and add 1 card from next category
iter[#iter]=gtab[rtab[code]+1]
sg:RemoveCard(ctab[code])
sg:AddCard(ctab[(iter[#iter])])
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
--last card is in the last category
elseif code then
if stop or code>=#ctab then
--clear all cards in the last category
while #iter>0 and iter[#iter]>=gtab[#gtab] do
sg:RemoveCard(ctab[(iter[#iter])])
iter[#iter]=nil
end
--backtrack and add 1 card from next category
local code2=iter[#iter]
if code2 then
iter[#iter]=gtab[rtab[code2]+1]
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[(iter[#iter])])
end
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
end
end
--classification is essential for efficiency, and this part is only for backup
else
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:AddCard(sc) --Merge(mg:Filter(class,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
if code<#ctab then
if stop then
iter[#iter]=nil
sg:RemoveCard(ctab[code])
end
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
else
local code2=iter[#iter-1]
iter[#iter]=nil
sg:RemoveCard(ctab[code])
if code2 and code2>0 then
iter[#iter]=code2+1
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[code2+1])
end
end
end
end
--finish searching
sg=iisg
local cg=aux.SubGroupCaptured:Clone()
aux.SubGroupCaptured:Clear()
cg:Sub(sg)
--Debug.Message(cm[0])
finish=(#sg>=min and #sg<=max and f(sg,...))
if #cg==0 then break end
local cancel=not finish and cancelable
......@@ -156,9 +278,11 @@ function cm.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
local sg=Duel.GetMatchingGroup(cm.filter3,tp,LOCATION_DECK,0,nil,e,tp)
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(sc),tp)
local tc=mg:CheckSubGroup(cm.hspcheck,1,#mg,cm.lvplus(sc),tp)
local tc=cm.SelectSubGroup(mg,tp,cm.fselect,false,1,#mg,cm.lvplus(sc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if tc then return true end
end
return false
......@@ -172,9 +296,11 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
local sg=Duel.GetMatchingGroup(cm.filter3,tp,LOCATION_DECK,0,nil,e,tp)
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(sc),tp)
local tc=mg:CheckSubGroup(cm.hspcheck,1,#mg,cm.lvplus(sc),tp)
local tc=cm.SelectSubGroup(mg,tp,cm.fselect,false,1,#mg,cm.lvplus(sc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if tc then tg:AddCard(sc) end
end
if not tg or #tg==0 then return end
......@@ -184,11 +310,14 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
tc=tg:Select(tp,1,1,nil):GetFirst()
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE)
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(tc),tp)
rg=cm.SelectSubGroup(mg,tp,cm.hspcheck,true,1,#mg,cm.lvplus(tc),tp)
rg=cm.SelectSubGroup(mg,tp,cm.fselect,true,1,#mg,cm.lvplus(tc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
end
Duel.ConfirmCards(1-tp,rg:Filter(Card.IsFacedown,nil))
tc:SetMaterial(rg)
local tg=rg:Filter(cm.filter5,nil)
if not tg or #tg==0 then
if Duel.Remove(rg,POS_FACEUP,REASON_EFFECT)>0 then Duel.SpecialSummon(tc,0,tp,tp,false,false,POS_FACEUP) end
......
......@@ -101,30 +101,19 @@ function cm.hspgcheck(lv,tp)
return cm.fselect(g,lv,tp)
end
end
function cm.CheckGroupRecursiveCapture(bool,sg,g,f,min,max,ext_params)
local eg=g:Clone()
if bool then cm.esg=sg:Clone() end
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) then
for sc in aux.Next(sg-cm.esg) do
Auxiliary.SubGroupCaptured:Merge(eg:Filter(cm.slfilter,nil,sc))
end
end
if #sg<max then cm.CheckGroupRecursiveCapture(false,sg,eg,f,min,max,ext_params) end
end
sg:RemoveCard(c)
eg:Sub(eg:Filter(cm.slfilter,nil,c))
end
end
function cm.slfilter(c,sc)
return cm.lvplus(c)==cm.lvplus(sc)
return cm.lvplus(c)==cm.lvplus(sc) and cm.filter4(c)==cm.filter4(sc)
end
--subgroup optimization
function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
local min=min or 1
local max=max or #g
local ext_params={...}
--classif: function to classify cards, e.g. function(c,tc) return c:GetLevel()==tc:GetLevel() end
--sortif: function of subgroup search order, high to low. e.g. Card.GetLevel
--passf: cards that do not require check, e.g. function(c) return c:IsLevel(1) end
--goalstop: do you want to backtrack after reaching the goal? true/false
--check: do you want to return true after reaching the goal firstly? true/false
local classif,sortf,passf,goalstop,check=table.unpack(cm.SubGroupParams)
min=min or 1
max=max or #g
local sg=Group.CreateGroup()
local fg=Duel.GrabSelectedCard()
if #fg>max or min>max or #(g+fg)<min then return nil end
......@@ -132,13 +121,146 @@ function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
fg:SelectUnselect(sg,tp,false,false,min,max)
end
sg:Merge(fg)
local mg,iisg,tmp,stop,iter,ctab,rtab,gtab
--main check
local finish=(#sg>=min and #sg<=max and f(sg,...))
while #sg<max do
Auxiliary.SubGroupCaptured=Group.CreateGroup()
cm.CheckGroupRecursiveCapture(true,sg,g,f,min,max,ext_params)
local cg=Auxiliary.SubGroupCaptured:Clone()
Auxiliary.SubGroupCaptured:Clear()
mg=g-sg
iisg=sg:Clone()
if passf then
aux.SubGroupCaptured=mg:Filter(passf,nil,sg,g)
else
aux.SubGroupCaptured=Group.CreateGroup()
end
ctab,rtab,gtab={},{},{1}
for tc in aux.Next(mg) do
ctab[#ctab+1]=tc
end
--high to low
if sortf then
for i=1,#ctab-1 do
for j=1,#ctab-1-i do
if sortf(ctab[j])<sortf(ctab[j+1]) then
tmp=ctab[j]
ctab[j]=ctab[j+1]
ctab[j+1]=tmp
end
end
end
end
--classify
if classif then
--make similar cards adjacent
for i=1,#ctab-2 do
for j=i+2,#ctab do
if classif(ctab[i],ctab[j]) then
tmp=ctab[j]
ctab[j]=ctab[i+1]
ctab[i+1]=tmp
end
end
end
--rtab[i]: what category does the i-th card belong to
--gtab[i]: What is the first card's number in the i-th category
for i=1,#ctab-1 do
rtab[i]=#gtab
if not classif(ctab[i],ctab[i+1]) then
gtab[#gtab+1]=i+1
end
end
rtab[#ctab]=#gtab
--iter record all cards' number in sg
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
--prune if too much cards
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
--skip check if no new cards
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:Merge(mg:Filter(classif,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
--last card isn't in the last category
if code and code<gtab[#gtab] then
if stop then
--backtrack and add 1 card from next category
iter[#iter]=gtab[rtab[code]+1]
sg:RemoveCard(ctab[code])
sg:AddCard(ctab[(iter[#iter])])
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
--last card is in the last category
elseif code then
if stop or code>=#ctab then
--clear all cards in the last category
while #iter>0 and iter[#iter]>=gtab[#gtab] do
sg:RemoveCard(ctab[(iter[#iter])])
iter[#iter]=nil
end
--backtrack and add 1 card from next category
local code2=iter[#iter]
if code2 then
iter[#iter]=gtab[rtab[code2]+1]
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[(iter[#iter])])
end
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
end
end
--classification is essential for efficiency, and this part is only for backup
else
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:AddCard(sc) --Merge(mg:Filter(class,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
if code<#ctab then
if stop then
iter[#iter]=nil
sg:RemoveCard(ctab[code])
end
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
else
local code2=iter[#iter-1]
iter[#iter]=nil
sg:RemoveCard(ctab[code])
if code2 and code2>0 then
iter[#iter]=code2+1
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[code2+1])
end
end
end
end
--finish searching
sg=iisg
local cg=aux.SubGroupCaptured:Clone()
aux.SubGroupCaptured:Clear()
cg:Sub(sg)
--Debug.Message(cm[0])
finish=(#sg>=min and #sg<=max and f(sg,...))
if #cg==0 then break end
local cancel=not finish and cancelable
......@@ -211,9 +333,11 @@ function cm.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
local sg=Duel.GetMatchingGroup(cm.filter3,tp,LOCATION_DECK,0,nil,e,tp)
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(sc),tp)
local tc=mg:CheckSubGroup(cm.hspcheck,1,#mg,cm.lvplus(sc),tp)
local tc=cm.SelectSubGroup(mg,tp,cm.fselect,false,1,#mg,cm.lvplus(sc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if tc then return true end
end
return false
......@@ -227,9 +351,11 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
local sg=Duel.GetMatchingGroup(cm.filter3,tp,LOCATION_DECK,0,nil,e,tp)
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(sc),tp)
local tc=mg:CheckSubGroup(cm.hspcheck,1,#mg,cm.lvplus(sc),tp)
local tc=cm.SelectSubGroup(mg,tp,cm.fselect,false,1,#mg,cm.lvplus(sc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if tc then tg:AddCard(sc) end
end
if not tg or #tg==0 then return end
......@@ -239,11 +365,14 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
tc=tg:Select(tp,1,1,nil):GetFirst()
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE)
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(tc),tp)
rg=cm.SelectSubGroup(mg,tp,cm.hspcheck,true,1,#mg,cm.lvplus(tc),tp)
rg=cm.SelectSubGroup(mg,tp,cm.fselect,true,1,#mg,cm.lvplus(tc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
end
Duel.ConfirmCards(1-tp,rg:Filter(Card.IsFacedown,nil))
tc:SetMaterial(rg)
local tg=rg:Filter(cm.filter5,nil)
if not tg or #tg==0 then
if Duel.Remove(rg,POS_FACEUP,REASON_EFFECT)>0 then Duel.SpecialSummon(tc,0,tp,tp,false,false,POS_FACEUP) end
......
......@@ -85,30 +85,19 @@ function cm.hspgcheck(lv,tp)
return cm.fselect(g,lv,tp)
end
end
function cm.CheckGroupRecursiveCapture(bool,sg,g,f,min,max,ext_params)
local eg=g:Clone()
if bool then cm.esg=sg:Clone() end
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) then
for sc in aux.Next(sg-cm.esg) do
Auxiliary.SubGroupCaptured:Merge(eg:Filter(cm.slfilter,nil,sc))
end
end
if #sg<max then cm.CheckGroupRecursiveCapture(false,sg,eg,f,min,max,ext_params) end
end
sg:RemoveCard(c)
eg:Sub(eg:Filter(cm.slfilter,nil,c))
end
end
function cm.slfilter(c,sc)
return cm.lvplus(c)==cm.lvplus(sc)
return cm.lvplus(c)==cm.lvplus(sc) and cm.filter4(c)==cm.filter4(sc)
end
--subgroup optimization
function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
local min=min or 1
local max=max or #g
local ext_params={...}
--classif: function to classify cards, e.g. function(c,tc) return c:GetLevel()==tc:GetLevel() end
--sortif: function of subgroup search order, high to low. e.g. Card.GetLevel
--passf: cards that do not require check, e.g. function(c) return c:IsLevel(1) end
--goalstop: do you want to backtrack after reaching the goal? true/false
--check: do you want to return true after reaching the goal firstly? true/false
local classif,sortf,passf,goalstop,check=table.unpack(cm.SubGroupParams)
min=min or 1
max=max or #g
local sg=Group.CreateGroup()
local fg=Duel.GrabSelectedCard()
if #fg>max or min>max or #(g+fg)<min then return nil end
......@@ -116,13 +105,146 @@ function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
fg:SelectUnselect(sg,tp,false,false,min,max)
end
sg:Merge(fg)
local mg,iisg,tmp,stop,iter,ctab,rtab,gtab
--main check
local finish=(#sg>=min and #sg<=max and f(sg,...))
while #sg<max do
Auxiliary.SubGroupCaptured=Group.CreateGroup()
cm.CheckGroupRecursiveCapture(true,sg,g,f,min,max,ext_params)
local cg=Auxiliary.SubGroupCaptured:Clone()
Auxiliary.SubGroupCaptured:Clear()
mg=g-sg
iisg=sg:Clone()
if passf then
aux.SubGroupCaptured=mg:Filter(passf,nil,sg,g)
else
aux.SubGroupCaptured=Group.CreateGroup()
end
ctab,rtab,gtab={},{},{1}
for tc in aux.Next(mg) do
ctab[#ctab+1]=tc
end
--high to low
if sortf then
for i=1,#ctab-1 do
for j=1,#ctab-1-i do
if sortf(ctab[j])<sortf(ctab[j+1]) then
tmp=ctab[j]
ctab[j]=ctab[j+1]
ctab[j+1]=tmp
end
end
end
end
--classify
if classif then
--make similar cards adjacent
for i=1,#ctab-2 do
for j=i+2,#ctab do
if classif(ctab[i],ctab[j]) then
tmp=ctab[j]
ctab[j]=ctab[i+1]
ctab[i+1]=tmp
end
end
end
--rtab[i]: what category does the i-th card belong to
--gtab[i]: What is the first card's number in the i-th category
for i=1,#ctab-1 do
rtab[i]=#gtab
if not classif(ctab[i],ctab[i+1]) then
gtab[#gtab+1]=i+1
end
end
rtab[#ctab]=#gtab
--iter record all cards' number in sg
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
--prune if too much cards
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
--skip check if no new cards
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:Merge(mg:Filter(classif,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
--last card isn't in the last category
if code and code<gtab[#gtab] then
if stop then
--backtrack and add 1 card from next category
iter[#iter]=gtab[rtab[code]+1]
sg:RemoveCard(ctab[code])
sg:AddCard(ctab[(iter[#iter])])
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
--last card is in the last category
elseif code then
if stop or code>=#ctab then
--clear all cards in the last category
while #iter>0 and iter[#iter]>=gtab[#gtab] do
sg:RemoveCard(ctab[(iter[#iter])])
iter[#iter]=nil
end
--backtrack and add 1 card from next category
local code2=iter[#iter]
if code2 then
iter[#iter]=gtab[rtab[code2]+1]
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[(iter[#iter])])
end
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
end
end
--classification is essential for efficiency, and this part is only for backup
else
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:AddCard(sc) --Merge(mg:Filter(class,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
if code<#ctab then
if stop then
iter[#iter]=nil
sg:RemoveCard(ctab[code])
end
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
else
local code2=iter[#iter-1]
iter[#iter]=nil
sg:RemoveCard(ctab[code])
if code2 and code2>0 then
iter[#iter]=code2+1
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[code2+1])
end
end
end
end
--finish searching
sg=iisg
local cg=aux.SubGroupCaptured:Clone()
aux.SubGroupCaptured:Clear()
cg:Sub(sg)
--Debug.Message(cm[0])
finish=(#sg>=min and #sg<=max and f(sg,...))
if #cg==0 then break end
local cancel=not finish and cancelable
......@@ -189,9 +311,11 @@ function cm.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
local sg=Duel.GetMatchingGroup(cm.filter3,tp,LOCATION_DECK,0,nil,e,tp)
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(sc),tp)
local tc=mg:CheckSubGroup(cm.hspcheck,1,#mg,cm.lvplus(sc),tp)
local tc=cm.SelectSubGroup(mg,tp,cm.fselect,false,1,#mg,cm.lvplus(sc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if tc then return true end
end
return false
......@@ -205,9 +329,11 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
local sg=Duel.GetMatchingGroup(cm.filter3,tp,LOCATION_DECK,0,nil,e,tp)
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(sc),tp)
local tc=mg:CheckSubGroup(cm.hspcheck,1,#mg,cm.lvplus(sc),tp)
local tc=cm.SelectSubGroup(mg,tp,cm.fselect,false,1,#mg,cm.lvplus(sc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if tc then tg:AddCard(sc) end
end
if not tg or #tg==0 then return end
......@@ -217,11 +343,14 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
tc=tg:Select(tp,1,1,nil):GetFirst()
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE)
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true}
aux.GCheckAdditional=cm.hspgcheck(cm.lvplus(tc),tp)
rg=cm.SelectSubGroup(mg,tp,cm.hspcheck,true,1,#mg,cm.lvplus(tc),tp)
rg=cm.SelectSubGroup(mg,tp,cm.fselect,true,1,#mg,cm.lvplus(tc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
end
Duel.ConfirmCards(1-tp,rg:Filter(Card.IsFacedown,nil))
tc:SetMaterial(rg)
local tg=rg:Filter(cm.filter5,nil)
if not tg or #tg==0 then
if Duel.Remove(rg,POS_FACEUP,REASON_EFFECT)>0 then Duel.SpecialSummon(tc,0,tp,tp,false,false,POS_FACEUP) end
......
......@@ -83,9 +83,13 @@ function cm.fselect(g,ng,goal,tp)
elseif g:GetSum(cm.lvplus)==goal and Duel.GetMZoneCount(tp,g)>0 then
return true
end
local _SubGroupParams=cm.SubGroupParams
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck2(g,g:GetSum(cm.lvplus)-goal,tp)
local tc=cm.CheckSubGroup(ng,cm.fselect3,1,#ng,g,g:GetSum(cm.lvplus)-goal,tp)
local tc=cm.SelectSubGroup(ng,tp,cm.fselect3,false,1,#ng,g,g:GetSum(cm.lvplus)-goal,tp)
--local tc=ng:CheckSubGroup(cm.fselect3,1,#ng,g,g:GetSum(cm.lvplus)-goal,tp)
aux.GCheckAdditional=nil
cm.SubGroupParams=_SubGroupParams
return tc
end
function cm.fselect3(g,g1,lv,tp)
......@@ -103,53 +107,19 @@ function cm.hspgcheck2(ng,goal,tp)
return cm.fselect3(g,ng,goal,tp)
end
end
function cm.CheckSubGroup(g,f,min,max,...)
local min=min or 1
local max=max or #g
if min>max then return false end
local ext_params={...}
local sg=Duel.GrabSelectedCard()
if #sg>max or #(g+sg)<min then return false end
if #sg==max and (not f(sg,...) or Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg,nil,g,f,min,max,ext_params)) then return false end
if #sg>=min and #sg<=max and f(sg,...) and (not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,nil,g,f,min,max,ext_params)) then return true end
return cm.CheckGroupRecursive(sg,g,f,min,max,ext_params)
end
function cm.CheckGroupRecursive(sg,g,f,min,max,ext_params)
local eg=g:Clone()
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) or (#sg<max and cm.CheckGroupRecursive(sg,eg,f,min,max,ext_params)) then return true end
end
sg:RemoveCard(c)
eg:RemoveCard(c)
end
return false
end
function cm.CheckGroupRecursiveCapture(bool,sg,g,f,min,max,ext_params)
local eg=g:Clone()
if bool then cm.esg=sg:Clone() end
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) then
for sc in aux.Next(sg-cm.esg) do
Auxiliary.SubGroupCaptured:Merge(eg:Filter(cm.slfilter,nil,sc))
end
end
if #sg<max then cm.CheckGroupRecursiveCapture(false,sg,eg,f,min,max,ext_params) end
end
sg:RemoveCard(c)
eg:Sub(eg:Filter(cm.slfilter,nil,c))
end
end
function cm.slfilter(c,sc)
return cm.lvplus(c)==cm.lvplus(sc)
return cm.lvplus(c)==cm.lvplus(sc) and cm.filter4(c)==cm.filter4(sc)
end
--subgroup optimization
function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
local min=min or 1
local max=max or #g
local ext_params={...}
--classif: function to classify cards, e.g. function(c,tc) return c:GetLevel()==tc:GetLevel() end
--sortif: function of subgroup search order, high to low. e.g. Card.GetLevel
--passf: cards that do not require check, e.g. function(c) return c:IsLevel(1) end
--goalstop: do you want to backtrack after reaching the goal? true/false
--check: do you want to return true after reaching the goal firstly? true/false
local classif,sortf,passf,goalstop,check=table.unpack(cm.SubGroupParams)
min=min or 1
max=max or #g
local sg=Group.CreateGroup()
local fg=Duel.GrabSelectedCard()
if #fg>max or min>max or #(g+fg)<min then return nil end
......@@ -157,13 +127,146 @@ function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
fg:SelectUnselect(sg,tp,false,false,min,max)
end
sg:Merge(fg)
local mg,iisg,tmp,stop,iter,ctab,rtab,gtab
--main check
local finish=(#sg>=min and #sg<=max and f(sg,...))
while #sg<max do
Auxiliary.SubGroupCaptured=Group.CreateGroup()
cm.CheckGroupRecursiveCapture(true,sg,g,f,min,max,ext_params)
local cg=Auxiliary.SubGroupCaptured:Clone()
Auxiliary.SubGroupCaptured:Clear()
mg=g-sg
iisg=sg:Clone()
if passf then
aux.SubGroupCaptured=mg:Filter(passf,nil,sg,g)
else
aux.SubGroupCaptured=Group.CreateGroup()
end
ctab,rtab,gtab={},{},{1}
for tc in aux.Next(mg) do
ctab[#ctab+1]=tc
end
--high to low
if sortf then
for i=1,#ctab-1 do
for j=1,#ctab-1-i do
if sortf(ctab[j])<sortf(ctab[j+1]) then
tmp=ctab[j]
ctab[j]=ctab[j+1]
ctab[j+1]=tmp
end
end
end
end
--classify
if classif then
--make similar cards adjacent
for i=1,#ctab-2 do
for j=i+2,#ctab do
if classif(ctab[i],ctab[j]) then
tmp=ctab[j]
ctab[j]=ctab[i+1]
ctab[i+1]=tmp
end
end
end
--rtab[i]: what category does the i-th card belong to
--gtab[i]: What is the first card's number in the i-th category
for i=1,#ctab-1 do
rtab[i]=#gtab
if not classif(ctab[i],ctab[i+1]) then
gtab[#gtab+1]=i+1
end
end
rtab[#ctab]=#gtab
--iter record all cards' number in sg
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
--prune if too much cards
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
--skip check if no new cards
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:Merge(mg:Filter(classif,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
--last card isn't in the last category
if code and code<gtab[#gtab] then
if stop then
--backtrack and add 1 card from next category
iter[#iter]=gtab[rtab[code]+1]
sg:RemoveCard(ctab[code])
sg:AddCard(ctab[(iter[#iter])])
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
--last card is in the last category
elseif code then
if stop or code>=#ctab then
--clear all cards in the last category
while #iter>0 and iter[#iter]>=gtab[#gtab] do
sg:RemoveCard(ctab[(iter[#iter])])
iter[#iter]=nil
end
--backtrack and add 1 card from next category
local code2=iter[#iter]
if code2 then
iter[#iter]=gtab[rtab[code2]+1]
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[(iter[#iter])])
end
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
end
end
--classification is essential for efficiency, and this part is only for backup
else
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:AddCard(sc) --Merge(mg:Filter(class,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
if code<#ctab then
if stop then
iter[#iter]=nil
sg:RemoveCard(ctab[code])
end
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
else
local code2=iter[#iter-1]
iter[#iter]=nil
sg:RemoveCard(ctab[code])
if code2 and code2>0 then
iter[#iter]=code2+1
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[code2+1])
end
end
end
end
--finish searching
sg=iisg
local cg=aux.SubGroupCaptured:Clone()
aux.SubGroupCaptured:Clear()
cg:Sub(sg)
--Debug.Message(cm[0])
finish=(#sg>=min and #sg<=max and f(sg,...))
if #cg==0 then break end
local cancel=not finish and cancelable
......@@ -217,9 +320,9 @@ function cm.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
local ng=mg-trg
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
--aux.GCheckAdditional=cm.hspgcheck
local tc=cm.CheckSubGroup(trg,cm.fselect,1,#trg,ng,cm.lvplus(sc),tp)
--aux.GCheckAdditional=nil
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,false,true}
local tc=cm.SelectSubGroup(trg,tp,cm.fselect,false,1,#trg,ng,cm.lvplus(sc),tp)
cm.SubGroupParams={}
if tc then return true end
end
return false
......@@ -235,9 +338,9 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
local ng=mg-trg
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
--aux.GCheckAdditional=cm.hspgcheck
local tc=cm.CheckSubGroup(trg,cm.fselect,1,#trg,ng,cm.lvplus(sc),tp)
--aux.GCheckAdditional=nil
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,false,true}
local tc=cm.SelectSubGroup(trg,tp,cm.fselect,false,1,#trg,ng,cm.lvplus(sc),tp)
cm.SubGroupParams={}
if tc then tg:AddCard(sc) end
end
if not tg or #tg==0 then return end
......@@ -248,13 +351,16 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
tc=tg:Select(tp,1,1,nil):GetFirst()
Duel.Hint(HINT_SELECTMSG,tp,aux.Stringid(m,6))
--aux.GCheckAdditional=cm.hspgcheck
rg=trg:SelectSubGroup(tp,cm.fselect,true,1,#trg,ng,cm.lvplus(tc),tp)
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,false}
rg=cm.SelectSubGroup(trg,tp,cm.fselect,true,1,#trg,ng,cm.lvplus(tc),tp)
cm.SubGroupParams={}
if rg and #rg>0 and rg:GetSum(cm.lvplus)>cm.lvplus(tc) then
Duel.Hint(HINT_SELECTMSG,tp,aux.Stringid(m,7))
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true}
aux.GCheckAdditional=cm.hspgcheck2(rg,rg:GetSum(cm.lvplus)-cm.lvplus(tc),tp)
rg2=cm.SelectSubGroup(ng,tp,cm.fselect3,true,1,#ng,rg,rg:GetSum(cm.lvplus)-cm.lvplus(tc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if rg2 and #rg2>0 then
res=true
rg:Merge(rg2)
......@@ -264,6 +370,7 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
end
end
Duel.ConfirmCards(1-tp,rg:Filter(Card.IsFacedown,nil))
tc:SetMaterial(rg)
local tg=rg:Filter(cm.filter5,nil)
if not tg or #tg==0 then
if Duel.Remove(rg,POS_FACEUP,REASON_EFFECT)>0 then Duel.SpecialSummon(tc,0,tp,tp,false,false,POS_FACEUP) end
......
......@@ -86,9 +86,13 @@ function cm.fselect(g,ng,goal,tp)
elseif g:GetSum(cm.lvplus)==goal and Duel.GetMZoneCount(tp,g)>0 then
return true
end
local _SubGroupParams=cm.SubGroupParams
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true,true}
aux.GCheckAdditional=cm.hspgcheck2(g,g:GetSum(cm.lvplus)-goal,tp)
local tc=cm.CheckSubGroup(ng,cm.fselect3,1,#ng,g,g:GetSum(cm.lvplus)-goal,tp)
local tc=cm.SelectSubGroup(ng,tp,cm.fselect3,false,1,#ng,g,g:GetSum(cm.lvplus)-goal,tp)
--local tc=ng:CheckSubGroup(cm.fselect3,1,#ng,g,g:GetSum(cm.lvplus)-goal,tp)
aux.GCheckAdditional=nil
cm.SubGroupParams=_SubGroupParams
return tc
end
function cm.fselect3(g,g1,lv,tp)
......@@ -106,53 +110,19 @@ function cm.hspgcheck2(ng,goal,tp)
return cm.fselect3(g,ng,goal,tp)
end
end
function cm.CheckSubGroup(g,f,min,max,...)
local min=min or 1
local max=max or #g
if min>max then return false end
local ext_params={...}
local sg=Duel.GrabSelectedCard()
if #sg>max or #(g+sg)<min then return false end
if #sg==max and (not f(sg,...) or Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg,nil,g,f,min,max,ext_params)) then return false end
if #sg>=min and #sg<=max and f(sg,...) and (not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,nil,g,f,min,max,ext_params)) then return true end
return cm.CheckGroupRecursive(sg,g,f,min,max,ext_params)
end
function cm.CheckGroupRecursive(sg,g,f,min,max,ext_params)
local eg=g:Clone()
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) or (#sg<max and cm.CheckGroupRecursive(sg,eg,f,min,max,ext_params)) then return true end
end
sg:RemoveCard(c)
eg:RemoveCard(c)
end
return false
end
function cm.CheckGroupRecursiveCapture(bool,sg,g,f,min,max,ext_params)
local eg=g:Clone()
if bool then cm.esg=sg:Clone() end
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) then
for sc in aux.Next(sg-cm.esg) do
Auxiliary.SubGroupCaptured:Merge(eg:Filter(cm.slfilter,nil,sc))
end
end
if #sg<max then cm.CheckGroupRecursiveCapture(false,sg,eg,f,min,max,ext_params) end
end
sg:RemoveCard(c)
eg:Sub(eg:Filter(cm.slfilter,nil,c))
end
end
function cm.slfilter(c,sc)
return cm.lvplus(c)==cm.lvplus(sc)
return cm.lvplus(c)==cm.lvplus(sc) and cm.filter4(c)==cm.filter4(sc)
end
--subgroup optimization
function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
local min=min or 1
local max=max or #g
local ext_params={...}
--classif: function to classify cards, e.g. function(c,tc) return c:GetLevel()==tc:GetLevel() end
--sortif: function of subgroup search order, high to low. e.g. Card.GetLevel
--passf: cards that do not require check, e.g. function(c) return c:IsLevel(1) end
--goalstop: do you want to backtrack after reaching the goal? true/false
--check: do you want to return true after reaching the goal firstly? true/false
local classif,sortf,passf,goalstop,check=table.unpack(cm.SubGroupParams)
min=min or 1
max=max or #g
local sg=Group.CreateGroup()
local fg=Duel.GrabSelectedCard()
if #fg>max or min>max or #(g+fg)<min then return nil end
......@@ -160,13 +130,146 @@ function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
fg:SelectUnselect(sg,tp,false,false,min,max)
end
sg:Merge(fg)
local mg,iisg,tmp,stop,iter,ctab,rtab,gtab
--main check
local finish=(#sg>=min and #sg<=max and f(sg,...))
while #sg<max do
Auxiliary.SubGroupCaptured=Group.CreateGroup()
cm.CheckGroupRecursiveCapture(true,sg,g,f,min,max,ext_params)
local cg=Auxiliary.SubGroupCaptured:Clone()
Auxiliary.SubGroupCaptured:Clear()
mg=g-sg
iisg=sg:Clone()
if passf then
aux.SubGroupCaptured=mg:Filter(passf,nil,sg,g)
else
aux.SubGroupCaptured=Group.CreateGroup()
end
ctab,rtab,gtab={},{},{1}
for tc in aux.Next(mg) do
ctab[#ctab+1]=tc
end
--high to low
if sortf then
for i=1,#ctab-1 do
for j=1,#ctab-1-i do
if sortf(ctab[j])<sortf(ctab[j+1]) then
tmp=ctab[j]
ctab[j]=ctab[j+1]
ctab[j+1]=tmp
end
end
end
end
--classify
if classif then
--make similar cards adjacent
for i=1,#ctab-2 do
for j=i+2,#ctab do
if classif(ctab[i],ctab[j]) then
tmp=ctab[j]
ctab[j]=ctab[i+1]
ctab[i+1]=tmp
end
end
end
--rtab[i]: what category does the i-th card belong to
--gtab[i]: What is the first card's number in the i-th category
for i=1,#ctab-1 do
rtab[i]=#gtab
if not classif(ctab[i],ctab[i+1]) then
gtab[#gtab+1]=i+1
end
end
rtab[#ctab]=#gtab
--iter record all cards' number in sg
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
--prune if too much cards
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
--skip check if no new cards
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:Merge(mg:Filter(classif,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
--last card isn't in the last category
if code and code<gtab[#gtab] then
if stop then
--backtrack and add 1 card from next category
iter[#iter]=gtab[rtab[code]+1]
sg:RemoveCard(ctab[code])
sg:AddCard(ctab[(iter[#iter])])
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
--last card is in the last category
elseif code then
if stop or code>=#ctab then
--clear all cards in the last category
while #iter>0 and iter[#iter]>=gtab[#gtab] do
sg:RemoveCard(ctab[(iter[#iter])])
iter[#iter]=nil
end
--backtrack and add 1 card from next category
local code2=iter[#iter]
if code2 then
iter[#iter]=gtab[rtab[code2]+1]
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[(iter[#iter])])
end
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
end
end
--classification is essential for efficiency, and this part is only for backup
else
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:AddCard(sc) --Merge(mg:Filter(class,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
if code<#ctab then
if stop then
iter[#iter]=nil
sg:RemoveCard(ctab[code])
end
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
else
local code2=iter[#iter-1]
iter[#iter]=nil
sg:RemoveCard(ctab[code])
if code2 and code2>0 then
iter[#iter]=code2+1
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[code2+1])
end
end
end
end
--finish searching
sg=iisg
local cg=aux.SubGroupCaptured:Clone()
aux.SubGroupCaptured:Clear()
cg:Sub(sg)
--Debug.Message(cm[0])
finish=(#sg>=min and #sg<=max and f(sg,...))
if #cg==0 then break end
local cancel=not finish and cancelable
......@@ -257,9 +360,9 @@ function cm.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
local ng=mg-trg
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
--aux.GCheckAdditional=cm.hspgcheck
local tc=cm.CheckSubGroup(trg,cm.fselect,1,#trg,ng,cm.lvplus(sc),tp)
--aux.GCheckAdditional=nil
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,false,true}
local tc=cm.SelectSubGroup(trg,tp,cm.fselect,false,1,#trg,ng,cm.lvplus(sc),tp)
cm.SubGroupParams={}
if tc then return true end
end
return false
......@@ -275,9 +378,9 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
local ng=mg-trg
local tg=Group.CreateGroup()
for sc in aux.Next(sg) do
--aux.GCheckAdditional=cm.hspgcheck
local tc=cm.CheckSubGroup(trg,cm.fselect,1,#trg,ng,cm.lvplus(sc),tp)
--aux.GCheckAdditional=nil
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,false,true}
local tc=cm.SelectSubGroup(trg,tp,cm.fselect,false,1,#trg,ng,cm.lvplus(sc),tp)
cm.SubGroupParams={}
if tc then tg:AddCard(sc) end
end
if not tg or #tg==0 then return end
......@@ -288,13 +391,16 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
tc=tg:Select(tp,1,1,nil):GetFirst()
Duel.Hint(HINT_SELECTMSG,tp,aux.Stringid(m,6))
--aux.GCheckAdditional=cm.hspgcheck
rg=trg:SelectSubGroup(tp,cm.fselect,true,1,#trg,ng,cm.lvplus(tc),tp)
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,false}
rg=cm.SelectSubGroup(trg,tp,cm.fselect,true,1,#trg,ng,cm.lvplus(tc),tp)
cm.SubGroupParams={}
if rg and #rg>0 and rg:GetSum(cm.lvplus)>cm.lvplus(tc) then
Duel.Hint(HINT_SELECTMSG,tp,aux.Stringid(m,7))
cm.SubGroupParams={cm.slfilter,Card.GetLevel,nil,true}
aux.GCheckAdditional=cm.hspgcheck2(rg,rg:GetSum(cm.lvplus)-cm.lvplus(tc),tp)
rg2=cm.SelectSubGroup(ng,tp,cm.fselect3,true,1,#ng,rg,rg:GetSum(cm.lvplus)-cm.lvplus(tc),tp)
aux.GCheckAdditional=nil
cm.SubGroupParams={}
if rg2 and #rg2>0 then
res=true
rg:Merge(rg2)
......@@ -304,6 +410,7 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
end
end
Duel.ConfirmCards(1-tp,rg:Filter(Card.IsFacedown,nil))
tc:SetMaterial(rg)
local tg=rg:Filter(cm.filter5,nil)
if not tg or #tg==0 then
if Duel.Remove(rg,POS_FACEUP,REASON_EFFECT)>0 then Duel.SpecialSummon(tc,0,tp,tp,false,false,POS_FACEUP) end
......
......@@ -36,66 +36,22 @@ end
function cm.mzfilter(c)
return c:IsAbleToDeckOrExtraAsCost() and c:GetLevel()>=1 and c:IsRace(RACE_PSYCHO) and (c:IsLocation(LOCATION_GRAVE) or c:IsFacedown())
end
function cm.CheckSubGroup(g,f,min,max,...)
local min=min or 1
local max=max or #g
if min>max then return false end
local ext_params={...}
local sg=Duel.GrabSelectedCard()
if #sg>max or #(g+sg)<min then return false end
if #sg==max and (not f(sg,...) or Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg,nil,g,f,min,max,ext_params)) then return false end
if #sg>=min and #sg<=max and f(sg,...) and (not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,nil,g,f,min,max,ext_params)) then return true end
return cm.CheckGroupRecursive(sg,g,f,min,max,ext_params)
end
function cm.CheckGroupRecursive(sg,g,f,min,max,ext_params)
local eg=g:Clone()
for c in aux.Next(g-sg) do
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) or (#sg<max and cm.CheckGroupRecursive(sg,eg,f,min,max,ext_params)) then return true end
end
sg:RemoveCard(c)
eg:Sub(eg:Filter(cm.slfilter,nil,c))
end
return false
end
function cm.CheckGroupRecursiveCapture(bool,sg,g,f,min,max,ext_params)
local eg=g:Clone()
if bool then cm.esg=sg:Clone() cm.eeg=g:Clone() end
local tempg=g-sg
local c=tempg:GetFirst()
while c do
if not bool or not Auxiliary.SubGroupCaptured:IsContains(c) then
sg:AddCard(c)
if not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,c,eg,f,min,max,ext_params) then
if (#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) then -- or (#sg<max and cm.CheckGroupRecursiveCapture(false,sg,eg,f,min,max,ext_params)) then
--Debug.Message(cm[0])
for sc in aux.Next(sg-cm.esg) do
Auxiliary.SubGroupCaptured:Merge(cm.eeg:Filter(cm.slfilter,nil,sc))
end
end
if #sg<max then cm.CheckGroupRecursiveCapture(false,sg,eg,f,min,max,ext_params) end
end
sg:RemoveCard(c)
--eg:RemoveCard(c)
eg:Sub(eg:Filter(cm.slfilter,nil,c))
tempg:Sub(eg:Filter(cm.slfilter,nil,c))
end
tempg:RemoveCard(c)
c=tempg:GetFirst()
end
end
function cm.slfilter(c,sc)
return c:IsLocation(sc:GetLocation()) and (c:GetLevel()-sc:GetLevel())%5==0
end
function cm.srfilter(c)
return c:GetLevel()%5==0
end
--subgroup optimization
function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
Auxiliary.SubGroupCaptured=g:Filter(cm.srfilter,nil)
local min=min or 1
local max=max or #g
local ext_params={...}
--classif: function to classify cards, e.g. function(c,tc) return c:GetLevel()==tc:GetLevel() end
--sortif: function of subgroup search order, high to low. e.g. Card.GetLevel
--passf: cards that do not require check, e.g. function(c) return c:IsLevel(1) end
--goalstop: do you want to backtrack after reaching the goal? true/false
--check: do you want to return true after reaching the goal firstly? true/false
local classif,sortf,passf,goalstop,check=table.unpack(cm.SubGroupParams)
min=min or 1
max=max or #g
local sg=Group.CreateGroup()
local fg=Duel.GrabSelectedCard()
if #fg>max or min>max or #(g+fg)<min then return nil end
......@@ -103,14 +59,146 @@ function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
fg:SelectUnselect(sg,tp,false,false,min,max)
end
sg:Merge(fg)
local mg,iisg,tmp,stop,iter,ctab,rtab,gtab
--main check
local finish=(#sg>=min and #sg<=max and f(sg,...))
while #sg<max do
Auxiliary.SubGroupCaptured=(g-sg):Filter(cm.srfilter,nil)
cm.CheckGroupRecursiveCapture(true,sg,g,f,min,max,ext_params)
local cg=Auxiliary.SubGroupCaptured:Clone()
Auxiliary.SubGroupCaptured:Clear()
--Debug.Message(cm[0])
mg=g-sg
iisg=sg:Clone()
if passf then
aux.SubGroupCaptured=mg:Filter(passf,nil,sg,g)
else
aux.SubGroupCaptured=Group.CreateGroup()
end
ctab,rtab,gtab={},{},{1}
for tc in aux.Next(mg) do
ctab[#ctab+1]=tc
end
--high to low
if sortf then
for i=1,#ctab-1 do
for j=1,#ctab-1-i do
if sortf(ctab[j])<sortf(ctab[j+1]) then
tmp=ctab[j]
ctab[j]=ctab[j+1]
ctab[j+1]=tmp
end
end
end
end
--classify
if classif then
--make similar cards adjacent
for i=1,#ctab-2 do
for j=i+2,#ctab do
if classif(ctab[i],ctab[j]) then
tmp=ctab[j]
ctab[j]=ctab[i+1]
ctab[i+1]=tmp
end
end
end
--rtab[i]: what category does the i-th card belong to
--gtab[i]: What is the first card's number in the i-th category
for i=1,#ctab-1 do
rtab[i]=#gtab
if not classif(ctab[i],ctab[i+1]) then
gtab[#gtab+1]=i+1
end
end
rtab[#ctab]=#gtab
--iter record all cards' number in sg
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
--prune if too much cards
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
--skip check if no new cards
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:Merge(mg:Filter(classif,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
--last card isn't in the last category
if code and code<gtab[#gtab] then
if stop then
--backtrack and add 1 card from next category
iter[#iter]=gtab[rtab[code]+1]
sg:RemoveCard(ctab[code])
sg:AddCard(ctab[(iter[#iter])])
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
--last card is in the last category
elseif code then
if stop or code>=#ctab then
--clear all cards in the last category
while #iter>0 and iter[#iter]>=gtab[#gtab] do
sg:RemoveCard(ctab[(iter[#iter])])
iter[#iter]=nil
end
--backtrack and add 1 card from next category
local code2=iter[#iter]
if code2 then
iter[#iter]=gtab[rtab[code2]+1]
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[(iter[#iter])])
end
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
end
end
--classification is essential for efficiency, and this part is only for backup
else
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:AddCard(sc) --Merge(mg:Filter(class,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
if code<#ctab then
if stop then
iter[#iter]=nil
sg:RemoveCard(ctab[code])
end
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
else
local code2=iter[#iter-1]
iter[#iter]=nil
sg:RemoveCard(ctab[code])
if code2 and code2>0 then
iter[#iter]=code2+1
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[code2+1])
end
end
end
end
--finish searching
sg=iisg
local cg=aux.SubGroupCaptured:Clone()
aux.SubGroupCaptured:Clear()
cg:Sub(sg)
--Debug.Message(cm[0])
finish=(#sg>=min and #sg<=max and f(sg,...))
if #cg==0 then break end
local cancel=not finish and cancelable
......@@ -137,11 +225,11 @@ function cm.sprcon(e,c)
if c==nil then return true end
local tp=c:GetControler()
local mg=Duel.GetMatchingGroup(cm.mzfilter,tp,LOCATION_GRAVE+LOCATION_REMOVED,0,nil)
--[[Auxiliary.SubGroupCaptured=Group.CreateGroup()
local sg=Group.CreateGroup()
cm.CheckGroupRecursiveCapture(true,sg,mg,cm.syngoal,4,#mg,{1})
Debug.Message(cm[0])--]]
return mg:IsExists(Card.IsLocation,2,nil,LOCATION_GRAVE) and mg:IsExists(Card.IsLocation,2,nil,LOCATION_REMOVED) and Duel.GetLocationCountFromEx(tp,tp,nil,c)>0 and cm.CheckSubGroup(mg,cm.syngoal)
cm.SubGroupParams={cm.slfilter,Card.GetLevel,cm.srfilter,false,true}
local res=cm.SelectSubGroup(mg,tp,cm.syngoal,Duel.IsSummonCancelable(),2,#mg)
cm.SubGroupParams={}
--Debug.Message(cm[0])
return mg:IsExists(Card.IsLocation,2,nil,LOCATION_GRAVE) and mg:IsExists(Card.IsLocation,2,nil,LOCATION_REMOVED) and Duel.GetLocationCountFromEx(tp,tp,nil,c)>0 and res
end
--cm[0]=0
function cm.syngoal(g)
......@@ -150,40 +238,18 @@ function cm.syngoal(g)
end
function cm.sprtg(e,tp,eg,ep,ev,re,r,rp,chk,c)
local mg=Duel.GetMatchingGroup(cm.mzfilter,tp,LOCATION_GRAVE+LOCATION_REMOVED,0,nil)
local sg=cm.SelectSubGroup(mg,tp,cm.syngoal,Duel.IsSummonCancelable(),4,#mg)
cm.SubGroupParams={cm.slfilter,Card.GetLevel,cm.srfilter,false}
local sg=cm.SelectSubGroup(mg,tp,cm.syngoal,Duel.IsSummonCancelable(),2,#mg)
cm.SubGroupParams={}
if sg then
sg:KeepAlive()
e:SetLabelObject(sg)
return true
else return false end
--[[local sg=Group.CreateGroup()
local cg=mg:Filter(cm.syncheck,sg,sg,mg)
local cg0=cg
local finish=cm.syngoal(sg)
while 1==1 do
cg=cg0:Filter(cm.syncheck,sg,sg,cg0)
cg:Sub(sg)
finish=cm.syngoal(sg)
local cancel=not finish and Duel.IsSummonCancelable()
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_TODECK)
local tc=cg:SelectUnselect(sg,tp,finish,cancel,4,#mg)
if not tc then break end
if not sg:IsContains(tc) then
sg:AddCard(tc)
if #sg==#cg then finish=true end
else
sg:RemoveCard(tc)
end
end
if finish then
sg:KeepAlive()
e:SetLabelObject(sg)
return true
else return false end--]]
end
function cm.sprop(e,tp,eg,ep,ev,re,r,rp,c)
local sg=e:GetLabelObject()
Card.SetMaterial(c,sg)
c:SetMaterial(sg)
local cg=sg:Filter(Card.IsFacedown,nil)
Duel.SendtoDeck(sg,nil,2,REASON_COST+REASON_MATERIAL)
if #cg>0 then Duel.ConfirmCards(1-tp,cg) end
......
......@@ -136,10 +136,10 @@ function cm.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
local mg2=Duel.GetOverlayGroup(tp,1,1):Filter(cm.matfilter,nil)
mg:Merge(mg2)
if chk==0 then
aux.GCheckAdditional=cm.fselect
local res=Duel.IsExistingMatchingCard(Card.IsLinkSummonable,tp,LOCATION_EXTRA,0,1,nil,mg)
aux.GCheckAdditional=nil
return res
--aux.GCheckAdditional=cm.fselect
--local res=Duel.IsExistingMatchingCard(Card.IsLinkSummonable,tp,LOCATION_EXTRA,0,1,nil,mg)
--aux.GCheckAdditional=nil
return Duel.IsExistingMatchingCard(cm.scfilter,tp,LOCATION_EXTRA,0,1,nil,mg)
end
Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,nil,1,0,0)
end
......
......@@ -183,7 +183,7 @@ function cm.spop(e,tp,eg,ep,ev,re,r,rp)
end
local _GetReason=Card.GetReason
local _GetReasonCard=Card.GetReasonCard
Card.GetReason=function(c) if c:GetFlagEffect(m)>0 then return 0x40008 else return _GetReason(c) end end
Card.GetReason=function(c) if c:GetFlagEffect(m)>0 then return _GetReason(c)|0x40008 else return _GetReason(c) end end
Card.GetReasonCard=function(c) if c:GetFlagEffect(m)>0 then return tc else return _GetReasonCard(c) end end
--[[if c:GetFlagEffect(m)>0 then
local _,fusc=_GetReasonCard(c)
......
......@@ -48,20 +48,31 @@ function cm.fselect2(g)
end
function cm.fselect3(g)
local ct2=g:FilterCount(cm.sfilter,nil)
return #g<=2*ct2
return #g<=2*ct2 and #g%2==0
end
function cm.fselect4(g)
return #g%2==0
end
function cm.fselect5(g)
local ct4=g:FilterCount(cm.mfilter,nil)
return #g<=2*ct4
return #g<=2*ct4 and #g%2==0
end
function cm.slfilter(c,sc)
return (c:IsOnField() and sc:IsOnField() and cm.sfilter(c,e)==cm.sfilter(sc,e)) or (not c:IsOnField() and not sc:IsOnField() and cm.mfilter(c,e)==cm.mfilter(sc,e))
end
function cm.srfilter(c,sg,g)
return (cm.sfilter(c) or cm.mfilter(c)) and #(g-sg)>1
end
--subgroup optimization
function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
Auxiliary.SubGroupCaptured=Group.CreateGroup()
local min=min or 1
local max=max or #g
local ext_params={...}
--classif: function to classify cards, e.g. function(c,tc) return c:GetLevel()==tc:GetLevel() end
--sortif: function of subgroup search order, high to low. e.g. Card.GetLevel
--passf: cards that do not require check, e.g. function(c) return c:IsLevel(1) end
--goalstop: do you want to backtrack after reaching the goal? true/false
--check: do you want to return true after reaching the goal firstly? true/false
local classif,sortf,passf,goalstop,check=table.unpack(cm.SubGroupParams)
min=min or 1
max=max or #g
local sg=Group.CreateGroup()
local fg=Duel.GrabSelectedCard()
if #fg>max or min>max or #(g+fg)<min then return nil end
......@@ -69,18 +80,146 @@ function cm.SelectSubGroup(g,tp,f,cancelable,min,max,...)
fg:SelectUnselect(sg,tp,false,false,min,max)
end
sg:Merge(fg)
local mg,iisg,tmp,stop,iter,ctab,rtab,gtab
--main check
local finish=(#sg>=min and #sg<=max and f(sg,...))
while #sg<max do
local cg=Group.CreateGroup()
local eg=g:Clone()
for c in aux.Next(g-sg) do
if not cg:IsContains(c) then
if Auxiliary.CheckGroupRecursiveCapture(c,sg,eg,f,min,max,ext_params) then
cg:Merge(Auxiliary.SubGroupCaptured)
mg=g-sg
iisg=sg:Clone()
if passf then
aux.SubGroupCaptured=mg:Filter(passf,nil,sg,g)
else
aux.SubGroupCaptured=Group.CreateGroup()
end
ctab,rtab,gtab={},{},{1}
for tc in aux.Next(mg) do
ctab[#ctab+1]=tc
end
--high to low
if sortf then
for i=1,#ctab-1 do
for j=1,#ctab-1-i do
if sortf(ctab[j])<sortf(ctab[j+1]) then
tmp=ctab[j]
ctab[j]=ctab[j+1]
ctab[j+1]=tmp
end
end
end
end
--classify
if classif then
--make similar cards adjacent
for i=1,#ctab-2 do
for j=i+2,#ctab do
if classif(ctab[i],ctab[j]) then
tmp=ctab[j]
ctab[j]=ctab[i+1]
ctab[i+1]=tmp
end
end
end
--rtab[i]: what category does the i-th card belong to
--gtab[i]: What is the first card's number in the i-th category
for i=1,#ctab-1 do
rtab[i]=#gtab
if not classif(ctab[i],ctab[i+1]) then
gtab[#gtab+1]=i+1
end
end
rtab[#ctab]=#gtab
--iter record all cards' number in sg
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
--prune if too much cards
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
--skip check if no new cards
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:Merge(mg:Filter(classif,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
--last card isn't in the last category
if code and code<gtab[#gtab] then
if stop then
--backtrack and add 1 card from next category
iter[#iter]=gtab[rtab[code]+1]
sg:RemoveCard(ctab[code])
sg:AddCard(ctab[(iter[#iter])])
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
--last card is in the last category
elseif code then
if stop or code>=#ctab then
--clear all cards in the last category
while #iter>0 and iter[#iter]>=gtab[#gtab] do
sg:RemoveCard(ctab[(iter[#iter])])
iter[#iter]=nil
end
--backtrack and add 1 card from next category
local code2=iter[#iter]
if code2 then
iter[#iter]=gtab[rtab[code2]+1]
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[(iter[#iter])])
end
else
--continue searching forward
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
end
end
end
--classification is essential for efficiency, and this part is only for backup
else
iter={1}
sg:AddCard(ctab[1])
while #sg>#iisg and #aux.SubGroupCaptured<#mg do
stop=#sg>=max
if (aux.GCheckAdditional and not aux.GCheckAdditional(sg,c,g,f,min,max,...)) then
stop=true
elseif #(sg-iisg-aux.SubGroupCaptured)>0 and #sg>=min and #sg<=max and f(sg,...) then
for sc in aux.Next(sg-iisg) do
if check then return true end
aux.SubGroupCaptured:AddCard(sc) --Merge(mg:Filter(class,nil,sc))
end
stop=goalstop
end
local code=iter[#iter]
if code<#ctab then
if stop then
iter[#iter]=nil
sg:RemoveCard(ctab[code])
end
iter[#iter+1]=code+1
sg:AddCard(ctab[code+1])
else
local code2=iter[#iter-1]
iter[#iter]=nil
sg:RemoveCard(ctab[code])
if code2 and code2>0 then
iter[#iter]=code2+1
sg:RemoveCard(ctab[code2])
sg:AddCard(ctab[code2+1])
end
end
end
end
--finish searching
sg=iisg
local cg=aux.SubGroupCaptured:Clone()
aux.SubGroupCaptured:Clear()
cg:Sub(sg)
--Debug.Message(cm[0])
finish=(#sg>=min and #sg<=max and f(sg,...))
if #cg==0 then break end
local cancel=not finish and cancelable
......@@ -114,12 +253,14 @@ function cm.thtg(e,tp,eg,ep,ev,re,r,rp,chk,chkc)
--Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_TARGET)
local min=2
if Duel.IsExistingTarget(cm.mfilter,tp,LOCATION_GRAVE,LOCATION_GRAVE,1,nil,e) then min=0 end
aux.GCheckAdditional=cm.fselect3
local tg=cm.SelectSubGroup(g1,tp,cm.fselect4,false,min,#g1)
cm.SubGroupParams={cm.slfilter,nil,cm.srfilter,false}
--aux.GCheckAdditional=cm.fselect3
local tg=cm.SelectSubGroup(g1,tp,cm.fselect3,false,min,#g1)
Duel.Hint(HINT_SELECTMSG,tp,aux.Stringid(m,14))
aux.GCheckAdditional=cm.fselect5
local tg2=cm.SelectSubGroup(g2,tp,cm.fselect4,false,math.max(0,2-#tg),#g2)
aux.GCheckAdditional=nil
--aux.GCheckAdditional=cm.fselect5
local tg2=cm.SelectSubGroup(g2,tp,cm.fselect5,false,math.max(0,2-#tg),#g2)
--aux.GCheckAdditional=nil
cm.SubGroupParams={}
tg:Merge(tg2)
Duel.SetTargetCard(tg)
end
......@@ -176,12 +317,12 @@ function cm.filter1(c,fid)
return c:GetFlagEffect(m)>0 and c:GetFlagEffectLabel(m)==fid
end
function Group.ForEach(group,func,...)
if aux.GetValueType(group)=="Group" and group:GetCount()>0 then
local d_group=group:Clone()
for tc in aux.Next(d_group) do
func(tc,...)
end
end
if aux.GetValueType(group)=="Group" and group:GetCount()>0 then
local d_group=group:Clone()
for tc in aux.Next(d_group) do
func(tc,...)
end
end
end
function cm.acop(e,tp,eg,ep,ev,re,r,rp)
if pnfl_adjusting then return end
......
......@@ -106,7 +106,7 @@ function c28318027.rsop(e,tp,eg,ep,ev,re,r,rp)
local xlv=c:GetFlagEffectLabel(28318027)
local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetCode(EFFECT_CHANGE_RANK)
e1:SetCode(EFFECT_CHANGE_RANK_FINAL)
e1:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e1:SetReset(RESET_EVENT+RESETS_STANDARD)
e1:SetValue(xlv)
......
......@@ -109,7 +109,7 @@ function c28318749.rsop(e,tp,eg,ep,ev,re,r,rp)
local xlv=c:GetFlagEffectLabel(28318749)
local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetCode(EFFECT_CHANGE_RANK)
e1:SetCode(EFFECT_CHANGE_RANK_FINAL)
e1:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e1:SetReset(RESET_EVENT+RESETS_STANDARD)
e1:SetValue(xlv)
......
......@@ -127,7 +127,7 @@ function c28322413.rsop(e,tp,eg,ep,ev,re,r,rp)
local xlv=c:GetFlagEffectLabel(28322413)
local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetCode(EFFECT_CHANGE_RANK)
e1:SetCode(EFFECT_CHANGE_RANK_FINAL)
e1:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e1:SetReset(RESET_EVENT+RESETS_STANDARD)
e1:SetValue(xlv)
......@@ -178,19 +178,58 @@ function c28322413.ruop(e,tp,eg,ep,ev,re,r,rp)
local og=Duel.GetOperatedGroup()
local ct=og:FilterCount(Card.IsLocation,nil,LOCATION_DECK+LOCATION_EXTRA)
if ct>0 then
local e1=Effect.CreateEffect(e:GetHandler())
e1:SetType(EFFECT_TYPE_FIELD)
e1:SetCode(EFFECT_UPDATE_LEVEL)
e1:SetTargetRange(LOCATION_MZONE,0)
e1:SetValue(ct)
local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS)
e1:SetCode(EVENT_ADJUST)
e1:SetCondition(c28322413.adcon)
e1:SetReset(RESET_PHASE+PHASE_END+RESET_OPPO_TURN)
e1:SetTarget(aux.TargetBoolFunction(Card.IsSetCard,0x284))
e1:SetOperation(c28322413.adop)
e1:SetLabel(ct)
e1:SetLabelObject(c)
Duel.RegisterEffect(e1,tp)
local e2=e1:Clone()
e2:SetCode(EFFECT_UPDATE_RANK)
Duel.RegisterEffect(e2,tp)
table.insert(c28322413.et,{e1})
end
end
function c28322413.adcon(e,tp,eg,ep,ev,re,r,rp)
return Duel.IsExistingMatchingCard(c28322413.adf,tp,LOCATION_MZONE,0,1,nil,e)
end
function c28322413.adop(e,tp,eg,ep,ev,re,r,rp)
local ct=e:GetLabel()
local c,g= e:GetLabelObject(),Duel.GetMatchingGroup(c28322413.adf,tp,LOCATION_MZONE,0,nil,e)
for xc in aux.Next(g) do
local x
if xc:GetLevel()>0 then x=EFFECT_UPDATE_LEVEL
elseif xc:GetRank()>0 then x=EFFECT_UPDATE_RANK end
local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetCode(x)
e1:SetReset(RESET_EVENT+RESETS_STANDARD+RESET_PHASE+PHASE_END+RESET_OPPO_TURN)
e1:SetValue(ct)
e1:SetCondition(c28322413.efcon)
e1:SetOwnerPlayer(tp)
xc:RegisterEffect(e1)
table.insert(c28322413.get(e),xc)
end
end
function c28322413.efcon(e,tp,eg,ep,ev,re,r,rp)
return e:GetHandler():GetControler()==e:GetOwnerPlayer()
end
c28322413.et = { }
function c28322413.get(v)
for _,i in ipairs(c28322413.et) do
if i[1]==v then return i end
end
end
function c28322413.ck(e,c)
local t = c28322413.get(e)
for _,v in ipairs(t) do
if v == c then return false end
end
return true
end
function c28322413.adf(c,e)
return c:IsSetCard(0x284) and (c:GetLevel()>0 or c:GetRank()>0) and c28322413.ck(e,c)
end
function c28322413.immunefilter(e,te)
return te:IsActiveType(TYPE_MONSTER) and not te:GetHandler():IsType(TYPE_XYZ)
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