add support for popular vote elections and add nk 2019
This commit is contained in:
parent
f073c48cc7
commit
e8183499c6
17 changed files with 235 additions and 6 deletions
66
assets/NorthKorea2019.svg
Normal file
66
assets/NorthKorea2019.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 175 KiB |
15
src/VoteType.ts
Normal file
15
src/VoteType.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
enum VoteType {
|
||||
Electoral,
|
||||
Popular,
|
||||
}
|
||||
|
||||
export function VoteTypeString(voteType: VoteType) {
|
||||
switch (voteType) {
|
||||
case VoteType.Electoral:
|
||||
return "Electoral Votes";
|
||||
case VoteType.Popular:
|
||||
return "Votes";
|
||||
}
|
||||
}
|
||||
|
||||
export default VoteType;
|
|
@ -1,7 +1,10 @@
|
|||
import VoteType from './VoteType.js';
|
||||
|
||||
export default interface Election {
|
||||
title : string,
|
||||
shortname : string,
|
||||
description : string,
|
||||
voteType : VoteType,
|
||||
svg: string,
|
||||
candidates : {
|
||||
name : string,
|
||||
|
@ -10,7 +13,8 @@ export default interface Election {
|
|||
}[],
|
||||
states : {
|
||||
[key : string] : {
|
||||
electoralVotes : number,
|
||||
electoralVotes? : number | undefined,
|
||||
population? : number | undefined,
|
||||
odds : {
|
||||
[key : string] : number
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_1789 = {
|
||||
title: "1789 United States Presidential Election Simulator",
|
||||
shortname: "1789",
|
||||
description: "The CalubViem Press has rewritten history and called the 1789 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege1789.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_1848 = {
|
||||
title: "1848 United States Presidential Election Simulator",
|
||||
shortname: "1848",
|
||||
description: "The CalubViem Press has rewritten history and called the 1848 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege1848.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_1864 = {
|
||||
title: "1864 United States Presidential Election Simulator",
|
||||
shortname: "1864",
|
||||
description: "The CalubViem Press has rewritten history and called the 1864 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege1864.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_1968 = {
|
||||
title: "1968 United States Presidential Election Simulator",
|
||||
shortname: "1968",
|
||||
description: "The CalubViem Press has rewritten history and called the 1968 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege1968.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_1968 = {
|
||||
title: "1968 United States Presidential Election Simulator",
|
||||
shortname: "1968",
|
||||
description: "The CalubViem Press has rewritten history and called the 1968 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege1968.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_1992 = {
|
||||
title: "1992 United States Presidential Election Simulator",
|
||||
shortname: "1992",
|
||||
description: "The CalubViem Press has rewritten history and called the 1992 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege1992.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_2000 = {
|
||||
title: "2000 United States Presidential Election Simulator",
|
||||
shortname: "2000",
|
||||
description: "The CalubViem Press has rewritten history and called the 2000 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege1992.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_2004 = {
|
||||
title: "2004 United States Presidential Election Simulator",
|
||||
shortname: "2004",
|
||||
description: "The CalubViem Press has rewritten history and called the 2004 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege2004.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_2008 = {
|
||||
title: "2008 United States Presidential Election Simulator",
|
||||
shortname: "2008",
|
||||
description: "The CalubViem Press has rewritten history and called the 2008 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege2008.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { readFile } from "node:fs/promises";
|
||||
import Election from "../election.js";
|
||||
import VoteType from "../VoteType.js";
|
||||
|
||||
const Presidential_2024 = {
|
||||
title: "2024 United States Presidential Election Simulator",
|
||||
shortname: "2024",
|
||||
description: "The CalubViem Press has called the 2024 United States Presidential Election for $WINNER!",
|
||||
voteType: VoteType.Electoral,
|
||||
svg: await readFile("assets/ElectoralCollege2024.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
|
|
94
src/elections/NK2019.ts
Normal file
94
src/elections/NK2019.ts
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { readFile } from "fs/promises";
|
||||
import VoteType from "../VoteType.js";
|
||||
import Election from "../election.js"
|
||||
|
||||
const NK_2019 = {
|
||||
title: "2019 North Korean Supreme People's Assembly Election",
|
||||
shortname: "nk2019",
|
||||
description: "The Central Election Committee of the Democratic People's Republic of Korea has called the election for $WINNER!",
|
||||
voteType: VoteType.Popular,
|
||||
svg: await readFile("assets/NorthKorea2019.svg", "utf-8"),
|
||||
candidates: [
|
||||
{
|
||||
name: "Kim Jong-Un",
|
||||
party: "Democratic Front FTRF",
|
||||
color: "#FF0000",
|
||||
},
|
||||
],
|
||||
states: {
|
||||
"KP-01": {
|
||||
population: 3157538,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-02": {
|
||||
population: 4051696,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-03": {
|
||||
population: 12191,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-04": {
|
||||
population: 1299830,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-05": {
|
||||
population: 8450,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-06": {
|
||||
population: 8154,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-07": {
|
||||
population: 11255,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-08": {
|
||||
population: 18970,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-09": {
|
||||
population: 2327362,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-10": {
|
||||
population: 719269,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-13": {
|
||||
population: 205000,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
"KP-14": {
|
||||
population: 983660,
|
||||
odds: {
|
||||
"Democratic Front FTRF": 1,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default NK_2019 as Election;
|
|
@ -8,8 +8,10 @@ import Presidential_2000 from "./2000.js";
|
|||
import Presidential_2004 from "./2004.js";
|
||||
import Presidential_2008 from "./2008.js";
|
||||
import Presidential_2024 from "./2024.js";
|
||||
import NK_2019 from "./NK2019.js";
|
||||
|
||||
const Elections = {
|
||||
// US
|
||||
"1789": Presidential_1789,
|
||||
"1848": Presidential_1848,
|
||||
"1864": Presidential_1864,
|
||||
|
@ -18,7 +20,9 @@ const Elections = {
|
|||
"2000": Presidential_2000,
|
||||
"2004": Presidential_2004,
|
||||
"2008": Presidential_2008,
|
||||
"2024": Presidential_2024
|
||||
"2024": Presidential_2024,
|
||||
// Other
|
||||
"nk2019": NK_2019,
|
||||
}
|
||||
|
||||
export default (Elections as {[key : string] : Election})
|
|
@ -5,6 +5,7 @@ import {MakePrediction} from "./predictor.js";
|
|||
import Election from "./election.js";
|
||||
import Presidential_2024 from "./elections/2024.js";
|
||||
import Elections from "./elections/elections.js";
|
||||
import VoteType, { VoteTypeString } from "./VoteType.js";
|
||||
|
||||
const configraw = fs.readFileSync("config.json", "utf-8");
|
||||
const config = JSON.parse(configraw);
|
||||
|
@ -100,7 +101,7 @@ if (!config.token) {
|
|||
.addFields(result.candidates.map(c => {
|
||||
return {
|
||||
name: `${(result.winner === c.name ? ":white_check_mark:" : "")} ${c.name} (${c.party})`,
|
||||
value: `${c.votes} Electoral Votes`,
|
||||
value: `${c.votes} ${VoteTypeString(election.voteType)}${election.voteType === VoteType.Popular ? ` (${((c.votes / result.totalVotes) * 100).toFixed(2)}%)` : ""}`,
|
||||
inline: true
|
||||
}
|
||||
}))
|
||||
|
|
|
@ -3,6 +3,7 @@ import { SVG, registerWindow } from '@svgdotjs/svg.js'
|
|||
import sharp from "sharp";
|
||||
import crypto from "crypto";
|
||||
import Election from "./election.js";
|
||||
import VoteType from './VoteType.js';
|
||||
|
||||
export function MakePrediction(election : Election) : Promise<Prediction> {
|
||||
return new Promise(async res => {
|
||||
|
@ -24,8 +25,17 @@ export function MakePrediction(election : Election) : Promise<Prediction> {
|
|||
if (Object.keys(election.states[state].odds).every(p => election.states[state].odds[p] <= 0))
|
||||
for (const candidate of election.candidates)
|
||||
election.states[state].odds[candidate.party] = 1;
|
||||
var winner = await weightedRand(election.states[state].odds);
|
||||
var winner = "";
|
||||
if (election.voteType === VoteType.Electoral) {
|
||||
winner = await weightedRand(election.states[state].odds);
|
||||
pred.candidates.find((c : any) => c.party === winner).votes += election.states[state].electoralVotes;
|
||||
} else if (election.voteType === VoteType.Popular) {
|
||||
var votes = await getVotes(election.states[state].population!, election.states[state].odds);
|
||||
winner = Object.keys(votes).sort((a, b) => votes[b] - votes[a])[0];
|
||||
for (const candidate of election.candidates) {
|
||||
pred.candidates.find((c : any) => c.party === candidate.party).votes += votes[candidate.party];
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
draw.find(`#${state}`).fill(election.candidates.find((c : any) => c.party === winner).color);
|
||||
}
|
||||
|
@ -33,6 +43,7 @@ export function MakePrediction(election : Election) : Promise<Prediction> {
|
|||
var s = sharp(Buffer.from(draw.svg()));
|
||||
var png = await s.png().toBuffer();
|
||||
pred.winner = pred.candidates.sort((a : any, b : any) => b.votes - a.votes)[0].name;
|
||||
pred.totalVotes = pred.candidates.reduce((a : any, b : any) => a + b.votes, 0);
|
||||
pred.svg = draw.svg();
|
||||
pred.png = png;
|
||||
res(pred);
|
||||
|
@ -44,9 +55,10 @@ export interface Prediction {
|
|||
candidates : {
|
||||
name : string,
|
||||
party : string,
|
||||
votes : string,
|
||||
votes : number,
|
||||
}[],
|
||||
winner: string,
|
||||
totalVotes: number,
|
||||
svg: string,
|
||||
png: Buffer,
|
||||
}
|
||||
|
@ -72,3 +84,16 @@ export async function weightedRand(spec : { [key : string] : number }) : Promise
|
|||
}
|
||||
return table[await betterRandom(0, table.length)];
|
||||
}
|
||||
|
||||
export async function getVotes(population: number, spec: { [key: string]: number }) : Promise<{ [key: string]: number }>{
|
||||
// split the population into 100 chunks
|
||||
var chunk = population / 100;
|
||||
var votes = {} as { [key: string]: number };
|
||||
for (var c in spec) votes[c] = 0;
|
||||
for (var i = 0; i < 100; i++) {
|
||||
var winner = await weightedRand(spec);
|
||||
votes[winner] += chunk;
|
||||
}
|
||||
for (var c in votes) votes[c] = Math.round(votes[c]);
|
||||
return votes;
|
||||
}
|
Loading…
Reference in a new issue