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 {
|
export default interface Election {
|
||||||
title : string,
|
title : string,
|
||||||
shortname : string,
|
shortname : string,
|
||||||
description : string,
|
description : string,
|
||||||
|
voteType : VoteType,
|
||||||
svg: string,
|
svg: string,
|
||||||
candidates : {
|
candidates : {
|
||||||
name : string,
|
name : string,
|
||||||
|
@ -10,7 +13,8 @@ export default interface Election {
|
||||||
}[],
|
}[],
|
||||||
states : {
|
states : {
|
||||||
[key : string] : {
|
[key : string] : {
|
||||||
electoralVotes : number,
|
electoralVotes? : number | undefined,
|
||||||
|
population? : number | undefined,
|
||||||
odds : {
|
odds : {
|
||||||
[key : string] : number
|
[key : string] : number
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_1789 = {
|
const Presidential_1789 = {
|
||||||
title: "1789 United States Presidential Election Simulator",
|
title: "1789 United States Presidential Election Simulator",
|
||||||
shortname: "1789",
|
shortname: "1789",
|
||||||
description: "The CalubViem Press has rewritten history and called the 1789 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege1789.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_1848 = {
|
const Presidential_1848 = {
|
||||||
title: "1848 United States Presidential Election Simulator",
|
title: "1848 United States Presidential Election Simulator",
|
||||||
shortname: "1848",
|
shortname: "1848",
|
||||||
description: "The CalubViem Press has rewritten history and called the 1848 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege1848.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_1864 = {
|
const Presidential_1864 = {
|
||||||
title: "1864 United States Presidential Election Simulator",
|
title: "1864 United States Presidential Election Simulator",
|
||||||
shortname: "1864",
|
shortname: "1864",
|
||||||
description: "The CalubViem Press has rewritten history and called the 1864 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege1864.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_1968 = {
|
const Presidential_1968 = {
|
||||||
title: "1968 United States Presidential Election Simulator",
|
title: "1968 United States Presidential Election Simulator",
|
||||||
shortname: "1968",
|
shortname: "1968",
|
||||||
description: "The CalubViem Press has rewritten history and called the 1968 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege1968.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_1968 = {
|
const Presidential_1968 = {
|
||||||
title: "1968 United States Presidential Election Simulator",
|
title: "1968 United States Presidential Election Simulator",
|
||||||
shortname: "1968",
|
shortname: "1968",
|
||||||
description: "The CalubViem Press has rewritten history and called the 1968 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege1968.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_1992 = {
|
const Presidential_1992 = {
|
||||||
title: "1992 United States Presidential Election Simulator",
|
title: "1992 United States Presidential Election Simulator",
|
||||||
shortname: "1992",
|
shortname: "1992",
|
||||||
description: "The CalubViem Press has rewritten history and called the 1992 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege1992.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_2000 = {
|
const Presidential_2000 = {
|
||||||
title: "2000 United States Presidential Election Simulator",
|
title: "2000 United States Presidential Election Simulator",
|
||||||
shortname: "2000",
|
shortname: "2000",
|
||||||
description: "The CalubViem Press has rewritten history and called the 2000 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege1992.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_2004 = {
|
const Presidential_2004 = {
|
||||||
title: "2004 United States Presidential Election Simulator",
|
title: "2004 United States Presidential Election Simulator",
|
||||||
shortname: "2004",
|
shortname: "2004",
|
||||||
description: "The CalubViem Press has rewritten history and called the 2004 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege2004.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_2008 = {
|
const Presidential_2008 = {
|
||||||
title: "2008 United States Presidential Election Simulator",
|
title: "2008 United States Presidential Election Simulator",
|
||||||
shortname: "2008",
|
shortname: "2008",
|
||||||
description: "The CalubViem Press has rewritten history and called the 2008 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege2008.svg", "utf-8"),
|
||||||
candidates: [
|
candidates: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import Election from "../election.js";
|
import Election from "../election.js";
|
||||||
|
import VoteType from "../VoteType.js";
|
||||||
|
|
||||||
const Presidential_2024 = {
|
const Presidential_2024 = {
|
||||||
title: "2024 United States Presidential Election Simulator",
|
title: "2024 United States Presidential Election Simulator",
|
||||||
shortname: "2024",
|
shortname: "2024",
|
||||||
description: "The CalubViem Press has called the 2024 United States Presidential Election for $WINNER!",
|
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"),
|
svg: await readFile("assets/ElectoralCollege2024.svg", "utf-8"),
|
||||||
candidates: [
|
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_2004 from "./2004.js";
|
||||||
import Presidential_2008 from "./2008.js";
|
import Presidential_2008 from "./2008.js";
|
||||||
import Presidential_2024 from "./2024.js";
|
import Presidential_2024 from "./2024.js";
|
||||||
|
import NK_2019 from "./NK2019.js";
|
||||||
|
|
||||||
const Elections = {
|
const Elections = {
|
||||||
|
// US
|
||||||
"1789": Presidential_1789,
|
"1789": Presidential_1789,
|
||||||
"1848": Presidential_1848,
|
"1848": Presidential_1848,
|
||||||
"1864": Presidential_1864,
|
"1864": Presidential_1864,
|
||||||
|
@ -18,7 +20,9 @@ const Elections = {
|
||||||
"2000": Presidential_2000,
|
"2000": Presidential_2000,
|
||||||
"2004": Presidential_2004,
|
"2004": Presidential_2004,
|
||||||
"2008": Presidential_2008,
|
"2008": Presidential_2008,
|
||||||
"2024": Presidential_2024
|
"2024": Presidential_2024,
|
||||||
|
// Other
|
||||||
|
"nk2019": NK_2019,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (Elections as {[key : string] : Election})
|
export default (Elections as {[key : string] : Election})
|
|
@ -5,6 +5,7 @@ import {MakePrediction} from "./predictor.js";
|
||||||
import Election from "./election.js";
|
import Election from "./election.js";
|
||||||
import Presidential_2024 from "./elections/2024.js";
|
import Presidential_2024 from "./elections/2024.js";
|
||||||
import Elections from "./elections/elections.js";
|
import Elections from "./elections/elections.js";
|
||||||
|
import VoteType, { VoteTypeString } from "./VoteType.js";
|
||||||
|
|
||||||
const configraw = fs.readFileSync("config.json", "utf-8");
|
const configraw = fs.readFileSync("config.json", "utf-8");
|
||||||
const config = JSON.parse(configraw);
|
const config = JSON.parse(configraw);
|
||||||
|
@ -100,7 +101,7 @@ if (!config.token) {
|
||||||
.addFields(result.candidates.map(c => {
|
.addFields(result.candidates.map(c => {
|
||||||
return {
|
return {
|
||||||
name: `${(result.winner === c.name ? ":white_check_mark:" : "")} ${c.name} (${c.party})`,
|
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
|
inline: true
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { SVG, registerWindow } from '@svgdotjs/svg.js'
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import Election from "./election.js";
|
import Election from "./election.js";
|
||||||
|
import VoteType from './VoteType.js';
|
||||||
|
|
||||||
export function MakePrediction(election : Election) : Promise<Prediction> {
|
export function MakePrediction(election : Election) : Promise<Prediction> {
|
||||||
return new Promise(async res => {
|
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))
|
if (Object.keys(election.states[state].odds).every(p => election.states[state].odds[p] <= 0))
|
||||||
for (const candidate of election.candidates)
|
for (const candidate of election.candidates)
|
||||||
election.states[state].odds[candidate.party] = 1;
|
election.states[state].odds[candidate.party] = 1;
|
||||||
var winner = await weightedRand(election.states[state].odds);
|
var winner = "";
|
||||||
pred.candidates.find((c : any) => c.party === winner).votes += election.states[state].electoralVotes;
|
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
|
// @ts-ignore
|
||||||
draw.find(`#${state}`).fill(election.candidates.find((c : any) => c.party === winner).color);
|
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 s = sharp(Buffer.from(draw.svg()));
|
||||||
var png = await s.png().toBuffer();
|
var png = await s.png().toBuffer();
|
||||||
pred.winner = pred.candidates.sort((a : any, b : any) => b.votes - a.votes)[0].name;
|
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.svg = draw.svg();
|
||||||
pred.png = png;
|
pred.png = png;
|
||||||
res(pred);
|
res(pred);
|
||||||
|
@ -44,9 +55,10 @@ export interface Prediction {
|
||||||
candidates : {
|
candidates : {
|
||||||
name : string,
|
name : string,
|
||||||
party : string,
|
party : string,
|
||||||
votes : string,
|
votes : number,
|
||||||
}[],
|
}[],
|
||||||
winner: string,
|
winner: string,
|
||||||
|
totalVotes: number,
|
||||||
svg: string,
|
svg: string,
|
||||||
png: Buffer,
|
png: Buffer,
|
||||||
}
|
}
|
||||||
|
@ -71,4 +83,17 @@ export async function weightedRand(spec : { [key : string] : number }) : Promise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return table[await betterRandom(0, table.length)];
|
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