Jump to content
Wikipedia The Free Encyclopedia

Module:Build bracket/Logic

From Wikipedia, the free encyclopedia
Module documentation[create] [purge]
You might want to create a documentation page for this Scribunto module.
Editors can experiment in this module's sandbox (edit | diff) and testcases (create) pages.
Add categories to the /doc subpage. Subpages of this module.
 localLogic={}

 -- =======================
 -- 1) STDLIB ALIASES
 -- =======================
 localm_max=math.max
 localm_ceil=math.ceil
 locals_match=string.match
 locals_find=string.find

 -- =======================
 -- 2) MODULE UPVALUES
 -- =======================
 localstate,config,Helpers,StateChecks
 localisempty,notempty,teamLegs

 localfunctionbind(_state,_config,_Helpers,_StateChecks)
 state,config,Helpers,StateChecks=_state,_config,_Helpers,_StateChecks
 isempty=_Helpersand_Helpers.isemptyorfunction(v)
 returnv==nilorv==""
 end
 notempty=_Helpersand_Helpers.notemptyorfunction(v)
 returnv~=nilandv~=""
 end
 teamLegs=_StateChecksand_StateChecks.teamLegs
 end

 -- =======================
 -- 3) SMALL UTILITIES
 -- =======================
 -- Map common Unicode fraction characters to decimal
 localfraction_map={
 ["1⁄2"]=".5",
 ["1⁄3"]=".333",
 ["2⁄3"]=".667",
 ["1⁄4"]=".25",
 ["3⁄4"]=".75",
 ["1⁄5"]=".2",
 ["2⁄5"]=".4",
 ["3⁄5"]=".6",
 ["4⁄5"]=".8",
 ["1⁄6"]=".167",
 ["5⁄6"]=".833",
 ["1⁄8"]=".125",
 ["3⁄8"]=".375",
 ["5⁄8"]=".625",
 ["7⁄8"]=".875"
 }

 -- Normalize fractions like "11⁄2" to "1.5"
 localfunctionnormalizeFractions(s)
 -- Replace integer + fraction (e.g. "11⁄2" → "1.5")
 s=
 s:gsub(
 "(%d+)%s*([%z1円-127円194円-244円][128円-191円]*)",
 function(d,frac)
 localrepl=fraction_map[frac]
 ifreplthen
 returnd..repl
 else
 returnd..frac
 end
 end
 )

 -- Replace standalone fraction (e.g. "1⁄2" → "0.5")
 s=
 s:gsub(
 "([%z1円-127円194円-244円][128円-191円]*)",
 function(frac)
 localrepl=fraction_map[frac]
 ifreplthen
 return"0"..repl
 else
 returnfrac
 end
 end
 )

 returns
 end

 -- Leading integer from a value; supports string or number; nil if none.
 localfunctionnumlead(v)
 ifv==nilthen
 returnnil
 end
 iftype(v)=="number"then
 returnv
 end
 locals=tostring(v)
 ifs==""then
 returnnil
 end

 -- 1) strip leading spaces and wiki bold/italic quotes ('' or ''')
 s=s:match("^%s*'*%s*(.*)")ors

 -- 2) strip *leading* simple wrappers (tags/templates/links), repeatedly, but only if they occur before the first digit.
 localadvanced=true-- set false if you want the minimal version
 ifadvancedthen
 localchanged=true
 whilechangeddo
 changed=false
 locals2=s:gsub("^%s*<[^>]->%s*","",1)-- leading HTML tag
 ifs2~=sthen
 s,changed=s2,true
 end
 s2=s:gsub("^%s*{{.-}}%s*","",1)-- leading template
 ifs2~=sthen
 s,changed=s2,true
 end
 s2=s:gsub("^%s*%[%[[^%]]-%]%]%s*","",1)-- leading wikilink
 ifs2~=sthen
 s,changed=s2,true
 end
 end
 end

 -- 3) capture leading digits only (stops at first non-digit)
 s=normalizeFractions(s)
 localn=s:match("^(%d+%.?%d*)")
 returnnandtonumber(n)ornil
 end

 -- ===========================
 -- 4) MATCH GROUPING (PER RD)
 -- ===========================
 localfunction_matchGroups()
 state.matchgroup=state.matchgroupor{}
 localMINC,C,R=config.minc,config.c,config.r
 forj=MINC,Cdo
 localmgj={}
 state.matchgroup[j]=mgj

 localtpm=tonumber(state.teamsPerMatch[j])or2
 iftpm<1then
 tpm=2
 end

 localcol=state.entries[j]
 ifcolthen
 fori=1,Rdo
 locale=col[i]
 ifeande.ctype=="team"then
 localidx=tonumber(e.index)ortonumber(e.altindex)ori
 localg=m_ceil(idx/tpm)
 mgj[i]=g
 e.group=g
 end
 end
 end
 end
 end

 -- Build ordered lists once per round: gid -> {row indices}
 localfunctionbuildGroupsForRound(j,R)
 localgroups={}
 localmg=(state.matchgroupandstate.matchgroup[j])or{}
 localcol=state.entries[j]
 ifnotcolthen
 returngroups
 end

 fori=1,Rdo
 locale=col[i]
 ifeande.ctype=="team"then
 localgid=mg[i]
 ifgid~=nilthen
 localt=groups[gid]
 ifnottthen
 t={}
 groups[gid]=t
 end
 t[#t+1]=i
 end
 end
 end
 returngroups
 end

 -- Pre-parse leg numbers for each team (per round), only when agg & >1 legs.
 -- Returns: i -> { [l] = number|nil }
 localfunctionpreparseLegs(j,R)
 locallegNums={}
 localcol=state.entries[j]
 ifnotcolthen
 returnlegNums
 end

 fori=1,Rdo
 locale=col[i]
 ifeande.ctype=="team"then
 localL=teamLegs(j,i)
 ifconfig.aggregateandL>1ande.scorethen
 localt={}
 forl=1,Ldo
 t[l]=numlead(e.score[l])
 end
 legNums[i]=t
 end
 end
 end
 returnlegNums
 end

 -- ==========================================
 -- 5) COMPUTE AGGREGATES (score/legs/sets)
 -- ==========================================
 localfunction_computeAggregate()
 ifconfig.aggregate_mode=="off"orconfig.aggregate_mode=="manual"then
 return
 end

 localMINC,C,R=config.minc,config.c,config.r
 localmodeLow=(config.boldwinner_mode=="low")

 forj=MINC,Cdo
 localgroups=buildGroupsForRound(j,R)
 locallegNums=preparseLegs(j,R)

 ifconfig.aggregate_mode=="score"then
 -- Sum per-leg scores; operate directly on parsed legNums.
 fori,numsinpairs(legNums)do
 locale=state.entries[j][i]
 ifeande.ctype=="team"andconfig.aggregateandteamLegs(j,i)>1then
 localsc=e.score
 ifscandisempty(sc.agg)then
 localsum=0
 for_,vinipairs(nums)do
 ifvthen
 sum=sum+v
 end
 end
 sc.agg=tostring(sum)
 end
 end
 end
 else
 -- 'sets'/'legs': count wins per-leg using high/low rule; ties yield no win.
 for_,membersinpairs(groups)do
 localwins={}-- row index -> wins

 -- Comparable leg count across the group = min(#numeric arrays)
 localcommonLegs=math.huge
 for_,iinipairs(members)do
 localnums=legNums[i]
 localL=(numsand#nums)or0
 ifL==0then
 commonLegs=0
 break
 end
 ifL<commonLegsthen
 commonLegs=L
 end
 end

 forl=1,commonLegsdo
 localallNumeric=true
 for_,iinipairs(members)do
 localv=legNums[i]andlegNums[i][l]
 ifv==nilthen
 allNumeric=false
 break
 end
 end
 ifallNumericthen
 localbest,bestIdx,tie
 for_,iinipairs(members)do
 localv=legNums[i][l]
 ifbest==nilthen
 best,bestIdx,tie=v,i,false
 else
 if(modeLowandv<best)or(notmodeLowandv>best)then
 best,bestIdx,tie=v,i,false
 elseifv==bestthen
 tie=true
 end
 end
 end
 ifnottieandbestIdxthen
 wins[bestIdx]=(wins[bestIdx]or0)+1
 end
 end
 end

 -- Write aggregates if still empty
 for_,iinipairs(members)do
 locale=state.entries[j][i]
 ifeande.ctype=="team"andconfig.aggregateandteamLegs(j,i)>1then
 localsc=e.score
 ifscandisempty(sc.agg)then
 sc.agg=tostring(wins[i]or0)
 end
 end
 end
 end
 end
 end
 end

 -- ==========================================
 -- 6) BOLD WINNERS (per cells & whole rows)
 -- ==========================================
 localfunction_boldWinner()
 localfunctionisWin(mine,theirs)
 returnmodeLowand(mine<theirs)or(notmodeLowandmine>theirs)
 end

 localfunctionisAggWin(mine,theirs,colKey)
 -- For aggregate counts (legs/sets won), higher is always better
 ifcolKey=="agg"and(config.aggregate_mode~="score")then
 returnmine>theirs
 end
 returnisWin(mine,theirs)
 end

 ifnotconfigorconfig.boldwinner_mode=="off"then
 -- Normalize all weights (defensive; avoids leftovers across calls)
 forj=config.minc,config.cdo
 fori=1,config.rdo
 locale=state.entries[j]andstate.entries[j][i]
 ifeande.ctype=="team"then
 e.weight="normal"
 ife.scoreande.score.weightthen
 fork,_inpairs(e.score.weight)do
 e.score.weight[k]="normal"
 end
 end
 end
 end
 end
 return
 end

 localMINC,C,R=config.minc,config.c,config.r
 localmodeLow=(config.boldwinner_mode=="low")
 localaggOnly=config.boldwinner_aggonly

 localfunctionisWin(mine,theirs)
 returnmodeLowand(mine<theirs)or(notmodeLowandmine>theirs)
 end

 localfunctionisAggWin(mine,theirs,colKey)
 ifcolKey=="agg"andconfig.aggregate_mode=="sets"then
 -- Sets/legs won: larger count wins regardless of low/high sport
 returnmine>theirs
 end
 returnisWin(mine,theirs)
 end

 localfunctionhasAllScores(e,legs)
 localsc=e.score
 forl=1,legsdo
 localsv=scandsc[l]
 ifisempty(sv)ors_find(svor"","nbsp")then-- use alias
 returnfalse
 end
 end
 returntrue
 end

 forj=MINC,Cdo
 localgroups=buildGroupsForRound(j,R)

 -- Reset counters & ensure score/weight tables exist
 fori=1,Rdo
 locale=state.entries[j]andstate.entries[j][i]
 ifeande.ctype=="team"then
 e.wins,e.aggwins=0,0
 e.score=e.scoreor{}
 e.score.weight=e.score.weightor{}
 end
 end

 for_,membersinpairs(groups)do
 -- Parse per-leg and aggregate numbers ONCE for this group (works for 1+ legs)
 localperLegNum={}-- row -> { l -> number|nil }
 localaggNum={}-- row -> number|nil

 for_,iinipairs(members)do
 locale=state.entries[j][i]
 locallegs=teamLegs(j,i)
 localarr={}
 forl=1,legsdo
 arr[l]=numlead(e.scoreande.score[l])
 end
 perLegNum[i]=arr
 aggNum[i]=numlead(e.scoreande.score.agg)
 end

 -- Per-score bolding (skip entirely if agg-only)
 ifnotaggOnlythen
 -- iterate to the max leg count in the group
 localmaxL=0
 for_,iinipairs(members)do
 localL=teamLegs(j,i)
 ifL>maxLthen
 maxL=L
 end
 end

 forl=1,maxLdo
 localallNumeric=true
 localbest,bestIdx,tie
 for_,iinipairs(members)do
 localv=perLegNum[i]andperLegNum[i][l]
 ifv==nilthen
 allNumeric=false
 break
 end
 ifbest==nilthen
 best,bestIdx,tie=v,i,false
 else
 if(modeLowandv<best)or(notmodeLowandv>best)then
 best,bestIdx,tie=v,i,false
 elseifv==bestthen
 tie=true
 end
 end
 end

 ifallNumericandnottieandbestIdxthen
 -- set the winner bold + increment wins
 locale=state.entries[j][bestIdx]
 e.score.weight[l]="bold"
 e.wins=(e.winsor0)+1
 -- normalize others on this leg
 for_,iinipairs(members)do
 ifi~=bestIdxthen
 state.entries[j][i].score.weight[l]="normal"
 end
 end
 else
 -- no unique winner: normalize everyone for this leg
 for_,iinipairs(members)do
 state.entries[j][i].score.weight[l]="normal"
 end
 end
 end
 end

 -- Aggregate column (if configured & multi-leg)
 do
 localneedAgg=false
 for_,iinipairs(members)do
 ifconfig.aggregateandteamLegs(j,i)>1then
 needAgg=true
 break
 end
 end

 ifneedAggthen
 localallNumeric=true
 localbest,bestIdx,tie

 -- comparator: for legs/sets counts, higher always wins
 localfunctionbetterAgg(a,b)
 ifconfig.aggregate_mode~="score"then
 returna>b
 else
 return(modeLowanda<b)or(notmodeLowanda>b)
 end
 end

 for_,iinipairs(members)do
 localv=aggNum[i]
 ifv==nilthen
 allNumeric=false
 break
 end
 ifbest==nilthen
 best,bestIdx,tie=v,i,false
 else
 ifbetterAgg(v,best)then
 best,bestIdx,tie=v,i,false
 elseifv==bestthen
 tie=true
 end
 end
 end

 ifallNumericandnottieandbestIdxthen
 locale=state.entries[j][bestIdx]
 e.score.weight.agg="bold"
 e.aggwins=1
 for_,iinipairs(members)do
 ifi~=bestIdxthen
 localo=state.entries[j][i]
 o.score.weight.agg="normal"
 o.aggwins=0
 end
 end
 else
 for_,iinipairs(members)do
 locale=state.entries[j][i]
 ife.scorethen
 e.score.weight.agg="normal"
 end
 e.aggwins=0
 end
 end
 end
 end

 -- Whole-team bolding (skip if agg-only so only agg cell bolds)
 ifnotaggOnlythen
 for_,iinipairs(members)do
 locale=state.entries[j][i]
 locallegs=teamLegs(j,i)
 localuseAggregate=config.aggregateandlegs>1
 localwinsKey=useAggregateand"aggwins"or"wins"

 ifnotuseAggregatethen
 if(e[winsKey]or0)>legs/2then
 e.weight="bold"
 else
 e.weight=hasAllScores(e,legs)and"bold"or"normal"
 end
 end

 -- Must strictly beat any opponent on winsKey
 for_,oiinipairs(members)do
 ifoi~=ithen
 localopp=state.entries[j][oi]
 if(e[winsKey]or0)<=tonumber(opp[winsKey]or0)then
 e.weight="normal"
 break
 end
 end
 end

 ifuseAggregatethen
 -- when using aggregate, team weight follows aggwins comparison
 e.weight=((e[winsKey]or0)>0)and"bold"or"normal"
 for_,oiinipairs(members)do
 ifoi~=ithen
 localopp=state.entries[j][oi]
 if(e[winsKey]or0)<=tonumber(opp[winsKey]or0)then
 e.weight="normal"
 break
 end
 end
 end
 end
 end
 end
 end
 end
 end

 -- ==============================
 -- 7) UPDATE PER-ROUND MAX LEGS
 -- ==============================
 localfunction_updateMaxLegs()
 localMINC,C,R=config.minc,config.c,config.r
 forj=MINC,Cdo
 localcol=state.entries[j]
 localrj=state.rlegs[j]
 localmj=rj
 ifcolthen
 fori=1,Rdo
 locale=col[i]
 ifethen
 ifnotempty(e.legs)then
 mj=m_max(rj,e.legs)
 end
 ifconfig.autolegsande.scorethen
 locall=1
 whilee.score[l]andnotisempty(e.score[l])do
 l=l+1
 end
 mj=m_max(mj,l-1)
 end
 end
 end
 end
 state.maxlegs[j]=mj
 end
 end

 -- ==============
 -- 8) PUBLIC API
 -- ==============
 functionLogic.matchGroups(_state,_config)
 bind(_state,_config)
 _matchGroups()
 end

 functionLogic.computeAggregate(_state,_config,_Helpers,_StateChecks)
 bind(_state,_config,_Helpers,_StateChecks)
 _computeAggregate()
 end

 functionLogic.boldWinner(_state,_config,_Helpers,_StateChecks)
 bind(_state,_config,_Helpers,_StateChecks)
 _boldWinner()
 end

 functionLogic.updateMaxLegs(_state,_config,_Helpers)
 bind(_state,_config,_Helpers)
 _updateMaxLegs()
 end

 returnLogic

AltStyle によって変換されたページ (->オリジナル) /