Jump to content
Wikipedia The Free Encyclopedia

Module:Sandbox/Pbrks

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 (create | mirror) and testcases (create) pages.
Add categories to the /doc subpage. Subpages of this module.
 ---
 --- Build Bracket (refactor skeleton)
 --- Goal: separate data phases, minimize mutation, clarify responsibilities.
 --- This is a FIRST PASS skeleton wired to p.main(frame).
 --- We'll port functionality in phases while keeping the public API.
 ---

 localp={}

 -- =====================
 -- Localized stdlib
 -- =====================
 localstr_gsub,str_match,str_find=string.gsub,string.match,string.find
 localt_insert,t_sort,t_concat=table.insert,table.sort,table.concat
 localm_max,m_min,m_ceil=math.max,math.min,math.ceil
 localtonumber,tostring=tonumber,tostring
 localpairs,ipairs,type=pairs,ipairs,type

 localmw_html_create=mwandmw.htmlandmw.html.create

 -- =====================
 -- Small utilities (pure)
 -- =====================
 localfunctionisempty(s)returns==nilors==''end
 localfunctionnotempty(s)returns~=nilands~=''end
 localfunctionyesish(v)
 v=(tostring(vor''):lower())
 returnv=='y'orv=='yes'orv=='true'orv=='1'
 end
 localfunctionnoish(v)
 v=(tostring(vor''):lower())
 returnv=='n'orv=='no'orv=='false'orv=='0'
 end
 localfunctiontoChar(num)returnstring.char(string.byte('a')+num-1)end

 -- =====================
 -- Types (documentation only)
 -- =====================
 -- Config = {
 -- c:number, r:number|nil, minc:number,
 -- autocol:boolean, autolegs:boolean,
 -- seeds:boolean, forceseeds:boolean,
 -- boldwinner_mode:'off'|'high'|'low', boldwinner_aggonly:boolean,
 -- aggregate:boolean, aggregate_mode:'off'|'manual'|'sets'|'score',
 -- colspacing:number, height:number, nowrap:boolean,
 -- paramstyle:'indexed'|'numbered',
 -- }
 --
 -- Grid[j][i] = Cell where Cell has a stable shape:
 -- { ctype='header'|'team'|'text'|'line'|'group'|'blank',
 -- index:number?, altindex:number?, headerindex:number?,
 -- position:'top'|nil,
 -- team:string?, seed:string?,
 -- legs:number?,
 -- score={ [1]=string?, [2]=string?, agg=string?, weight=table }?,
 -- weight:'bold'|'normal'|nil,
 -- pheader:string?, header:string?, shade:string?, shade_is_rd:boolean?,
 -- group:string?, colspan:number?,
 -- borderWidth:{number,number,number,number}? ,
 -- border:'top'|'bottom'|'both'|nil,
 -- }
 --
 -- Derived = {
 -- rlegs = { [j]=number },
 -- maxlegs = { [j]=number },
 -- teamsPerMatch = { [j]=number },
 -- headercount = { [j]=number },
 -- hide = { [j] = { [headerindex]=true } },
 -- byes = { [j] = { [headerindex]=true } },
 -- matchgroup = { [j] = { [i]=groupId } },
 -- pathCell, crossCell, skipPath, hascross, shift,
 -- }

 -- =====================
 -- Phase 0. Arg access
 -- =====================
 localfunctionmakeArgReaders(frame)
 localfargs=frame.argsor{}
 localpargs=(frame.getParentandframe:getParent().args)or{}
 localfunctionbargs(k)returnpargs[k]orfargs[k]end
 returnfargs,pargs,bargs
 end

 -- =====================
 -- Phase 1. Parse args → Config (pure)
 -- =====================
 localfunctionparseConfig(fargs,pargs,bargs)
 localcfg={
 r=tonumber(fargs.rows)ornil,
 c=tonumber(fargs.rounds)or1,
 minc=tonumber(pargs.minround)or1,

 autocol=yesish(fargs.autocol),
 colspacing=tonumber(fargs['col-spacing'])or5,
 height=bargs('height')or0,

 -- seeds
 forceseeds=yesish(pargs.seeds),
 seeds=notnoish(pargs.seeds),

 -- boldwinner
 boldwinner_mode='off',
 boldwinner_aggonly=false,

 -- aggregate
 aggregate=false,
 aggregate_mode='off',

 autolegs=yesish(pargs.autolegs),
 paramstyle=(bargs('paramstyle')=='numbered')and'numbered'or'indexed',
 nowrap=notnoish(pargs.nowrap),

 deprecation_category='Pages using Build Bracket with deprecated parameters',
 }

 -- rounds override via maxround(s)
 localmaxc=tonumber(pargs.maxrounds)ortonumber(pargs.maxround)
 ifmaxcthencfg.c=maxcend

 -- boldwinner legacy switch mapping
 do
 localbw=(bargs('boldwinner')or''):lower()
 ifbw=='low'thencfg.boldwinner_mode='low'
 elseifbw=='high'oryesish(bw)thencfg.boldwinner_mode='high'
 elseifbw=='aggregate'orbw=='agg'orbw=='aggregate-high'orbw=='agg-high'then
 cfg.boldwinner_mode='high';cfg.boldwinner_aggonly=true
 elseifbw=='aggregate-low'orbw=='agg-low'then
 cfg.boldwinner_mode='low';cfg.boldwinner_aggonly=true
 end
 ifyesish(bargs('boldwinner-aggregate-only'))thencfg.boldwinner_aggonly=trueend
 end

 -- aggregate mode
 do
 localaval=(bargs('aggregate')or''):lower()
 ifaval=='sets'oraval=='legs'then
 cfg.aggregate_mode='sets';cfg.aggregate=true
 elseifaval=='score'then
 cfg.aggregate_mode='score';cfg.aggregate=true
 elseifyesish(aval)then
 cfg.aggregate_mode='manual';cfg.aggregate=true
 else
 cfg.aggregate_mode='off';cfg.aggregate=false
 end
 end

 returncfg
 end

 -- =====================
 -- Phase 2. Build initial grid (headers/teams/lines/text) → Grid
 -- NOTE: This mirrors the original getCells(), but returns a new grid and a
 -- small Derived stub. We keep arg names compatible (colX-headers, etc.).
 -- =====================
 localfunctionsplitCSVInts(s)
 ifisempty(s)thenreturn{}end
 localout={}
 s=s:gsub('%s+','')
 fornins:gmatch('[^,]+')do
 localv=tonumber(n)
 ifvthent_insert(out,v)end
 end
 returnout
 end

 localfunctionbuildInitialGrid(cfg,fargs,pargs,bargs)
 localgrid={}
 localderived={
 teamsPerMatch={},
 shift={},
 maxtpm=1,
 }

 localDEFAULT_TPM=2

 -- detect explicit headers
 localhasHeaders=false
 forj=cfg.minc,cfg.cdo
 ifnotisempty(fargs['col'..j..'-headers'])thenhasHeaders=trueend
 end

 -- pass 1: get tpm per round and track maxtpm
 forj=cfg.minc,cfg.cdo
 localtpm=tonumber(fargs['RD'..j..'-teams-per-match'])
 ortonumber(fargs['col'..j..'-teams-per-match'])
 ortonumber(fargs['teams-per-match'])
 orDEFAULT_TPM
 derived.teamsPerMatch[j]=tpm
 iftpm>(derived.maxtpmor1)thenderived.maxtpm=tpmend
 end

 -- pass 2: populate skeleton cells
 localmaxrow=1
 forj=cfg.minc,cfg.cdo
 grid[j]={}
 derived.shift[j]=tonumber(bargs('RD'..j..'-shift'))ortonumber(bargs('shift'))or0

 localheaders=splitCSVInts(fargs['col'..j..'-headers']or'')
 localmatches=splitCSVInts(fargs['col'..j..'-matches']or'')
 locallines=splitCSVInts(fargs['col'..j..'-lines']or'')
 localtexts=splitCSVInts(fargs['col'..j..'-text']or'')

 -- Auto-insert a header if no explicit headers passed anywhere and noheaders flag not set.
 ifnothasHeadersand(fargs['noheaders']~='y'andfargs['noheaders']~='yes')then
 t_insert(headers,1)
 end

 localfunctionmark(i,cell)
 grid[j][i]=cell
 end

 localfunctionpopulateHeader(pos)
 locali=2*(pos+(derived.shift[j]or0))-1
 mark(i,{ctype='header',index=#headers,position='top'})
 mark(i+1,{ctype='blank'})
 maxrow=m_max(maxrow,i+1)
 end

 localfunctionpopulateTeamGroup(n)
 localstart=2*(n+(derived.shift[j]or0))-1
 -- ensure a text row before first team block
 ifgrid[j][start-1]==nilandgrid[j][start-2]==nilthen
 mark(start-2,{ctype='text',index=n})
 mark(start-1,{ctype='blank'})
 end
 -- top team
 mark(start,{ctype='team',index=derived.teamsPerMatch[j]*n-(derived.teamsPerMatch[j]-1),position='top'})
 mark(start+1,{ctype='blank'})
 -- remaining teams in match
 form=2,derived.teamsPerMatch[j]do
 localidx=derived.teamsPerMatch[j]*n-(derived.teamsPerMatch[j]-m)
 localrow=start+2*(m-1)
 mark(row,{ctype='team',index=idx})
 mark(row+1,{ctype='blank'})
 end
 maxrow=m_max(maxrow,start+2*derived.teamsPerMatch[j]-1)
 end

 localfunctionpopulateLine(pos)
 locali=2*(pos+(derived.shift[j]or0))-1
 mark(i,{ctype='line',border='bottom'})
 mark(i+1,{ctype='blank'})
 mark(i+2,{ctype='line',border='top'})
 mark(i+3,{ctype='blank'})
 maxrow=m_max(maxrow,i+3)
 end

 localfunctionpopulateText(pos,textindex)
 locali=2*(pos+(derived.shift[j]or0))-1
 mark(i,{ctype='text',index=textindex})
 mark(i+1,{ctype='blank'})
 maxrow=m_max(maxrow,i+1)
 end

 -- Sorted application keeps row math simple
 table.sort(headers);table.sort(matches);table.sort(lines);table.sort(texts)

 localtextindexCounter=0
 for_,posinipairs(headers)dopopulateHeader(pos)end
 forn,_inipairs(matches)dopopulateTeamGroup(n)end
 for_,posinipairs(lines)dopopulateLine(pos)end
 fork,_inipairs(texts)dotextindexCounter=textindexCounter+1;populateText(texts[k],#matches+textindexCounter)end
 end

 -- finalize row count
 ifcfg.r==nilthen
 localmr=1
 forj=cfg.minc,cfg.cdo
 fori,_inpairs(grid[j])doifi>mrthenmr=iendend
 end
 cfg.r=mr
 end

 returngrid,derived
 end

 -- =====================
 -- Phase 3+. Placeholders to port next
 -- =====================
 localfunctioncomputeAltIndices(grid,cfg,fargs,pargs,bargs)
 -- TODO: port getAltIndices() but return: headercount[j], and set .altindex/.headerindex on cells (pure-ISH)
 localheadercount={}
 forj=cfg.minc,cfg.cdo
 headercount[j]=0
 localteamindex,textindex,groupindex=1,1,1
 localrow=grid[j]
 ifrowandrow[1]==nilthenheadercount[j]=headercount[j]+1end
 fori=1,cfg.rdo
 locale=rowandrow[i]
 ifethen
 ife.ctype=='header'thene.altindex=headercount[j];teamindex,textindex=1,1;headercount[j]=headercount[j]+1
 elseife.ctype=='team'thene.altindex=teamindex;teamindex=teamindex+1
 elseife.ctype=='text'thene.altindex=textindex;textindex=textindex+1
 elseife.ctype=='group'thene.altindex=groupindex;groupindex=groupindex+1end
 e.headerindex=headercount[j]
 end
 end
 end
 returnheadercount
 end

 localfunctioncomputeHideAndByes(grid,cfg,bargs,headercount)
 -- Lua 5.1-safe (no goto). Port of getHide/getByes and a basic empty-round hide pass.
 localhide,byes={},{}
 forj=cfg.minc,cfg.cdo
 hide[j],byes[j]={},{}
 fork=1,(headercount[j]or0)do
 -- hide flags
 localh=bargs('RD'..j..toChar(k)..'-hide')
 hide[j][k]=(h=='y'orh=='yes')andtrueorfalse

 -- byes: global, RDj, RDja (last writer wins, matching original precedence)
 localv=false
 localglobalByes=bargs('byes')
 ifyesish(globalByes)thenv=true
 elseiftonumber(globalByes)andj<=tonumber(globalByes)thenv=trueend
 localrd=bargs('RD'..j..'-byes');ifyesish(rd)thenv=trueelseifnoish(rd)thenv=falseend
 localrda=bargs('RD'..j..toChar(k)..'-byes');ifyesish(rda)thenv=trueend
 byes[j][k]=v
 end
 end

 -- helper
 localfunctionisBlankEntry(j,i)
 localcol=grid[j];locale=colandcol[i]
 ifnotethenreturntrueend
 ife.ctype=='team'thenreturn(e.team==nilore.team=='')and(e.text==nilore.text=='')end
 ife.ctype=='text'thenreturn(e.text==nilore.text=='')end
 returnfalse
 end

 -- hide empty-header rounds (no goto; nest conditions)
 forj=cfg.minc,cfg.cdo
 fori=1,cfg.rdo
 locale=grid[j]andgrid[j][i]
 ifeande.ctype=='header'then
 localhidx=e.headerindex
 ifhidxthen
 localrow=i+1;localany=false
 whilerow<=cfg.rdo
 localrce=grid[j][row]
 ifrceandrce.ctype=='header'thenbreakend
 ifrceandrce.ctype~='blank'andnotisBlankEntry(j,row)thenany=true;breakend
 row=row+1
 end
 ifnotanythenhide[j][hidx]=hide[j][hidx]ortrueend
 end
 end
 end
 end
 returnhide,byes
 end

 -- Assign parameters (seed/team/score/header/text/group/line text)
 localfunctionassignParams(grid,cfg,fargs,pargs,bargs,derived)
 -- TODO: port paramNames() logic; for now, minimal pass to keep structure.
 returngrid-- unchanged placeholder
 end

 -- Aggregates & bolding (pure)
 localfunctioncomputeAggregatesAndBold(grid,cfg,derived)
 -- TODO: port computeAggregate() and boldWinner() in a pure style.
 end

 -- Paths (pure data) and post-processing merges
 localfunctioncomputePaths(grid,cfg,fargs,pargs,bargs,derived)
 -- TODO: port getPaths() and connect logic but return pathCell/crossCell/skipPath/hascross; do not mutate grid here.
 derived.pathCell,derived.crossCell,derived.skipPath,derived.hascross={},{},{},{}
 returnderived
 end

 localfunctionupdateMaxLegs(grid,cfg,derived)
 -- TODO: port updateMaxLegs() against current grid entries
 derived.rlegs,derived.maxlegs=derived.rlegsor{},derived.maxlegsor{}
 forj=cfg.minc,cfg.cdo
 derived.rlegs[j]=derived.rlegs[j]or1
 derived.maxlegs[j]=derived.maxlegs[j]orderived.rlegs[j]
 end
 end

 -- =====================
 -- Rendering (impure, view-only, no surprises)
 -- =====================
 localCOLORS={
 cell_bg_light='var(--background-color-neutral-subtle,#f8f9fa)',
 cell_bg_dark='var(--background-color-neutral,#eaecf0)',
 text_color='var(--color-base,#202122)',
 path_line_color='gray',
 cell_border='var(--border-color-base,#a2a9b1)'
 }

 localfunctioncellBorder(b)return(b[1]..'px '..b[2]..'px '..b[3]..'px '..b[4]..'px')end

 localfunctionrenderTable(grid,cfg,derived)
 localframe=mw.getCurrentFrame()
 localdiv=mw_html_create('div'):css('overflow','auto')
 div:wikitext(frame:extensionTag('templatestyles','',{src='Module:Build bracket/styles.css'}))
 ifcfg.height~=0thendiv:css('height',cfg.height)end

 localtbl=mw_html_create('table'):addClass('brk')
 ifcfg.nowrapthentbl:addClass('brk-nw')end

 -- invisible header row for col widths (placeholder; widths will depend on derived.maxlegs)
 tbl:tag('tr'):css('visibility','collapse'):tag('td'):css('width','1px')

 -- TODO: set width cells using derived.maxlegs/aggregate/seeds just like original

 fori=1,cfg.rdo
 localrow=tbl:tag('tr')
 row:tag('td'):css('height','11px')
 forj=cfg.minc,cfg.cdo
 locale=grid[j]andgrid[j][i]
 localtd=row:tag('td')
 ifethen
 td:wikitext(e.ctypeor''):css('font-size','smaller'):css('color','#666')
 else
 td:wikitext('')
 end
 -- TODO: replace with real insertors once phases are fully ported
 end
 end

 div:wikitext(tostring(tbl))
 returntostring(div)
 end

 -- =====================
 -- Deprecation cats (kept simple for now)
 -- =====================
 localfunctionemitDeprecationCats()
 localtitle=mw.title.getCurrentTitle()
 ifnottitleortitle.namespace~=0thenreturn''end
 return''
 end

 -- =====================
 -- MAIN
 -- =====================
 functionp.main(frame)
 -- Styles once
 frame:extensionTag('templatestyles','',{src='Module:Build bracket/styles.css'})

 -- Phase 0/1
 localfargs,pargs,bargs=makeArgReaders(frame)
 localcfg=parseConfig(fargs,pargs,bargs)

 -- Phase 2
 localgrid,derived=buildInitialGrid(cfg,fargs,pargs,bargs)

 -- Phase 3+
 derived.headercount=computeAltIndices(grid,cfg,fargs,pargs,bargs)
 derived.hide,derived.byes=computeHideAndByes(grid,cfg,bargs,derived.headercount)
 grid=assignParams(grid,cfg,fargs,pargs,bargs,derived)
 computeAggregatesAndBold(grid,cfg,derived)
 computePaths(grid,cfg,fargs,pargs,bargs,derived)
 updateMaxLegs(grid,cfg,derived)

 -- Output
 localout=renderTable(grid,cfg,derived)
 returntostring(out)..emitDeprecationCats()
 end

 returnp

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