Module:Build bracket/Params
Appearance
From Wikipedia, the free encyclopedia
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.
Editors can experiment in this module's sandbox (edit | diff) and testcases (create) pages.
Add categories to the /doc subpage. Subpages of this module.
localParams={} -- ========================= -- 1) MODULE BINDINGS -- ========================= -- Upvalues bound per call localstate,config,Helpers,StateChecks -- Stdlib aliases localstr_format=string.format localt_insert=table.insert localt_sort=table.sort -- Locals filled on bind (with safe fallbacks) localisempty,notempty,bargs,getPArg,getFArg,toChar,split localfunction_toCharFallback(n) n=tonumber(nor0)or0 ifn>=1andn<=26then returnstring.char(96+n)-- 'a'..'z' end returntostring(n) end localfunctionbind(_state,_config,_Helpers,_StateChecks) state,config,Helpers,StateChecks=_state,_config,_Helpers,_StateChecks isempty=HelpersandHelpers.isemptyorfunction(v) returnv==nilorv=="" end notempty=HelpersandHelpers.notemptyorfunction(v) returnv~=nilandv~="" end bargs=HelpersandHelpers.bargs getPArg=HelpersandHelpers.getPArg getFArg=HelpersandHelpers.getFArg toChar=(HelpersandHelpers.toChar)or_toCharFallback split=HelpersandHelpers.split end -- Try both RDj[a]-X and RDj[A]-X; falls back to "" if not present localfunctionreadPerHeaderArg(j,k,suffix) localch=toChar(k)-- e.g. 'a' with Helpers.toChar localkey1="RD"..j..ch..suffix localv=bargs(key1) ifv~=nilandv~=""then returnv end localkey2="RD"..j..string.upper(ch)..suffix v=bargs(key2) ifv~=nilandv~=""then returnv end return"" end -- ========================= -- 2) ARG HELPERS -- ========================= -- Trim + split a comma list frame arg (returns {} on blank) localfunctionreadCsvArg(name) localraw=(getFArg(name)or""):gsub("%s+","") returnsplit(raw,{","},true) end -- ======================================== -- 3) BUILD SKELETON (formerly getCells) -- ======================================== localfunctionbuildSkeleton() localDEFAULT_TPM=2 localmaxrow=1 localcolentry={} localhasNoHeaders=true -- ensure containers state.entries=state.entriesor{} state.shift=state.shiftor{} state.teamsPerMatch=state.teamsPerMatchor{} state.maxtpm=state.maxtpmor0 localCmin,Cmax=config.minc,config.c -- Phase 1: Determine header presence and teamsPerMatch forj=Cmin,Cmaxdo ifnotempty(getFArg("col"..j.."-headers"))then hasNoHeaders=false end localtpm= tonumber(getFArg("RD"..j.."-teams-per-match"))ortonumber(getFArg("col"..j.."-teams-per-match"))or tonumber(getFArg("teams-per-match"))or DEFAULT_TPM state.teamsPerMatch[j]=tpm iftpm>state.maxtpmthen state.maxtpm=tpm end end -- Phase 2: Build colentry for each column forj=Cmin,Cmaxdo state.entries[j]={} state.shift[j]=tonumber(bargs("RD"..j.."-shift"))ortonumber(bargs("shift"))or0 colentry[j]={ readCsvArg("col"..j.."-headers"), readCsvArg("col"..j.."-matches"), readCsvArg("col"..j.."-lines"), readCsvArg("col"..j.."-text"), readCsvArg("col"..j.."-groups")-- reserved for user-specified groups } -- inject a default header if none were specified anywhere (unless noheaders=y/yes) localnoheaders=(getFArg("noheaders")or""):lower() ifhasNoHeadersand(noheaders~="y"andnoheaders~="yes")then t_insert(colentry[j][1],1) end end -- Ctype mapping for colentry positions localCTYPE_MAP={"header","team","line","text","group"} -- Helpers to populate entries (preserve legacy shapes) localfunctionpopulateTeam(j,rowIndex,n) localTPM=state.teamsPerMatch[j] -- scaffold a text row above when needed (legacy behavior) ifstate.entries[j][rowIndex-1]==nilandstate.entries[j][rowIndex-2]==nilthen state.entries[j][rowIndex-2]={ctype="text",index=n} state.entries[j][rowIndex-1]={ctype="blank"} end -- first team (top) state.entries[j][rowIndex]={ctype="team",index=TPM*n-(TPM-1),position="top"} state.entries[j][rowIndex+1]={ctype="blank"} -- remaining teams in the match (every 2 rows) form=2,TPMdo localidx=TPM*n-(TPM-m) localr=rowIndex+2*(m-1) state.entries[j][r]={ctype="team",index=idx} state.entries[j][r+1]={ctype="blank"} end end localfunctionpopulateText(j,rowIndex,index) state.entries[j][rowIndex]={ctype="text",index=index} state.entries[j][rowIndex+1]={ctype="blank"} end localfunctionpopulateLine(j,rowIndex) -- first segment draws its bottom edge state.entries[j][rowIndex]={ctype="line",border="bottom"} state.entries[j][rowIndex+1]={ctype="blank"} -- second segment draws its top edge state.entries[j][rowIndex+2]={ctype="line",border="top"} state.entries[j][rowIndex+3]={ctype="blank"} end localfunctionpopulateGroup(j,rowIndex,n) state.entries[j][rowIndex]={ctype="group",index=n} state.entries[j][rowIndex+1]={ctype="blank"} end localfunctionpopulateDefault(j,rowIndex,n) state.entries[j][rowIndex]={ctype="header",index=n,position="top"} state.entries[j][rowIndex+1]={ctype="blank"} end -- Phase 3: Populate entries for each column forj=Cmin,Cmaxdo localtextindex=0 localTPM=state.teamsPerMatch[j] localshiftJ=state.shift[j] fork,positionsinipairs(colentry[j])do t_sort(positions) localctype=CTYPE_MAP[k] forn=1,#positionsdo ifshiftJ~=0andpositions[n]>1then positions[n]=positions[n]+shiftJ end localrowIndex=2*positions[n]-1 locallastRow=rowIndex+2*TPM-1 iflastRow>maxrowthen maxrow=lastRow end ifctype=="team"then populateTeam(j,rowIndex,n) textindex=n elseifctype=="text"then populateText(j,rowIndex,textindex+n) elseifctype=="line"then populateLine(j,rowIndex) elseifctype=="group"then populateGroup(j,rowIndex,n) else populateDefault(j,rowIndex,n) end end end end ifisempty(config.r)then config.r=maxrow end end -- ======================================== -- 4) NAME RESOLUTION HELPERS -- ======================================== localfunctionparamNames(cname,j,i,l) localfunctiongetArg(key) returnbargs(key)or"" end localfunctiongetP(key) returngetPArg(key)or"" end locale=state.entries[j][i] localRD="RD"..j localhidx=e.headerindex localhchar=toChar(hidx) localRDh=RD..hchar localSYNONYMS={legs={"legs","sets"}} -- Try a list of names against base+index(+suffix); returns first non-empty localfunctiontryAny(base,names,idx,suffix) suffix=suffixor"" for_,nminipairs(names)do locala=bargs(base.."-"..nm..idx..suffix)or"" ifisempty(a)then a=bargs(base.."-"..nm..string.format("%02d",idx)..suffix)or"" end ifnotempty(a)then returna end end return"" end localfunctiontryBoth(base,name,idx,suffix) suffix=suffixor"" locala=getArg(base.."-"..name..idx..suffix) ifisempty(a)then a=getArg(base.."-"..name..str_format("%02d",idx)..suffix) end returna end -- Round names (prefer altname when present) localRDlabel=getArg(RD.."-altname")orRD localRDhlabel=getArg(RDh.."-altname")orRDh localrname={{RD,RDlabel},{RDh,RDhlabel}} localname={cname,getArg(cname.."-altname")orcname} localnameKeys=SYNONYMS[cname]or{name[1]} localindex={e.index,e.altindex} localresult={} ifcname=="header"then ifhidx==1then for_,baseinipairs({rname[1],rname[2]})do fork=2,1,-1do result[#result+1]=getArg(base[k]) end end else fork=2,1,-1do result[#result+1]=getArg(rname[2][k]) end end elseifcname=="pheader"then ifhidx==1then for_,baseinipairs({rname[1],rname[2]})do fork=2,1,-1do result[#result+1]=getP(base[k]) end end else fork=2,1,-1do result[#result+1]=getP(rname[2][k]) end end elseifcname=="score"then localbases={rname[2][2],rname[2][1],rname[1][2],rname[1][1]} localidxs={index[2],index[2],index[1],index[1]} forn=1,4do ifl==1then result[#result+1]=tryAny(bases[n],nameKeys,idxs[n]) end result[#result+1]=tryAny(bases[n],nameKeys,idxs[n],"-"..l) end elseifcname=="shade"then fork=2,1,-1do localbase=(hidx==1)andrname[1][k]orrname[2][k] result[#result+1]=getArg(base.."-"..name[1]) end result[#result+1]=getArg("RD-shade") result[#result+1]=(config.COLORSandconfig.COLORS.cell_bg_dark)or"#eaecf0" elseifcname=="text"then localbases={rname[2][2],rname[2][1],rname[1][2],rname[1][1]} localidxs={index[2],index[2],index[1],index[1]} localnames={name[2],name[1]} forni=1,2do forn=1,4do result[#result+1]=tryBoth(bases[n],names[ni],idxs[n]) end end else localbases={rname[2][2],rname[2][1],rname[1][2],rname[1][1]} localidxs={index[2],index[2],index[1],index[1]} forn=1,4do result[#result+1]=tryAny(bases[n],nameKeys,idxs[n]) end end for_,valinipairs(result)do ifnotempty(val)then returnval end end return"" end -- ======================================== -- 5) NUMBERED PARAM MODE -- ======================================== localmasterindex=1 localfunctionnumberedParams(j) localrow=state.entries[j] ifnotrowthen return end localfunctionnextArg() localv=bargs(tostring(masterindex))or"" masterindex=masterindex+1 returnv end localR=config.r fori=1,Rdo locale=row[i] ifethen localct=e.ctype ifct=="team"then locallegs=state.rlegs[j] ifconfig.forceseedsthen e.seed=nextArg() end e.team=nextArg() e.legs=paramNames("legs",j,i) e.score={weight={}} e.weight="normal" ifnotempty(e.legs)then legs=tonumber(e.legs)orlegs end forl=1,legsdo e.score[l]=nextArg() e.score.weight[l]="normal" end ifconfig.aggregateandlegs>1then e.score.agg=nextArg() e.score.weight.agg="normal" end elseifct=="header"then e.header=paramNames("header",j,i) e.pheader=paramNames("pheader",j,i) e.shade=paramNames("shade",j,i) elseifct=="text"then e.text=nextArg() elseifct=="group"then e.group=nextArg() elseifct=="line"ande.hastext==truethen e.text=nextArg() end end end end -- ======================================== -- 6) NAMED MODE ASSIGNERS (per-ctype) -- ======================================== localfunctioncellHasMeaningfulContent(e) ifnotethen returnfalse end ife.ctype=="team"then returnnotempty(e.team) end ife.ctype=="text"then returnnotempty(e.text) end ife.ctype=="group"then returnnotempty(e.group) end ife.ctype=="line"ande.hastext==truethen returnnotempty(e.text) end returnfalse end localfunctionenforceContentUnhide(j) ifnot(state.hideandstate.hide[j])then return end localexplicit=(state._hideExplicitandstate._hideExplicit[j])or{} localR=config.r -- If master hid a header, but we later discover content in that header, -- flip it visible unless there was an EXPLICIT per-header hide. fori=1,Rdo locale=state.entries[j][i] ifeande.headerindexthen localh=e.headerindex ifstate.hide[j][h]andcellHasMeaningfulContent(e)then state.hide[j][h]=false end end end end localfunctionassignTeamParams(j,i) locallegs=state.rlegs[j] locale=state.entries[j][i] e.seed=paramNames("seed",j,i) e.team=paramNames("team",j,i) e.legs=paramNames("legs",j,i) e.score={weight={}} e.weight="normal" ifnotempty(e.legs)then legs=tonumber(e.legs)orlegs end ifconfig.autolegsthen locall=1 repeat e.score[l]=paramNames("score",j,i,l) e.score.weight[l]="normal" l=l+1 untilisempty(paramNames("score",j,i,l)) legs=l-1 else forl=1,legsdo e.score[l]=paramNames("score",j,i,l) e.score.weight[l]="normal" end end ifconfig.aggregateandlegs>1then e.score.agg=paramNames("score",j,i,"agg") e.score.weight.agg="normal" end end localfunctionassignHeaderParams(j,i) locale=state.entries[j][i] e.header=paramNames("header",j,i) e.pheader=paramNames("pheader",j,i) e.shade=paramNames("shade",j,i) -- Did shade originate from an RD*-shade param? localhchar=toChar(e.headerindex) localrdNames={ "RD"..j.."-shade", "RD"..j..hchar.."-shade", "RD-shade" } e.shade_is_rd=false for_,pnameinipairs(rdNames)do localv=bargs(pname) ifnotempty(v)ande.shade==vthen e.shade_is_rd=true break end end end localfunctionassignTextParams(j,i) state.entries[j][i].text=paramNames("text",j,i) end localfunctionassignGroupParams(j,i) state.entries[j][i].group=paramNames("group",j,i) end localfunctionassignLineTextParams(j,i) state.entries[j][i].text=paramNames("text",j,i) end -- ======================================== -- 7) TABLE-WIDE ASSIGNMENT PASS -- ======================================== localfunctiongetScalarRoundParam(j,bases)-- e.g. {"legs","sets"} -- prefer per-round keys, then global for_,baseinipairs(bases)do localv=bargs("RD"..j.."-"..base) ifnotempty(v)then returnv end end for_,baseinipairs(bases)do localv=bargs(base) ifnotempty(v)then returnv end end return"" end localfunctionassignParams() masterindex=1 localmaxcol=1 localCmin,Cmax,R=config.minc,config.c,config.r forj=Cmin,Cmaxdo -- prepare per-round containers state.hide[j]=state.hide[j]or{} state.byes[j]=state.byes[j]or{} -- Set legs for this column localvlegs=getScalarRoundParam(j,{"legs","sets"}) state.rlegs[j]=tonumber(vlegs)or1 ifnotempty(vlegs)then config.autolegs=false end -- assign params ifconfig.paramstyle=="numbered"then numberedParams(j) else localcol=state.entries[j] fori=1,Rdo localcell=col[i] ifcell~=nilthen localct=cell.ctype ifct=="team"then assignTeamParams(j,i) elseifct=="header"then assignHeaderParams(j,i) elseifct=="text"then assignTextParams(j,i) elseifct=="group"then assignGroupParams(j,i) elseifct=="line"andcell.hastext==truethen assignLineTextParams(j,i) end end ifconfig.autocolandnotStateChecks.isBlankEntry(j,i)andj>maxcolthen maxcol=j end end end enforceContentUnhide(j) -- parent header text forces visible fori=1,Rdo locale=state.entries[j][i] ifeande.ctype=="header"then localhidx=e.headerindex if(Helpers.notemptyandHelpers.notempty(e.pheader))then state.hide[j][hidx]=false end end end end ifconfig.autocolthen config.c=maxcol end end -- ======================================== -- 8) STRUCTURE DISCOVERY (hide/byes/indices) -- ======================================== localfunctiongetHide(j) state.hide[j]={} state._hideExplicit=state._hideExplicitor{} state._hideExplicit[j]={} -- master round-level hide flag: RD{j}-hide localmasterRaw=bargs("RD"..j.."-hide")or"" localmasterOn=(HelpersandHelpers.yesandHelpers.yes(masterRaw))orfalse fork=1,state.headerindex[j]do state.hide[j][k]=masterOn -- per-header override localrh=readPerHeaderArg(j,k,"-hide") ifrh~=""then ifHelpersandHelpers.yesandHelpers.yes(rh)then state.hide[j][k]=true state._hideExplicit[j][k]=true elseifHelpersandHelpers.noandHelpers.no(rh)then state.hide[j][k]=false state._hideExplicit[j][k]=true end end end end localfunctiongetByes(j) state.byes[j]={} fork=1,state.headerindex[j]do -- global byes localbyes=(bargs("byes")or""):lower() if(Helpers.yesandHelpers.yes(byes))then state.byes[j][k]=true elseiftonumber(byes)then state.byes[j][k]=(j<=tonumber(byes)) else state.byes[j][k]=false end -- per-round byes localr=(bargs("RD"..j.."-byes")or""):lower() if(Helpers.yesandHelpers.yes(r))then state.byes[j][k]=true elseifr=="no"orr=="n"then state.byes[j][k]=false end -- per-header byes localrh=(readPerHeaderArg(j,k,"-byes")or""):lower() if(Helpers.yesandHelpers.yes(rh))then state.byes[j][k]=true elseifrh=="no"orrh=="n"then state.byes[j][k]=false end end end localfunctiongetAltIndices() localCmin,Cmax,R=config.minc,config.c,config.r forj=Cmin,Cmaxdo state.headerindex[j]=0 -- per-round counters localteamindex,textindex,groupindex=1,1,1 localrow=state.entries[j] -- if the very first cell is nil, bump headerindex once (legacy quirk) ifrowandrow[1]==nilthen state.headerindex[j]=state.headerindex[j]+1 end -- walk rows in the round fori=1,Rdo locale=rowandrow[i]ornil ifethen localct=e.ctype ifct=="header"then e.altindex=state.headerindex[j] teamindex,textindex=1,1 state.headerindex[j]=state.headerindex[j]+1 elseifct=="team"then e.altindex=teamindex teamindex=teamindex+1 elseifct=="text"or(ct=="line"ande.hastext==true)then e.altindex=textindex textindex=textindex+1 elseifct=="group"then e.altindex=groupindex groupindex=groupindex+1 end e.headerindex=state.headerindex[j] end end getByes(j) getHide(j) end end -- ======================================== -- 9) PUBLIC API -- ======================================== functionParams.buildSkeleton(_state,_config,_Helpers,_StateChecks) bind(_state,_config,_Helpers,_StateChecks) buildSkeleton() end functionParams.scanStructure(_state,_config,_Helpers,_StateChecks) bind(_state,_config,_Helpers,_StateChecks) getAltIndices() end functionParams.assign(_state,_config,_Helpers,_StateChecks) bind(_state,_config,_Helpers,_StateChecks) assignParams() end -- ======================================== -- 10) SLICING FOR MIN ROUND (base offset) -- ======================================== localfunctionshiftCols(tbl,base,c) ifnottblthen return{} end localout={} forj=base+1,cdo out[j-base]=tbl[j] end returnout end functionParams.sliceForMinround(_state,_config) localbase=_config.baseor0 ifbase<=0then return end localoldC=_config.c localnewC=oldC-base ifnewC<1then newC=1 end -- Shift all column-indexed tables _state.entries=shiftCols(_state.entries,base,oldC) _state.headerindex=shiftCols(_state.headerindex,base,oldC) _state.rlegs=shiftCols(_state.rlegs,base,oldC) _state.maxlegs={}-- recompute later _state.hascross={}-- rebuild later _state.crossCell={}-- rebuild later _state.pathCell={}-- rebuild later _state.skipPath={}-- rebuild later _state.hide=shiftCols(_state.hide,base,oldC) _state.byes=shiftCols(_state.byes,base,oldC) _state.teamsPerMatch=shiftCols(_state.teamsPerMatch,base,oldC) _state.matchgroup={}-- recompute -- Update view range: now we render 1..newC _config.c=newC _config.minc=1 end returnParams