add more election types; add image overlay to simulator (wip)
This commit is contained in:
parent
1c82c1d5ca
commit
4d5dc235d1
|
@ -84,6 +84,16 @@ const commands = [
|
||||||
description: 'The odds of the candidate to win in any state',
|
description: 'The odds of the candidate to win in any state',
|
||||||
type: ApplicationCommandOptionType.Number
|
type: ApplicationCommandOptionType.Number
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'image_overlay',
|
||||||
|
description: 'Overlay an image',
|
||||||
|
type: ApplicationCommandOptionType.Attachment
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'image_opacity',
|
||||||
|
description: 'Image overlay opacity',
|
||||||
|
type: ApplicationCommandOptionType.Number
|
||||||
|
},
|
||||||
...Elections[e].candidates.flatMap(c => [
|
...Elections[e].candidates.flatMap(c => [
|
||||||
{
|
{
|
||||||
name: c.party.toLowerCase().replace(/ /g, "_") + "_candidate",
|
name: c.party.toLowerCase().replace(/ /g, "_") + "_candidate",
|
||||||
|
|
17
src/index.ts
17
src/index.ts
|
@ -72,7 +72,7 @@ if (!config.token) {
|
||||||
.setDescription("API test")
|
.setDescription("API test")
|
||||||
.addFields(Object.values(results[year][0].candidates).map((candidate: any) => ({
|
.addFields(Object.values(results[year][0].candidates).map((candidate: any) => ({
|
||||||
name: `${candidate.winner ? ":white_check_mark:" : ""} ${CandidateEmojis[candidate.party] ?? ""} ${candidate.name} ${candidate.incumbent ? "(I)" : ""} (${candidate.party})`,
|
name: `${candidate.winner ? ":white_check_mark:" : ""} ${CandidateEmojis[candidate.party] ?? ""} ${candidate.name} ${candidate.incumbent ? "(I)" : ""} (${candidate.party})`,
|
||||||
value: `${results[year][0].election_type === "electoral" ? `${candidate.electoral_votes} electoral votes\n` : ""} ${candidate.votes.toLocaleString()} votes (${candidate.percent}%)`,
|
value: `${results[year][0].election_type === "electoral" ? `${candidate.electoral_votes} electoral votes\n` : ""}${results[year][0].election_type === "parliament" ? `${candidate.seats_won} seats\n` : ""}${candidate.states_carried !== null && candidate.states_carried !== undefined ? `${candidate.states_carried} states carried\n` : ""}${candidate.delegates !== null && candidate.delegates !== undefined ? `${candidate.delegates} delegates\n` : ""}${candidate.votes !== null && candidate.votes !== undefined ? `${candidate.votes.toLocaleString()} votes (${candidate.percent}%)` : ""}`,
|
||||||
inline: true
|
inline: true
|
||||||
})))
|
})))
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
|
@ -105,6 +105,7 @@ if (!config.token) {
|
||||||
|
|
||||||
case "simulate":
|
case "simulate":
|
||||||
var electionname = (i.options as CommandInteractionOptionResolver).getSubcommand();
|
var electionname = (i.options as CommandInteractionOptionResolver).getSubcommand();
|
||||||
|
var overlayimage = (i.options as CommandInteractionOptionResolver).getAttachment('image_overlay');
|
||||||
|
|
||||||
var election = structuredClone(Elections[electionname]);
|
var election = structuredClone(Elections[electionname]);
|
||||||
for (const candidate of election.candidates) {
|
for (const candidate of election.candidates) {
|
||||||
|
@ -141,14 +142,24 @@ if (!config.token) {
|
||||||
for (const state of Object.keys(election.states))
|
for (const state of Object.keys(election.states))
|
||||||
election.states[state].odds[party] = odds;
|
election.states[state].odds[party] = odds;
|
||||||
}
|
}
|
||||||
var result = await MakePrediction(election);
|
if (overlayimage !== null) {
|
||||||
|
if (overlayimage.size > 5000000) {
|
||||||
|
await i.editReply("Keep images under 5 MB please!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (overlayimage.contentType?.substring(0, 5) != "image") {
|
||||||
|
await i.editReply("Invalid image!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var result = await MakePrediction(election, overlayimage?.url);
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.setTitle(election.title)
|
.setTitle(election.title)
|
||||||
.setDescription(election.description.replace("$WINNER", result.winner))
|
.setDescription(election.description.replace("$WINNER", result.winner))
|
||||||
.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: `${election.voteType === VoteType.Electoral ? `${c.electoralVotes} electoral votes\n` : ""}${c.votes} votes (${((c.votes / result.totalVotes) * 100).toFixed(2)}%)`,
|
value: `${election.voteType === VoteType.Electoral ? `${c.electoralVotes} electoral votes\n` : ""}${c.votes.toLocaleString()} votes (${((c.votes / result.totalVotes) * 100).toFixed(2)}%)`,
|
||||||
inline: true
|
inline: true
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -5,7 +5,7 @@ import crypto from "crypto";
|
||||||
import Election from "./election.js";
|
import Election from "./election.js";
|
||||||
import VoteType from './VoteType.js';
|
import VoteType from './VoteType.js';
|
||||||
|
|
||||||
export function MakePrediction(election : Election) : Promise<Prediction> {
|
export function MakePrediction(election : Election, overlay_image?: string) : Promise<Prediction> {
|
||||||
return new Promise(async res => {
|
return new Promise(async res => {
|
||||||
const window = createSVGWindow();
|
const window = createSVGWindow();
|
||||||
registerWindow(window, window.document);
|
registerWindow(window, window.document);
|
||||||
|
@ -41,6 +41,33 @@ 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();
|
||||||
|
|
||||||
|
//overlay image
|
||||||
|
if (overlay_image !== undefined) {
|
||||||
|
const url = await fetch(overlay_image);
|
||||||
|
const arrayBuffer = await url.arrayBuffer();
|
||||||
|
const overlayBuffer = Buffer.from(arrayBuffer);
|
||||||
|
|
||||||
|
const overlay = await sharp(overlayBuffer)
|
||||||
|
.composite([{
|
||||||
|
input: Buffer.from([0, 0, 0, 255]),
|
||||||
|
raw: {
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
channels: 4,
|
||||||
|
},
|
||||||
|
tile: true,
|
||||||
|
blend: 'dest-in',
|
||||||
|
}])
|
||||||
|
.png()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
png = await sharp(png)
|
||||||
|
.composite([{ input: overlay, blend: 'over' }])
|
||||||
|
.png()
|
||||||
|
.toBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
if (election.voteType === VoteType.Electoral)
|
if (election.voteType === VoteType.Electoral)
|
||||||
pred.winner = pred.candidates.sort((a : any, b : any) => b.electoralVotes - a.electoralVotes)[0].name;
|
pred.winner = pred.candidates.sort((a : any, b : any) => b.electoralVotes - a.electoralVotes)[0].name;
|
||||||
else if (election.voteType === VoteType.Popular)
|
else if (election.voteType === VoteType.Popular)
|
||||||
|
|
Loading…
Reference in a new issue