Module:Jam leaderboards

From VNDev Wiki

Documentation for this module may be created at Module:Jam leaderboards/doc

local p = {}

function p.occurrence( frame )

    local rowsToTest = 23
    local rowsToShow = 20

    if frame.args['rows'] ~= nil then
        rowsToShow = tonumber(frame.args['rows'])
        rowsToTest = rowsToShow + 3
    end

    local statType = 'entries'
    if frame.args['statType'] ~= nil then
        statType = frame.args['statType']
    end

    local countColLabel = 'Count'
    if statType == 'entries' then countColLabel = 'Entries' end
    if statType == 'participants' then countColLabel = 'Participants' end
    if statType == 'top prize' then countColLabel = 'Top Prize' end
    if statType == 'prize pool' then countColLabel = 'Prize Pool' end

    resultsTable = p.processOccurrence ( frame.args['rows'], frame.args['statType'], frame.args['date'], frame.args['vnOnly'] )

    local myResult = '<table class="wikitable sortable"><tr><th class="headerSort">Rank</th> <th class="headerSort">' .. countColLabel .. '</th> <th class="headerSort">Jam</th></tr>'

    for i=1,rowsToTest do
        if resultsTable[i] ~= nil then
            if resultsTable[i].count ~= 0 and tonumber(resultsTable[i].plainCount) ~= 0 then
                myResult = myResult .. '<tr><td>' .. resultsTable[i].rank .. '</td><td>' .. resultsTable[i].count .. '</td><td>' .. resultsTable[i].jam .. '</td></tr>'
            end
        end
    end

    myResult = myResult .. '</table>'
    return myResult
end


function p.processOccurrence( argRows, argStatType, argDate, argVNOnly )
    local rowsToTest = 23
    local rowsToShow = 20

    if argRows ~= nil then
        rowsToShow = tonumber(argRows)
        rowsToTest = rowsToShow + 3
    end

    local statType = 'entries'
    if argStatType ~= nil then
        statType = argStatType
    end

    local date = 'Jan 1 2100'
    if argDate ~= nil then
        date = argDate
    end
    local vnOnly = false
    if argVNOnly == 'VN-specific jams' then
        vnOnly = true
    end

    local query = { '[[Jam occurrence:+]]', '[[Has start date::<' .. date .. ']]', '?#-=jam', '?Has ' .. statType .. '=count', '?Has end date#-F[U]=endDate', '?Modification date#-F[U]=modDate', '?Has ' .. statType .. '#-n=plainCount', '?Is occurrence of#-=occurrenceOf' }
    if vnOnly == true then table.insert(query, '[[Is visual novels only::true]]') end
    query.limit = rowsToTest
    query.sort = 'Has ' .. statType
    query.order = 'descending'
    local queryResult = mw.smw.ask( query )
    if type( queryResult ) == "table" then
        local resultsTable = {}

        for i=1,rowsToTest do
          if queryResult[i] ~= nil then
            local row = queryResult[i]
            local isTie = false
            local rank = i

            if i > 1 and queryResult[i-1] ~= nil then
                local prevRow = queryResult[i-1]
                if prevRow.count == row.count then
                    isTie = true
                    rank = i-1
                end
            end
            if i > 2 and queryResult[i-2] ~= nil then
                local prevPrevRow = queryResult[i-2]
                if prevPrevRow.count == row.count then
                    isTie = true
                    rank = i-2
                end
            end

            if i < rowsToTest and queryResult[i+1] ~= nil then
                local nextRow = queryResult[i+1]
                if nextRow.count == row.count then isTie = true end
            end
            if i < rowsToTest-1 and queryResult[i+2] ~= nil then
                local nextNextRow = queryResult[i+2]
                if nextNextRow.count == row.count then isTie = true end
            end
            local rankToPrint = p.numToOrdinal(rank)
            if isTie then rankToPrint = rankToPrint .. ' (tie)' end

            local countToPrint = row.count
            if statType == 'entries' or statType == 'participants' then
                if tonumber(row.endDate) > tonumber(row.modDate) then countToPrint = row.count .. ' (partial)' end
            end

            if rank <= rowsToShow then
                local toAdd = {}
                toAdd.rank = rankToPrint
                toAdd.count = countToPrint
                toAdd.jam = mw.title.new( row.jam ).text
                toAdd.plainCount = row.plainCount
                toAdd.occurrenceOf = row.occurrenceOf
                table.insert(resultsTable, toAdd )
            end
          end
        end

        return resultsTable
    end

    return queryResult
end


function p.series( frame )

    local resultsTable = p.processSeries( frame.args['statType'], frame.args['date'], frame.args['vnOnly'] )

    local myResult = '<table class="wikitable sortable"><tr><th class="headerSort">Rank</th> <th class="headerSort">Count</th> <th class="headerSort">Jam</th> <th class="headerSort">Includes</th></tr>'

    for i=1,13 do
        if resultsTable[i] ~= nil then
            if resultsTable[i].count ~= 0 then
                myResult = myResult .. '<tr><td>' .. resultsTable[i].rank .. '</td><td>' .. resultsTable[i].count .. '</td><td>' .. resultsTable[i].jam .. '</td><td>' .. resultsTable[i].includes .. ' ' .. resultsTable[i].info .. '</td></tr>'
            end
        end
    end

    myResult = myResult .. '</table>'
    return myResult

end

function p.processSeries( argStatType, argDate, argVNOnly )
    local rowsToTest = 13
    local rowsToShow = 10

    local statType = 'entries'
    if argStatType ~= nil then
        statType = argStatType
    end
    local date = 'Jan 1 2100'
    if argDate ~= nil then
        date = argDate
    end
    local vnOnly = false
    if argVNOnly == 'VN-specific jams' then
        vnOnly = true
    end

    local seriesQuery = {'[[Category:Jam series]]', '?#-=name', '?Has short name=shortName'}
    seriesQuery.limit = 500
    local seriesList = mw.smw.ask( seriesQuery )
    local counts = {}

    for i,series in pairs(seriesList) do
        local subq = { '[[Jam occurrence:+]]', '[[Has start date::<' .. date .. ']]', '[[Is occurrence of::' .. series.name .. ']]', '?#-=jam', '?Has ' .. statType .. '=count', '?Has end date#-F[Y]=endYear', '?Has end date#-F[U]=endDate', '?Modification date#-F[U]=modDate' }
        if vnOnly == true then table.insert(subq, '[[Is visual novels only::true]]') end
        subq.limit = 50
        local queryResult = mw.smw.ask( subq )
        local seriesCount = 0
        local latestEnd = 0
        local latestName = ''
        local partial = ''
        if queryResult ~= nil then
            for num, row in pairs( queryResult ) do
                if type(row.count) == "number" then seriesCount = seriesCount + row.count end
                if tonumber(row.endYear) > latestEnd then 
                    if tonumber(row.endDate) > tonumber(row.modDate) and type(row.count) == "number" then 
                        if row.count > 0 then 
                            latestEnd = tonumber(row.endYear)
                            latestName = mw.title.new( row.jam ).text
                            partial = ' (partial)'
                        end
                    else 
                        latestEnd = tonumber(row.endYear)
                        latestName = mw.title.new( row.jam ).text
                    end
                end
            end
            table.insert(counts, { seriesCount, series.shortName, latestEnd, partial, latestName, series.name } )
        end
    end

    table.sort(counts, function (left, right)
        return left[1] > right[1]
    end)

    if type( counts ) == "table" then

        local resultsTable = {}

        for i=1,rowsToTest do
          if counts[i] ~= nil then
            local row = counts[i]
            local isTie = false
            local rank = i

            if i > 1 and counts[i-1] ~= nil then
                local prevRow = counts[i-1]
                if prevRow[1] == row[1] then
                    isTie = true
                    rank = i-1
                end
            end
            if i > 2 and counts[i-2] ~= nil then
                local prevPrevRow = counts[i-2]
                if prevPrevRow[1] == row[1] then
                    isTie = true
                    rank = i-2
                end
            end

            if i < rowsToTest and counts[i+1] ~= nil then
                local nextRow = counts[i+1]
                if nextRow[1] == row[1] then isTie = true end
            end
            if i < rowsToTest-1 and counts[i+2] ~= nil then
                local nextNextRow = counts[i+2]
                if nextNextRow[1] == row[1] then isTie = true end
            end
            local rankToPrint = p.numToOrdinal(rank)
            if isTie then rankToPrint = rankToPrint .. ' (tie)' end

            if rank <= rowsToShow then
                local toAdd = {}
                toAdd.rank = rankToPrint
                toAdd.count = row[1]
                toAdd.jam = mw.title.new( row[2] ).text
                toAdd.includes = row[3] .. row[4]
                toAdd.info = mw.smw.info(row[5], 'info')
                toAdd.longName = row[6]
                table.insert( resultsTable, toAdd )
            end
          end
        end
        return resultsTable
    end

    return counts
end


function p.year( frame )
    local statType = 'entries'
    if frame.args['statType'] ~= nil then
        statType = frame.args['statType']
    end
    local vnOnly = false
    if frame.args['vnOnly'] == 'VN-specific jams' then
        vnOnly = true
    end

    local dateNow = os.date("*t", mw.getContentLanguage():formatDate( "U", frame.args['date'] ) )
    local maxYear = dateNow.year
    if dateNow.month == 1 then maxYear = dateNow.year - 1 end

    local myResult = '<table class="wikitable sortable"><tr><th class="headerSort">Year</th> <th class="headerSort">1st</th> <th class="headerSort">2nd</th> <th class="headerSort">3rd</th></tr>'
    for i=maxYear,2015,-1 do
        local query = { '[[Jam occurrence:+]]', '[[Has start date::>Jan 1 ' .. i .. ']]', '[[Has start date::<Dec 31 ' .. i .. ']]', '?Is occurrence of.Has short name=name', '?Has ' .. statType .. '=count', '?Has end date#-F[U]=endDate', '?Modification date#-F[U]=modDate' }
        if vnOnly == true then table.insert(query, '[[Is visual novels only::true]]') end
        query.limit = 3
        query.sort = 'Has ' .. statType
        query.order = 'descending'
        local queryResult = mw.smw.ask( query )

        local yearToPrint = i
        if i == dateNow.year then yearToPrint = i .. ' (partial)' end

        myResult = myResult .. '<tr><td>' .. yearToPrint .. '</td>'

        for j=1,3 do
            local part = ''
            if tonumber(queryResult[j].endDate) > tonumber(queryResult[j].modDate) then part = ', partial' end
            myResult = myResult .. '<td>' .. queryResult[j].name .. ' (' .. queryResult[j].count .. part .. ')</td>'
        end

        myResult = myResult .. '</tr>'

    end
    myResult = myResult .. '</table>'
    return myResult

end

function p.seriesStats( frame )

    local name = frame.args['name']

    local results = {}
    results[1] = p.processOccurrence( nil, 'entries', nil, '' )
    results[2] = p.processOccurrence( nil, 'participants', nil, '' )
    results[3] = p.processSeries( 'entries', nil, '')
    results[4] = p.processSeries( 'participants', nil, '')
    results[5] = p.processOccurrence( nil, 'top prize', nil, '')
    results[6] = p.processOccurrence( nil, 'prize pool', nil, '')

    local annotations = { 'most entries', 'most participants', 'most cumulative entries', 'most cumulative participants', 'largest top prize', 'largest prize pool' }
    local ranks = { '', '', '', '', '', '' }

    local toRet = ''

    for j=1,6 do
        for i=1,23 do
            if results[j][i] ~= nil then
                if ranks[j] == '' then
                    if results[j][i].occurrenceOf == name or results[j][i].longName == name then
                        ranks[j] = results[j][i].rank
                    end
                end
            end
        end
        if ranks[j] ~= '' then 
            if toRet ~= '' then toRet = toRet .. ', ' end
            toRet = toRet .. ranks[j] .. ' ' .. annotations[j]
        end
    end

    if toRet == '' then return 'None recorded' end
    return toRet

end

function p.numToOrdinal( num )
    if num == 1 then return '1st' end
    if num == 2 then return '2nd' end
    if num == 3 then return '3rd' end
    return num .. 'th'
end


return p