homepage/content/blog/2022/10-28-CLRG-Results-Analysis/feisresults.mjs

139 lines
4.1 KiB
JavaScript
Raw Permalink Normal View History

/**
2022-10-10 19:59:25 -06:00
* Feisresults.com parser
*
*/
import {awardPoints, guessPlacing} from "./awardPoints.mjs"
/**
* @typedef {import("./types.mjs").Results} Results
* @typedef {import("./types.mjs").Result} Result
* @typedef {import("./types.mjs").Round} Round
* @typedef {import("./types.mjs").Adjudication} Adjudication
*/
/**
2022-10-10 19:59:25 -06:00
* Parse feisresults data
*
* @param {Array.<Array.<String>>} rawData Raw data
* @returns {Results}
*/
function parse(rawData) {
/** @type {Results} */
let results = []
let adjudicators = []
let numRounds = 0
let adjudicatorsPerRound = 0
let possibleTiesByAdjudicatorRound = {}
for (let rowIndex = 0; rowIndex < rawData.length; rowIndex++) {
let cells = rawData[rowIndex]
// Is it a page heading?
if ((cells[0].trim().toLowerCase() == "card")) {
continue
}
// Is it a list of adjudicators?
if (cells[cells.length-1].trim().toLowerCase() == "total ip *") {
cells.splice(cells.length-1, 1) // -1: total IP *
cells.splice(0, 5) // 0 - 4: blank
adjudicators = []
for (let cell of cells) {
cell = cell.trim()
if (cell.toLowerCase().includes("rounds 1")) {
// skip it
} else if (cell.toLowerCase().includes("round total")) {
numRounds++
} else {
adjudicators.push(cell)
}
}
adjudicatorsPerRound = adjudicators.length / numRounds
if (! Number.isSafeInteger(adjudicatorsPerRound)) {
console.error(`Irrational number of adjudicators for number of rounds: (${adjudicators.length}/${numRounds})`)
}
continue
}
let row = {}
row.number = Number(cells[0])
// cells[1]: Position at recall
row.overallRank = Number(cells[2])
{
let parts = cells[3].trim().split(/\s:\s/)
console.log(parts, cells[3])
let nameSchool = parts[0]
// parts[1]: region
// We're going to take a wild-ass guess here that the dancer only has two names
let subparts = nameSchool.split(/\s+/)
row.name = subparts.slice(0, 2).join(" ")
row.school = subparts.slice(2).join(" ")
}
row.qualifier = cells[4].trim()
/** @type {Round} */
let round = []
/** @type {Array.<Round>} */
row.rounds = []
let adjudicatorNumber = 0
for (let cellIndex = 5; cellIndex < cells.length; cellIndex++) {
let cell = cells[cellIndex].trim()
if (! cell.includes("/")) {
continue
}
/** @type {Adjudication} */
let adjudication = {}
adjudication.adjudicator = adjudicators[adjudicatorNumber++]
let parts = cell.split("/")
adjudication.raw = Number(parts[0])
adjudication.points = Number(parts[1])
adjudication.placing = guessPlacing(adjudication.points)
// Guidebook reports don't list every dancer: we'll guess placing later
round.push(adjudication)
if (round.length == adjudicatorsPerRound) {
row.rounds.push(round)
round = []
}
}
results.push(row)
}
2022-10-10 19:59:25 -06:00
disambiguatePlacings(results, numRounds, adjudicatorsPerRound)
return results
2022-10-10 19:59:25 -06:00
}
function disambiguatePlacings(results, numRounds, adjudicatorsPerRound) {
for (let roundNumber = 0; roundNumber < numRounds; roundNumber++) {
/**
* A list of raw score, award points, and placing
*
* @type {Array.<Adjudication>}
*/
for (let judgeNumber = 0; judgeNumber < adjudicatorsPerRound; judgeNumber++) {
let scores = []
for (let result of results) {
scores.push(result.rounds[roundNumber][judgeNumber])
}
scores.sort((a,b) => b.raw - a.raw)
let greatestPlacing = 0
for (let adjudication of scores) {
let possibilities = guessPlacing(adjudication.points)
possibilities.sort((a,b) => b-a)
// XXX: eliminate possibilities less than greatestPlacing, then pick the largest
}
console.log(scores)
}
}
}
export {
parse,
}