Source: compute/voteCasters/ranking/castRankingGrid.js

/** @module */

import * as types from '@paretoman/votekit-types'
import castRankingPoint from './castRankingPoint.js'
import makeGrid1D from '../voteCasters/makeGrid1D.js'
import makeGrid2D from '../voteCasters/makeGrid2D.js'

/**
 * Cast and tally votes on a grid of points.
 * @param {types.typesGeoms.voterGeom} voterGeom
 * @param {types.typesGeometry.geometry} geometry
 * @param {types.typesCast.castOptions} castOptions
 * @returns {types.typesVotesForGeomGrid.votesForGeomGridRanking} votesForGeom
 */
export default function castRankingGrid(voterGeom, geometry, castOptions) {
    const { canPoints, dimensions } = geometry
    const { verbosity } = castOptions

    // just find the vote and voteCount at each grid point
    const makeGrid = (dimensions === 1) ? makeGrid1D : makeGrid2D
    // @ts-ignore
    const grid = makeGrid(voterGeom, castOptions)
    const { voteCounts, totalVotes, voterPoints } = grid

    const nk = canPoints.length
    const cansByRankList = new Array(nk)

    let bordaScoreSumByCan
    let rankings
    let voteSet
    if (verbosity >= 2) {
        bordaScoreSumByCan = Array(nk).fill(0)
        rankings = new Array(nk)
        voteSet = Array(voteCounts.length)
    }

    // find vote
    for (let i = 0; i < voteCounts.length; i++) {
        const voteCount = voteCounts[i]
        const voterPoint = voterPoints[i]

        const vote = castRankingPoint(canPoints, voterPoint, dimensions, verbosity)

        cansByRankList[i] = vote.cansByRank

        if (verbosity < 2) continue

        voteSet[i] = vote

        rankings[i] = vote.ranking
        const { bordaScores } = vote
        for (let k = 0; k < nk; k++) {
            bordaScoreSumByCan[k] += bordaScores[k] * voteCount
        }
    }
    if (verbosity < 2) {
        return { voteCounts, totalVotes, cansByRankList }
    }

    // bordaScore is nk-1 if a candidate receives all the votes for the voter geometry.
    // bordaFractionAverageByCan is 1 if a candidate receives all the votes.
    const bordaFractionAverageByCan = bordaScoreSumByCan.map(
        (bt) => (bt / (nk - 1)) / totalVotes,
    )
    return { grid, voteSet, voteCounts, totalVotes, bordaFractionAverageByCan, rankings, cansByRankList }
}