置顶公告:【置顶】关于临时开启评论区所有功能的公告(2022.10.22) | 【置顶】关于本站Widget恢复使用的公告
  • 你好~!欢迎来到萌娘百科镜像站!如需查看或编辑,请联系本站管理员注册账号。
  • 本镜像站和其他萌娘百科的镜像站无关,请注意分别。

Module:TeamBracket

猛汉♂百科,万男皆可猛的百科全书!转载请标注来源页面的网页链接,并声明引自猛汉百科。内容不可商用。
跳到导航 跳到搜索
Template-info.svg 模块文档  [查看] [编辑] [历史] [刷新]

此模块用于实现比赛进程模板Template:16TeamBracket等的功能。

使用方法

{{#invoke: TeamBracket | teamBracket
| rounds      =

| seed-width  =
| team-width  =
| score-width =

| RD1         =
| RD1-group1  =
| RD1-seed1   =
| RD1-team1   =
| RD1-score1  =
 ...
}}

参数用法

rounds –比赛回合数。
seed-width – 选手编号列宽度。(可不填)
team-width – 选手列宽度。(可不填)
score-width – 得分(比赛结果)宽度。(可不填)
seeds – 当参数为no时隐藏全部选手号码。
compact – 当参数位yes时,禁用全部小组名。
RDn第“n”轮比赛名称。
RDn-groupm第“n”轮第“m”小组名称。
RDn-seedm“m”选手第“n”轮编号。
RDn-teamm第“n”轮“m”选手名称。
RDn-scorem“m”选手在第“n”轮比赛中的得分(比赛结果)。

参数含义

seed-width
选手编号列宽度(不填时根据内容自适应)。对应值:
N [em/%/px]
auto
team-width
选手名称列宽度(不填时根据内容自适应)。
score-width
得分(比赛结果)列编号列宽度(不填时根据内容自适应)。
RDn
每轮比赛的名字,默认值为:“m”强赛……“四分之一决赛”,“半决赛”,“决赛”,其中“m”为当前这轮比赛中队伍的总和。
RDn-groupm
第n轮第第“m”小组名称。每轮比赛四队为一个小组。
RDn-seedm
队伍m在第n轮的号码。在第一轮比赛中,默认值为锦标赛中惯用的队伍编号(第一轮赛时)。如果省略,除第1轮赛以外的Seed列都会被隐藏。如需隐藏第1轮比赛中队伍的号码,请不要设置第一轮赛中队伍的号码,并将Seeds参数设为“no”。“m”的值从1开始。
RDn-teamm
队伍m在第n轮的名称。“m”的值从1开始。
RDn-scorem
::队伍m在第n轮的得分(比赛结果)。“m”的值从1开始。

用例

无号码

{{#invoke: TeamBracket | teamBracket
| rounds    = 2
| RD1-seed1 =
| RD1-seed2 =
| RD1-seed3 =
| RD1-seed4 =
}}
半决赛 决赛
      
 
 
 
 
 
 

分组

{{#invoke: TeamBracket | teamBracket
| rounds     = 3
| RD1-group1 = 1月4日
| RD1-group2 = 1月5日
| RD2-group1 = 1月6日
}}
四分之一决赛 半决赛 决赛
         
1  
8  
 
1月4日
 
5  
4  
 
1月6日
 
3  
6  
 
1月5日
 
7  
2  
  1. --
  2. -- This module will implement {{TeamBracket}}
  3. --
  4. local p = {}
  5. local args
  6. local rounds
  7. local padding
  8. local hideSeeds
  9. local showSeeds
  10. local function getArgs(frame)
  11. local parent = frame:getParent();
  12. local args = parent.args;
  13. for k,v in pairs(frame.args) do
  14. args[k] = v
  15. end
  16. return args;
  17. end
  18. function getSeeds()
  19. local seeds = {1, 2}
  20. local count = 2
  21. local before = false
  22. for r = 2, rounds do
  23. local max = math.pow(2, r)
  24. for i = 1, count do
  25. local pos = i * 2
  26. if before then pos = pos - 1 end
  27. table.insert(seeds, pos, max - seeds[i * 2 - 1] + 1)
  28. before = not before
  29. end
  30. count = count * 2
  31. end
  32. return seeds
  33. end
  34. function addTableRow(tbl)
  35. return tbl:tag('tr')
  36. end
  37. function addBlank(row, width)
  38. local cell = row:tag('td')
  39. if width then
  40. cell:css('width', width)
  41. end
  42. return cell
  43. end
  44. function addPath(rows, index, round, top, left)
  45. local prop = top and 'border-bottom-width' or 'border-top-width'
  46. if left and round == 1 then
  47. addBlank(rows[index]):css('height', '7px')
  48. addBlank(rows[index + 1]):css('height', '7px')
  49. return nil
  50. else
  51. local cell = addBlank(rows[index])
  52. :attr('rowspan', '2')
  53. :css('border-width', '0')
  54. :css('border-style', 'solid')
  55. :css('border-color', 'black')
  56. if left or round < rounds and not left then
  57. cell:css(prop, '2px')
  58. end
  59. return cell
  60. end
  61. end
  62. function addCompactPath(rows, index, round, top, left)
  63. local prop = top and 'border-bottom-width' or 'border-top-width'
  64. if left and round == 1 then
  65. addBlank(rows[index])
  66. return nil
  67. else
  68. local cell = addBlank(rows[index])
  69. :css('border-width', '0')
  70. :css('border-style', 'solid')
  71. :css('border-color', 'black')
  72. if left or round < rounds and not left then
  73. cell:css(prop, '2px')
  74. end
  75. return cell
  76. end
  77. end
  78. function getWidth(param, default)
  79. local arg = args[param .. '-width']
  80. if not arg or string.len(arg) == 0 then
  81. arg = default
  82. end
  83. if tonumber(arg) ~= nil then
  84. arg = arg .. 'px'
  85. end
  86. return arg
  87. end
  88. function getTeamArg(round, type, team)
  89. return args[getTeamArgName(round, type, team)]
  90. end
  91. function getTeamArgName(round, type, team)
  92. return string.format('RD%d-%s' .. padding, round, type, team)
  93. end
  94. function getRoundName(round)
  95. local name = args['RD' .. round]
  96. if name and string.len(name) > 0 then
  97. return name
  98. end
  99. local roundFromLast = rounds - round + 1
  100. if roundFromLast == 1 then
  101. return "决赛"
  102. elseif roundFromLast == 2 then
  103. return "半决赛"
  104. elseif roundFromLast == 3 then
  105. return "四分之一决赛"
  106. else
  107. return math.pow(2, roundFromLast).."强赛"
  108. end
  109. end
  110. function renderTeam(row, round, team, top, compact)
  111. local seedCell
  112. local seedArg = getTeamArg(round, 'seed', team)
  113. -- seed value for the paired team
  114. local pairSeedArg = getTeamArg(round, 'seed',
  115. team % 2 == 0 and team - 1 or team + 1)
  116. -- show seed if seed is defined for either or both
  117. local showSeed = showSeeds
  118. or (seedArg and string.len(seedArg) > 0)
  119. or (pairSeedArg and string.len(pairSeedArg) > 0)
  120. if showSeed and (not hideSeeds) then
  121. seedCell = row:tag('td')
  122. :css('text-align', 'center')
  123. :css('background-color', '#f2f2f2')
  124. :css('border-color', '#aaa')
  125. :css('border-style', 'solid')
  126. :css('border-top-width', '1px')
  127. :css('border-left-width', '1px')
  128. :css('border-right-width', '1px')
  129. :css('border-bottom-width', '0')
  130. :wikitext(seedArg)
  131. :newline()
  132. end
  133. local teamArg = getTeamArg(round, 'team', team)
  134. if not teamArg or string.len(teamArg) == 0 then
  135. teamArg = '&nbsp;'
  136. end
  137. local teamCell = row:tag('td')
  138. :css('background-color', '#f9f9f9')
  139. :css('border-color', '#aaa')
  140. :css('border-style', 'solid')
  141. :css('border-top-width', '1px')
  142. :css('border-left-width', '1px')
  143. :css('border-right-width', '0')
  144. :css('border-bottom-width', '0')
  145. :css('padding', '0 2px')
  146. :wikitext(teamArg)
  147. :newline()
  148. if not showSeed and (not hideSeeds) then
  149. teamCell:attr('colspan', '2')
  150. end
  151. local scoreCell = row:tag('td')
  152. :css('text-align', 'center')
  153. :css('border-color', '#aaa')
  154. :css('border-style', 'solid')
  155. :css('border-top-width', '1px')
  156. :css('border-left-width', '1px')
  157. :css('border-right-width', '1px')
  158. :css('border-bottom-width', '0')
  159. :css('background-color', '#f9f9f9')
  160. :wikitext(getTeamArg(round, 'score', team))
  161. :newline()
  162. if not compact then
  163. if seedCell then
  164. seedCell:attr('rowspan', '2')
  165. :css('border-bottom-width', '1px')
  166. end
  167. scoreCell:attr('rowspan', '2')
  168. :css('border-bottom-width', '1px')
  169. teamCell:attr('rowspan', '2')
  170. :css('border-right-width', '1px')
  171. :css('border-bottom-width', '1px')
  172. else
  173. if not top then
  174. if seedCell then
  175. seedCell:css('border-bottom-width', '1px')
  176. end
  177. teamCell:css('border-bottom-width', '1px')
  178. scoreCell:css('border-bottom-width', '1px')
  179. end
  180. end
  181. end
  182. function renderRound(rows, count, r)
  183. local teams = math.pow(2, rounds - r + 1)
  184. local step = count / teams
  185. local topTeam = true -- is top row in match-up
  186. local topPair = true -- is top match-up in pair of match-ups
  187. local team = 1
  188. for i = 1, count, step do
  189. local offset, height, blank
  190. -- leave room for groups for teams other than first and last
  191. if team == 1 or team == teams then
  192. offset = topTeam and i or i + 2
  193. height = step - 2
  194. else
  195. offset = topTeam and i + 1 or i + 2
  196. height = step - 3
  197. end
  198. if height > 0 then
  199. blank = addBlank(rows[offset])
  200. :attr('colspan', hideSeeds and '4' or '5')
  201. :attr('rowspan', height)
  202. :css('border-color', 'black')
  203. :css('border-style', 'solid')
  204. :css('border-width', '0')
  205. end
  206. -- add bracket
  207. local j = topTeam and i + step - 2 or i
  208. -- add left path
  209. addPath(rows, j, r, topTeam, true)
  210. renderTeam(rows[j], r, team, topTeam, false)
  211. local rightPath = addPath(rows, j, r, topTeam, false)
  212. if not topTeam then topPair = not topPair end
  213. if not topPair and r < rounds then
  214. if blank then blank:css('border-right-width', '2px') end
  215. rightPath:css('border-right-width', '2px')
  216. end
  217. team = team + 1
  218. topTeam = not topTeam
  219. end
  220. end
  221. function renderCompactRound(rows, count, r)
  222. local teams = math.pow(2, rounds - r + 1)
  223. local step = count / teams
  224. local topTeam = true -- is top row in match-up
  225. local topPair = true -- is top match-up in pair of match-ups
  226. local team = 1
  227. for i = 1, count, step do
  228. local offset, height, blank
  229. -- empty space above or below
  230. local offset = topTeam and i or i + 1
  231. local height = step - 1
  232. if height > 0 then
  233. blank = addBlank(rows[offset])
  234. :attr('colspan', hideSeeds and '4' or '5')
  235. :css('border-color', 'black')
  236. :css('border-style', 'solid')
  237. :css('border-width', '0')
  238. :attr('rowspan', height)
  239. end
  240. -- add bracket
  241. local j = topTeam and i + step - 1 or i
  242. -- add left path
  243. addCompactPath(rows, j, r, topTeam, true)
  244. renderTeam(rows[j], r, team, topTeam, true)
  245. local rightPath = addCompactPath(rows, j, r, topTeam, false)
  246. if not topTeam then topPair = not topPair end
  247. if not topPair and r < rounds then
  248. if blank then blank:css('border-right-width', '2px') end
  249. rightPath:css('border-right-width', '2px')
  250. end
  251. team = team + 1
  252. topTeam = not topTeam
  253. end
  254. end
  255. function renderGroups(rows, count, round)
  256. local roundFromLast = rounds - round + 1
  257. local groups = math.pow(2, roundFromLast - 2)
  258. local step = count / groups
  259. local group = 1
  260. for i = step / 2, count, step do
  261. local name = 'RD' .. round .. '-group' .. group
  262. addBlank(rows[i]):css('height', '7px')
  263. addBlank(rows[i + 1]):css('height', '7px')
  264. addBlank(rows[i])
  265. :attr('rowspan', '2')
  266. :attr('colspan', (hideSeeds and 4 or 5) * round - 1)
  267. :css('text-align', 'center')
  268. :css('border-color', 'black')
  269. :css('border-style', 'solid')
  270. :css('border-width', '0 2px 0 0')
  271. :wikitext(args[name])
  272. :newline()
  273. group = group + 1
  274. end
  275. end
  276. function renderTree(tbl, compact)
  277. -- create 3 or 1 rows for every team
  278. local count = math.pow(2, rounds) * (compact and 1 or 3)
  279. local rows = {}
  280. for i = 1, count do
  281. rows[i] = addTableRow(tbl)
  282. end
  283. if not compact then
  284. -- fill rows with groups
  285. for r = 1, rounds - 1 do
  286. renderGroups(rows, count, r)
  287. end
  288. end
  289. -- fill rows with bracket
  290. for r = 1, rounds do
  291. if compact then
  292. renderCompactRound(rows, count, r)
  293. else
  294. renderRound(rows, count, r)
  295. end
  296. end
  297. end
  298. function renderHeading(tbl, compact)
  299. local titleRow = addTableRow(tbl)
  300. local widthRow = addTableRow(tbl)
  301. for r = 1, rounds do
  302. addBlank(titleRow)
  303. addBlank(widthRow, r > 1 and '5px' or nil)
  304. titleRow:tag('td')
  305. :attr('colspan', hideSeeds and '2' or '3')
  306. :css('text-align', 'center')
  307. :css('border', '1px solid #aaa')
  308. :css('background-color', '#f2f2f2')
  309. :wikitext(getRoundName(r))
  310. :newline()
  311. local seedCell
  312. if not hideSeeds then
  313. seedCell = addBlank(widthRow, getWidth('seed', '25px'))
  314. end
  315. local teamCell = addBlank(widthRow, getWidth('team', '150px'))
  316. local scoreCell = addBlank(widthRow, getWidth('score', '25px'))
  317. addBlank(titleRow)
  318. addBlank(widthRow, r < rounds and '5px' or nil)
  319. if compact then
  320. teamCell:css('height', '7px')
  321. else
  322. if seedCell then
  323. seedCell:wikitext('&nbsp;')
  324. end
  325. teamCell:wikitext('&nbsp;')
  326. scoreCell:wikitext('&nbsp;')
  327. end
  328. end
  329. end
  330. function p.teamBracket(frame)
  331. args = getArgs(frame)
  332. rounds = tonumber(args.rounds) or 2
  333. local teams = math.pow(2, rounds)
  334. padding = '%0' .. (teams < 10 and 1 or 2) .. 'd'
  335. local compact = (args['compact'] and (args['compact'] == 'yes' or args['compact'] == 'y'))
  336. hideSeeds = (args['seeds'] and (args['seeds'] == 'no' or args['seeds'] == 'n'))
  337. showSeeds = (args['seeds'] and (args['seeds'] == 'yes' or args['seeds'] == 'y'))
  338. -- set default seeds for round 1
  339. local seeds = getSeeds()
  340. local argname
  341. for i = 1, table.getn(seeds) do
  342. argname = getTeamArgName(1, 'seed', i)
  343. if not args[argname] then
  344. args[argname] = seeds[i]
  345. end
  346. end
  347. local tbl = mw.html.create('table')
  348. :css('border-style', 'none')
  349. :css('font-size', '90%')
  350. :css('margin', '1em 2em 1em 1em')
  351. :css('border-collapse', 'separate')
  352. :css('border-spacing', '0')
  353. if (args['nowrap'] and (args['nowrap'] == 'yes' or args['nowrap'] == 'y')) then
  354. tbl:css('white-space', 'nowrap')
  355. end
  356. if compact then
  357. tbl:css('font-size', '90%'):attr('cellpadding', '0')
  358. end
  359. renderHeading(tbl, compact)
  360. renderTree(tbl, compact)
  361. return tostring(tbl)
  362. end
  363. return p