ecclesia
Version:
Framework for political and electoral simulations
1 lines • 3.45 kB
Source Map (JSON)
{"version":3,"sources":["../../src/election/ballots.ts"],"sourcesContent":["import { ReadonlyCounter } from \"@gouvernathor/python/collections\";\n\n/**\n * A counter, mapping each party to its number of ballots.\n *\n * [[PS, 5], [LR: 7]] -> 5 ballots for PS, 7 for LR.\n */\nexport interface Simple<Party> extends ReadonlyCounter<Party> { }\n\n/**\n * A list of ballots, each ballot ordering parties by decreasing preference.\n *\n * [[LR, PS, LFI], [LFI, PS,], ] -> one voter prefers LR then PS then LFI,\n * another prefers LFI then PS and didn't rank LR.\n *\n * Math.max(result.map(ballot => ballot.length)) <= number of candidates-1\n * == if the voting method requires a full ranking\n *\n * There can be no tie between candidates within a ballot.\n * Note that not ranking all the candidates is permitted by this type,\n * although some attribution methods may not support it.\n */\nexport interface Order<Party> extends ReadonlyArray<ReadonlyArray<Party>> { }\n\n/**\n * A mapping from each party to a list of number of ballots, one for each grade.\n *\n * [[PS, [0, 2, 5, 9, 1]], ] -> PS received the worst grade 0 times, the best grade 1 time and so on.\n *\n * result.get(p).length is constant, equal to the number of grades of the voting method.\n *\n * If the voter must grade all the candidates, then sum(result.get(p)) is constant\n * and equal to the number of voters.\n *\n * Any party not mapped will be assumed to have\n * an array of zeros (of length ngrades).\n */\nexport interface Scores<Party> extends ReadonlyMap<Party, ReadonlyArray<number>> {\n readonly ngrades: number;\n get(key: Party): ReadonlyArray<number>;\n}\n\nexport namespace Scores {\n function get<Party>(this: Scores<Party>, key: Party): ReadonlyArray<number> {\n const value = this.get(key);\n if (value === undefined) {\n return Array(this.ngrades).fill(0);\n }\n return value!;\n }\n\n export function fromEntries<Party>(\n elements: readonly [Party, readonly number[]][],\n ): Scores<Party> {\n if (elements.length === 0) {\n throw new Error(\"Use the fromGrades method to create an empty Scores instance\");\n }\n const ths = new Map(elements) as Partial<Scores<Party>> & { ngrades?: number };\n ths.ngrades = elements[0][1].length;\n ths.get = get.bind(ths as any);\n return ths as Scores<Party>;\n }\n\n export function fromGrades<Party>(ngrades: number): Scores<Party> {\n const ths = new Map() as Partial<Scores<Party>> & { ngrades?: number };\n ths.ngrades = ngrades;\n ths.get = get.bind(ths as any);\n return ths as Scores<Party>;\n }\n}\n\n\nexport type Ballots<Party> = Simple<Party> | Order<Party> | Scores<Party>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0CO,IAAU;AAAA,CAAV,CAAUA,YAAV;AACH,WAAS,IAAgC,KAAmC;AACxE,UAAM,QAAQ,KAAK,IAAI,GAAG;AAC1B,QAAI,UAAU,QAAW;AACrB,aAAO,MAAM,KAAK,OAAO,EAAE,KAAK,CAAC;AAAA,IACrC;AACA,WAAO;AAAA,EACX;AAEO,WAAS,YACZ,UACa;AACb,QAAI,SAAS,WAAW,GAAG;AACvB,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAClF;AACA,UAAM,MAAM,IAAI,IAAI,QAAQ;AAC5B,QAAI,UAAU,SAAS,CAAC,EAAE,CAAC,EAAE;AAC7B,QAAI,MAAM,IAAI,KAAK,GAAU;AAC7B,WAAO;AAAA,EACX;AAVO,EAAAA,QAAS;AAYT,WAAS,WAAkB,SAAgC;AAC9D,UAAM,MAAM,oBAAI,IAAI;AACpB,QAAI,UAAU;AACd,QAAI,MAAM,IAAI,KAAK,GAAU;AAC7B,WAAO;AAAA,EACX;AALO,EAAAA,QAAS;AAAA,GArBH;","names":["Scores"]}