diff --git a/assets/NorthKorea2019.svg b/assets/NorthKorea2019.svg
new file mode 100644
index 0000000..a7f1f7b
--- /dev/null
+++ b/assets/NorthKorea2019.svg
@@ -0,0 +1,66 @@
+
+
+
\ No newline at end of file
diff --git a/src/VoteType.ts b/src/VoteType.ts
new file mode 100644
index 0000000..febf2dd
--- /dev/null
+++ b/src/VoteType.ts
@@ -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;
\ No newline at end of file
diff --git a/src/election.ts b/src/election.ts
index 9390056..62d7904 100644
--- a/src/election.ts
+++ b/src/election.ts
@@ -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
}
diff --git a/src/elections/1789.ts b/src/elections/1789.ts
index db969ed..caae7e1 100644
--- a/src/elections/1789.ts
+++ b/src/elections/1789.ts
@@ -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: [
{
diff --git a/src/elections/1848.ts b/src/elections/1848.ts
index 3e4392e..e0c00f7 100644
--- a/src/elections/1848.ts
+++ b/src/elections/1848.ts
@@ -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: [
{
diff --git a/src/elections/1864.ts b/src/elections/1864.ts
index f8eef90..534ada1 100644
--- a/src/elections/1864.ts
+++ b/src/elections/1864.ts
@@ -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: [
{
diff --git a/src/elections/1940.ts b/src/elections/1940.ts
index c20b3a9..35aac3c 100644
--- a/src/elections/1940.ts
+++ b/src/elections/1940.ts
@@ -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: [
{
diff --git a/src/elections/1968.ts b/src/elections/1968.ts
index c20b3a9..35aac3c 100644
--- a/src/elections/1968.ts
+++ b/src/elections/1968.ts
@@ -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: [
{
diff --git a/src/elections/1992.ts b/src/elections/1992.ts
index db378a5..a150bd1 100644
--- a/src/elections/1992.ts
+++ b/src/elections/1992.ts
@@ -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: [
{
diff --git a/src/elections/2000.ts b/src/elections/2000.ts
index e08cd87..4067490 100644
--- a/src/elections/2000.ts
+++ b/src/elections/2000.ts
@@ -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: [
{
diff --git a/src/elections/2004.ts b/src/elections/2004.ts
index a4c2b6a..f508811 100644
--- a/src/elections/2004.ts
+++ b/src/elections/2004.ts
@@ -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: [
{
diff --git a/src/elections/2008.ts b/src/elections/2008.ts
index 07bda7e..8d61aeb 100644
--- a/src/elections/2008.ts
+++ b/src/elections/2008.ts
@@ -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: [
{
diff --git a/src/elections/2024.ts b/src/elections/2024.ts
index c8d6c4f..dab8a21 100644
--- a/src/elections/2024.ts
+++ b/src/elections/2024.ts
@@ -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: [
{
diff --git a/src/elections/NK2019.ts b/src/elections/NK2019.ts
new file mode 100644
index 0000000..4965a9a
--- /dev/null
+++ b/src/elections/NK2019.ts
@@ -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;
\ No newline at end of file
diff --git a/src/elections/elections.ts b/src/elections/elections.ts
index 8087308..7521869 100644
--- a/src/elections/elections.ts
+++ b/src/elections/elections.ts
@@ -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})
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index 1d67d13..81ec061 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -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
}
}))
diff --git a/src/predictor.ts b/src/predictor.ts
index 7c712dc..cebcce5 100644
--- a/src/predictor.ts
+++ b/src/predictor.ts
@@ -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 {
return new Promise(async res => {
@@ -24,8 +25,17 @@ export function MakePrediction(election : Election) : Promise {
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);
- pred.candidates.find((c : any) => c.party === winner).votes += election.states[state].electoralVotes;
+ 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 {
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,
}
@@ -71,4 +83,17 @@ 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;
}
\ No newline at end of file