Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions lua/spec/standings_legacy_swiss_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
--- Triple Comment to Enable our LLS Plugin
describe('Standings Legacy Swiss', function()
local StandingTableLegacySwiss = require('Module:Standings/Table/Legacy/Swiss')

describe('team input', function()
it('maps r<round>bg<team> to r<round>bg on the opponent', function()
local args = {
rounds = '5',
team1 = 'alpha',
team2 = 'bravo',
r3bg1 = 'up',
r5bg1 = 'stayup',
r4bg2 = 'down',
}

local alpha = StandingTableLegacySwiss.parseTeamInput(args, 1)
assert.are_equal('alpha', alpha[1])
assert.are_equal('up', alpha.r3bg)
assert.are_equal('stayup', alpha.r5bg)
assert.is_nil(alpha.r4bg)

local bravo = StandingTableLegacySwiss.parseTeamInput(args, 2)
assert.are_equal('down', bravo.r4bg)
assert.is_nil(bravo.r3bg)
end)

it('ignores rounds beyond the number of rounds', function()
local opponent = StandingTableLegacySwiss.parseTeamInput({rounds = '3', team1 = 'alpha', r4bg1 = 'up'}, 1)
assert.is_nil(opponent.r4bg)
end)
end)

describe('solo input', function()
it('maps r<round>bg<player> to r<round>bg on the opponent', function()
local args = {rounds = '5', player1 = 'Alpha', p2 = 'Bravo', r3bg1 = 'up', r4bg2 = 'down'}

local alpha = StandingTableLegacySwiss.parseSoloInput(args, 1)
assert.are_equal('Alpha', alpha[1])
assert.are_equal('up', alpha.r3bg)
assert.is_nil(alpha.r4bg)

local bravo = StandingTableLegacySwiss.parseSoloInput(args, 2)
assert.are_equal('down', bravo.r4bg)
assert.is_nil(bravo.r3bg)
end)
end)
end)
33 changes: 33 additions & 0 deletions lua/spec/standings_parse_wiki_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,39 @@ describe('Standings Wiki Parser', function()
end)
end)

describe('definite statuses', function()
it('reads r<round>bg inputs keyed by the round they apply from', function()
assert.are_same({[3] = 'up'}, StandingsParseWiki.parseDefiniteStatuses({r3bg = 'up'}, 5))
assert.are_same(
{[3] = 'stayup', [5] = 'up'},
StandingsParseWiki.parseDefiniteStatuses({r3bg = 'stayup', r5bg = 'up', r1 = '3'}, 5)
)
end)

it('ignores empty values and rounds beyond the number of rounds', function()
assert.are_same({[2] = 'down'}, StandingsParseWiki.parseDefiniteStatuses({r1bg = '', r2bg = 'down'}, 3))
assert.are_same({[1] = 'up'}, StandingsParseWiki.parseDefiniteStatuses({r1bg = 'up', r4bg = 'down'}, 3))
end)

it('returns nil when there are none', function()
assert.is_nil(StandingsParseWiki.parseDefiniteStatuses({}, 3))
assert.is_nil(StandingsParseWiki.parseDefiniteStatuses({r1bg = '', bg = 'up'}, 3))
assert.is_nil(StandingsParseWiki.parseDefiniteStatuses({r4bg = 'up'}, 3))
end)

it('stores the definite statuses on the parsed opponent without affecting round input', function()
local withStatuses = StandingsParseWiki.parseWikiOpponent(
{type = 'literal', 'Alpha', r1 = '3', r2 = '1', r3bg = 'up', r4bg = 'stay'}, 3)
local without = StandingsParseWiki.parseWikiOpponent({type = 'literal', 'Bravo', r1 = '3'}, 3)

assert.are_same({[3] = 'up'}, withStatuses.definiteStatuses)
assert.are_equal(3, withStatuses.rounds[1].scoreboard.points)
assert.are_equal(1, withStatuses.rounds[2].scoreboard.points)
assert.is_nil(withStatuses.rounds[3].scoreboard.points)
assert.is_nil(without.definiteStatuses)
end)
end)

describe('tiebreakers', function()
it('always puts the disqualified tiebreaker first and manual last', function()
assert.are_same(
Expand Down
102 changes: 102 additions & 0 deletions lua/spec/standings_parser_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,108 @@ describe('Standings Parser', function()
end)
end)

describe('manual definite statuses', function()
local THREE_ROUNDS_TWO_FINISHED = {
{roundNumber = 1, started = true, finished = true},
{roundNumber = 2, started = true, finished = true},
{roundNumber = 3, started = true, finished = false},
}

---@param definiteStatuses table<integer, string>?
---@return table[]
local function makeOpponents(definiteStatuses)
local alpha = makeOpponent('Alpha', {{points = 0}, {points = 0}, {points = 0}})
alpha.definiteStatuses = definiteStatuses
return {
alpha,
makeOpponent('Bravo', {{points = 3}, {points = 3}, {points = 3}}),
makeOpponent('Charlie', {{points = 1}, {points = 1}, {points = 1}}),
}
end

it('applies only from the given round onwards on unfinished standings', function()
local standingsTable = StandingsParser.parse(
THREE_ROUNDS_TWO_FINISHED, makeOpponents({[2] = 'down'}), BGS, nil, {}, 'ffa', TIEBREAKERS)

local alpha1 = findEntry(standingsTable.entries, 'Alpha', 1)
assert.are_equal('down', alpha1.currentstatus)
assert.is_nil(alpha1.definitestatus)

Array.forEach({2, 3}, function(roundIndex)
local alpha = findEntry(standingsTable.entries, 'Alpha', roundIndex)
assert.are_equal('down', alpha.definitestatus)
end)
end)

it('does not apply to rounds before the first given round', function()
local standingsTable = StandingsParser.parse(
THREE_ROUNDS_TWO_FINISHED, makeOpponents({[3] = 'up'}), BGS, nil, {}, 'ffa', TIEBREAKERS)

Array.forEach({1, 2}, function(roundIndex)
local alpha = findEntry(standingsTable.entries, 'Alpha', roundIndex)
assert.is_nil(alpha.definitestatus)
assert.are_equal('down', alpha.currentstatus)
end)
assert.are_equal('up', findEntry(standingsTable.entries, 'Alpha', 3).definitestatus)
end)

it('uses the status with the highest round that has been reached', function()
local standingsTable = StandingsParser.parse(
THREE_ROUNDS_TWO_FINISHED, makeOpponents({[1] = 'stayup', [3] = 'up'}),
BGS, nil, {}, 'ffa', TIEBREAKERS)

assert.are_equal('stayup', findEntry(standingsTable.entries, 'Alpha', 1).definitestatus)
assert.are_equal('stayup', findEntry(standingsTable.entries, 'Alpha', 2).definitestatus)
assert.are_equal('up', findEntry(standingsTable.entries, 'Alpha', 3).definitestatus)
end)

it('sets the current status as well', function()
local standingsTable = StandingsParser.parse(
THREE_ROUNDS_TWO_FINISHED, makeOpponents({[2] = 'up'}), BGS, nil, {}, 'ffa', TIEBREAKERS)

local alpha2 = findEntry(standingsTable.entries, 'Alpha', 2)
assert.are_equal(3, alpha2.placement)
assert.are_equal('up', alpha2.currentstatus)
assert.are_equal('up', alpha2.definitestatus)
end)

it('overrides the definite status derived from the bgs on finished standings', function()
local standingsTable = StandingsParser.parse(
TWO_FINISHED_ROUNDS, makeOpponents({[1] = 'stay'}), BGS, nil, {}, 'ffa', TIEBREAKERS)

local alpha2 = findEntry(standingsTable.entries, 'Alpha', 2)
assert.are_equal('stay', alpha2.currentstatus)
assert.are_equal('stay', alpha2.definitestatus)
end)

it('is overridden by a disqualification', function()
local opponents = makeOpponents({[1] = 'up'})
opponents[1].disqualifiedFromRound = 2

local standingsTable = StandingsParser.parse(
TWO_FINISHED_ROUNDS, opponents, BGS, nil, {}, 'ffa', {'full.disqualified', 'full.points', 'full.manual'})

local alpha1 = findEntry(standingsTable.entries, 'Alpha', 1)
assert.are_equal('up', alpha1.currentstatus)
assert.are_equal('up', alpha1.definitestatus)
local alpha2 = findEntry(standingsTable.entries, 'Alpha', 2)
assert.are_equal('dq', alpha2.currentstatus)
assert.are_equal('dq', alpha2.definitestatus)
end)

it('leaves opponents without manual statuses unchanged', function()
local standingsTable = StandingsParser.parse(
THREE_ROUNDS_TWO_FINISHED, makeOpponents({[1] = 'up'}), BGS, nil, {}, 'ffa', TIEBREAKERS)

local bravo2 = findEntry(standingsTable.entries, 'Bravo', 2)
assert.are_equal('up', bravo2.currentstatus)
assert.is_nil(bravo2.definitestatus)
local charlie2 = findEntry(standingsTable.entries, 'Charlie', 2)
assert.are_equal('stay', charlie2.currentstatus)
assert.is_nil(charlie2.definitestatus)
end)
end)

it('increments the standingsindex wiki variable per table', function()
local opponents = {makeOpponent('Alpha', {{points = 3}, {points = 0}})}

Expand Down
14 changes: 14 additions & 0 deletions lua/wikis/commons/Standings/Parse/Wiki.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
-- @Liquipedia
-- page=Module:Standings/Parse/Wiki
Expand Down Expand Up @@ -160,6 +160,7 @@
aliases = aliases,
startingPoints = opponentData.startingpoints,
disqualifiedFromRound = StandingsParseWiki.parseDisqualifiedFromRound(opponentData.dq),
definiteStatuses = StandingsParseWiki.parseDefiniteStatuses(opponentData, numberOfRounds),
}
end

Expand All @@ -175,6 +176,19 @@
return Logic.readBool(input) and 1 or nil
end

---Reads the `r<round>bg` inputs of an opponent, e.g. `r3bg=up`. The status applies from that round onwards.
---Rounds beyond the number of rounds and empty values are ignored.
---@param opponentData table
---@param numberOfRounds integer
---@return table<integer, string>?
function StandingsParseWiki.parseDefiniteStatuses(opponentData, numberOfRounds)
local statuses = {}
for round = 1, numberOfRounds do
statuses[round] = Logic.nilIfEmpty(opponentData['r' .. round .. 'bg'])
end
return Logic.nilIfEmpty(statuses)
end

---@param input string
---@return table<integer, string>
function StandingsParseWiki.parseWikiBgs(input)
Expand Down
33 changes: 33 additions & 0 deletions lua/wikis/commons/Standings/Parser.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
-- @Liquipedia
-- page=Module:Standings/Parser
Expand Down Expand Up @@ -70,6 +70,9 @@
match = Table.copy(carryData.match),
matches = playedMatches or {},
startingPoints = opponentData.startingPoints,
manualDefiniteStatus = StandingsParser.resolveManualDefiniteStatus(
opponentData.definiteStatuses, round.roundNumber
),
extradata = {
pointschange = pointsFromRound,
specialstatus = statusInRound,
Expand Down Expand Up @@ -141,6 +144,7 @@
return opponentRound.roundindex == #rounds
end), bgs, 'definitestatus')
end
StandingsParser.applyManualStatuses(entries)
StandingsParser.applyDisqualifications(entries)
---@cast entries {opponent: standardOpponent, standingindex: integer, roundindex: integer, points: number,
---placement: integer?, slotindex: integer, placementchange: integer?,
Expand Down Expand Up @@ -252,6 +256,35 @@
end)
end

---Finds the manually set definite status that is in effect in a round,
---which is the one with the highest round number that is not after the given round.
---@param definiteStatuses table<integer, string>?
---@param roundNumber integer
---@return string?
function StandingsParser.resolveManualDefiniteStatus(definiteStatuses, roundNumber)
if not definiteStatuses then
return
end
for round = roundNumber, 1, -1 do
if definiteStatuses[round] then
return definiteStatuses[round]
end
end
end

---Overrides the statuses of opponents with a manually set definite status.
---A definite status is also the current status, so both are set.
---@param opponentEntries {manualDefiniteStatus: string?, currentstatus: string?, definitestatus: string?}[]
function StandingsParser.applyManualStatuses(opponentEntries)
Array.forEach(opponentEntries, function(opponent)
local manualStatus = opponent.manualDefiniteStatus
if manualStatus then
opponent.currentstatus = manualStatus
opponent.definitestatus = manualStatus
end
end)
end

---Overrides the statuses of disqualified opponents with 'dq'. A disqualification is final,
---so the definite status is set regardless of the standings being finished or not.
---@param opponentEntries {extradata: table, currentstatus: string?, definitestatus: string?}[]
Expand Down
1 change: 1 addition & 0 deletions lua/wikis/commons/Standings/Table.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
-- @Liquipedia
-- page=Module:Standings/Table
Expand Down Expand Up @@ -37,6 +37,7 @@
---@field aliases standardOpponent[]? # Only for team opponents
---@field startingPoints number?
---@field disqualifiedFromRound integer? # The first round in which the opponent is disqualified
---@field definiteStatuses table<integer, string>? # Manually set definite statuses, keyed by the round they apply from

---@param frame Frame
---@return Renderable
Expand Down
22 changes: 16 additions & 6 deletions lua/wikis/commons/Standings/Table/Legacy/Swiss.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
-- @Liquipedia
-- page=Module:Standings/Table/Legacy/Swiss
Expand Down Expand Up @@ -100,9 +100,19 @@
return tiebreaker, startingPoints, dq
end

---Legacy `r<round>bg<index>` maps to `r<round>bg` on the opponent
---@param args table
---@param index integer
---@return table<string, string>
local function parseDefiniteStatuses(args, index)
return Table.map(Array.range(1, tonumber(args.rounds) or 1), function(roundIndex)
return 'r' .. roundIndex .. 'bg', args['r' .. roundIndex .. 'bg' .. index]
end)
end

---@param args table
---@param teamIndex integer
---@return {type: OpponentType, [1]: string, tiebreaker: string?, startingpoints: string?, dq: string?}?
---@return {type: OpponentType, [1]: string, tiebreaker: string?, startingpoints: string?, dq: string?, r1bg: string?}?
function StandingTableLegacySwiss.parseTeamInput(args, teamIndex)
local team = args['team' .. teamIndex]
if not team then
Expand All @@ -111,18 +121,18 @@

local tiebreaker, startingPoints, dq = parseCoreInput(args, teamIndex)

return {
return Table.merge({
type = Opponent.team,
team,
tiebreaker = tiebreaker,
startingpoints = startingPoints,
dq = dq,
}
}, parseDefiniteStatuses(args, teamIndex))
end

---@param args table
---@param playerIndex integer
---@return {type: OpponentType, [1]: string, tiebreaker: string?, startingpoints: string?, dq: string?}?
---@return {type: OpponentType, [1]: string, tiebreaker: string?, startingpoints: string?, dq: string?, r1bg: string?}?
function StandingTableLegacySwiss.parseSoloInput(args, playerIndex)
local player = args['player' .. playerIndex] or args['p' .. playerIndex]
if not player then
Expand All @@ -131,15 +141,15 @@

local tiebreaker, startingPoints, dq = parseCoreInput(args, playerIndex)

return {
return Table.merge({
type = Opponent.solo,
player,
flag = args['player' .. playerIndex .. 'flag'] or args['p' .. playerIndex .. 'flag'],
link = args['player' .. playerIndex .. 'link'] or args['p' .. playerIndex .. 'link'],
tiebreaker = tiebreaker,
startingpoints = startingPoints,
dq = dq,
}
}, parseDefiniteStatuses(args, playerIndex))
end

---@param args table
Expand Down
Loading