Skip to content
Closed

Ppis #1161

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Projects/Election Campaign Simulator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Election Campaign Simulator

Manage a 30-day political campaign with a $1,000,000 budget. Take actions, deliver speeches, and track voter sentiment across demographic groups to win the election.

## Features
- **Budget Management** — Spend on ads, rallies, canvassing, and fundraising
- **Speech Writer** — Write and deliver speeches on key topics
- **Voter Sentiment** — Track approval across youth, suburban, rural, urban, and senior demographics
- **Random Events** — Endorsements, scandals, and surprises affect your campaign

Open `index.html` in any browser to play.
65 changes: 65 additions & 0 deletions Projects/Election Campaign Simulator/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Election Campaign Simulator — Manage your campaign budget, deliver speeches, and track voter sentiment.">
<title>Election Campaign Simulator</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="app">
<header class="topbar">
<h1><span aria-hidden="true">&#x1F3DB;</span> Election Campaign Simulator</h1>
<p class="subtitle">Budget &middot; Speeches &middot; Voter Sentiment</p>
</header>

<div class="dashboard">
<div class="stats-row">
<div class="stat-card"><span class="stat-label">Budget</span><span class="stat-value gold" id="budgetVal">$1,000,000</span></div>
<div class="stat-card"><span class="stat-label">Approval</span><span class="stat-value" id="approvalVal">50%</span></div>
<div class="stat-card"><span class="stat-label">Day</span><span class="stat-value" id="dayVal">1 / 30</span></div>
<div class="stat-card"><span class="stat-label">Votes</span><span class="stat-value" id="votesVal">0</span></div>
</div>

<div class="main-grid">
<div class="panel">
<h2>Campaign Actions</h2>
<div class="actions" id="actionsList"></div>
</div>

<div class="panel">
<h2>Speech Writer</h2>
<div class="speech-area">
<select id="speechTopic" aria-label="Speech topic">
<option value="economy">Economy & Jobs</option>
<option value="healthcare">Healthcare</option>
<option value="education">Education</option>
<option value="security">National Security</option>
<option value="environment">Environment</option>
</select>
<textarea id="speechText" rows="4" placeholder="Write your campaign speech..." aria-label="Speech content"></textarea>
<button class="btn" id="deliverSpeech">Deliver Speech</button>
</div>
<div class="speech-log" id="speechLog"><p class="empty-state">No speeches delivered yet.</p></div>
</div>

<div class="panel">
<h2>Voter Sentiment</h2>
<div class="sentiment-gauge" id="sentimentGauge">
<div class="gauge-bar"><div class="gauge-fill" id="sentimentFill" style="width:50%"></div></div>
<div class="gauge-labels"><span>Hostile</span><span id="sentimentLabel">Neutral</span><span>Adoring</span></div>
</div>
<div class="demographics" id="demographics"></div>
</div>
</div>

<div class="event-log" id="eventLog">
<h3>Campaign Trail Log</h3>
<div class="log-entries" id="logEntries"><p class="empty-state">Your campaign begins today. Make every decision count.</p></div>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions Projects/Election Campaign Simulator/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"title": "Election Campaign Simulator",
"description": "Manage your campaign budget, deliver speeches, and track voter sentiment to win the election.",
"entry": "index.html",
"tags": ["html", "css", "javascript", "simulation"],
"author": {
"name": "Girish Madarkar",
"github": "Girish0902"
}
}
152 changes: 152 additions & 0 deletions Projects/Election Campaign Simulator/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
const state = {
budget: 1000000,
approval: 50,
day: 1,
maxDays: 30,
votes: 0,
log: [],
sentiment: {
overall: 50,
youth: 50, suburban: 50, rural: 50, urban: 50,
seniors: 50, undecided: 50,
},
};

const ACTIONS = [
{ name: "TV Ad Campaign", cost: 80000, approval: 3, votes: 5000, desc: "Broadcast ads across key networks" },
{ name: "Rally in City", cost: 30000, approval: 2, votes: 3000, desc: "Hold a major rally in an urban center" },
{ name: "Door-to-Door Canvassing", cost: 15000, approval: 1, votes: 2000, desc: "Volunteers engage voters personally" },
{ name: "Social Media Blitz", cost: 10000, approval: 1, votes: 1500, desc: "Targeted digital campaign" },
{ name: "Town Hall Meeting", cost: 20000, approval: 4, votes: 1000, desc: "Answer questions from undecided voters" },
{ name: "Radio Interview", cost: 5000, approval: 1, votes: 800, desc: "Speak on popular talk radio" },
{ name: "Fundraising Dinner", cost: -40000, approval: 0, votes: 0, desc: "Raise funds from donors (gain budget)" },
{ name: "Opposition Research", cost: 25000, approval: 0, votes: 6000, desc: "Uncover weakness in opponent's record" },
{ name: "Get Out The Vote", cost: 40000, approval: 0, votes: 8000, desc: "Mobilize supporters on election day" },
];

const SPEECHES = {
economy: { impact: { youth: 2, suburban: 3, rural: 2, seniors: 3, urban: 2 }, approval: 2 },
healthcare: { impact: { youth: 3, suburban: 3, rural: 2, seniors: 4, urban: 3 }, approval: 3 },
education: { impact: { youth: 4, suburban: 3, rural: 1, seniors: 1, urban: 3 }, approval: 2 },
security: { impact: { youth: 1, suburban: 2, rural: 3, seniors: 4, urban: 1 }, approval: 2 },
environment: { impact: { youth: 4, suburban: 3, rural: 1, seniors: 1, urban: 2 }, approval: 1 },
};

const NAMES = ["Urban voters","Suburban families","Rural communities","Young voters","Senior citizens","Undecided voters"];

const $=id=>document.getElementById(id);

function updateUI(){
$('budgetVal').textContent='$'+state.budget.toLocaleString();
$('approvalVal').textContent=state.approval+'%';
$('approvalVal').style.color=state.approval>=60?'var(--green)':state.approval>=40?'var(--gold)':'var(--red)';
$('dayVal').textContent=state.day+' / '+state.maxDays;
$('votesVal').textContent=state.votes.toLocaleString();
const fill=$('sentimentFill');
fill.style.width=state.sentiment.overall+'%';
const labels=['Hostile','Unfavorable','Neutral','Favorable','Adoring'];
const idx=state.sentiment.overall<20?0:state.sentiment.overall<40?1:state.sentiment.overall<60?2:state.sentiment.overall<80?3:4;
$('sentimentLabel').textContent=labels[idx];

const demo=$('demographics');
const groups=['youth','suburban','rural','urban','seniors','undecided'];
demo.innerHTML=groups.map(g=>{
const val=state.sentiment[g];
const color=val>=60?'var(--green)':val>=40?'var(--gold)':'var(--red)';
const label=g==='youth'?'Youth (18-29)':g==='suburban'?'Suburban':g==='rural'?'Rural':g==='urban'?'Urban':g==='seniors'?'Seniors (65+)':'Undecided';
return `<div class="demo-row"><span class="label">${label}</span><span class="val" style="color:${color}">${val}%</span></div>`;
}).join('');

const acts=$('actionsList');
acts.innerHTML=ACTIONS.map((a,i)=>{
const affordable=a.cost<=0||a.cost<=state.budget;
const canAct=state.day<state.maxDays;
return `<button class="action-btn" data-idx="${i}" ${(!affordable||!canAct)?'disabled':''}>
${a.name} <span class="cost">${a.cost<0?'+$'+Math.abs(a.cost).toLocaleString():'$'+a.cost.toLocaleString()} · ${a.votes.toLocaleString()} votes · +${a.approval}% app.</span>
</button>`;
}).join('');
acts.querySelectorAll('.action-btn').forEach(b=>b.addEventListener('click',()=>performAction(parseInt(b.dataset.idx))));
}

function performAction(idx){
const a=ACTIONS[idx];
if(a.cost>0&&a.cost>state.budget) return;
if(state.day>=state.maxDays) return;
state.budget-=a.cost;
state.approval=Math.min(100,Math.max(0,state.approval+a.approval+Math.floor(Math.random()*3-1)));
state.votes+=Math.floor(a.votes*(0.8+Math.random()*0.4));
state.sentiment.overall=Math.min(100,Math.max(0,state.sentiment.overall+Math.floor(Math.random()*4-1)));
state.day++;
addLog(`Day ${state.day-1}: ${a.name}`, a.desc);
randomEvent();
updateUI();
if(state.day>=state.maxDays) endCampaign();
}

function deliverSpeech(){
const topic=$('speechTopic').value;
const text=$('speechText').value.trim();
if(!text){ addLog('Speech draft empty','Write something before delivering.'); return; }
if(state.day>=state.maxDays) return;

const sp=SPEECHES[topic];
Object.keys(sp.impact).forEach(k=>{
state.sentiment[k]=Math.min(100,Math.max(0,state.sentiment[k]+sp.impact[k]));
});
const avg=Object.values(state.sentiment).slice(0,5).reduce((a,b)=>a+b,0)/5;
state.sentiment.overall=Math.round(avg);
state.approval=Math.min(100,Math.max(0,state.approval+sp.approval+Math.floor(Math.random()*2)));
state.day++;
addLog(`Speech on ${topic}`, text.length>80?text.slice(0,80)+'...':text);
$('speechText').value='';

const log=$('speechLog');
const entry=document.createElement('div');
entry.className='speech-entry';
entry.innerHTML=`<span class="topic">[${topic}]</span> "${text.length>60?text.slice(0,60)+'...':text}" <span class="impact">+${sp.approval}% approval</span>`;
log.prepend(entry);
if(log.children.length>5) log.removeChild(log.lastChild);

randomEvent();
updateUI();
if(state.day>=state.maxDays) endCampaign();
}

function randomEvent(){
const events=[
{ msg:"Endorsement from a local newspaper!", approval:2, votes:2000 },
{ msg:"Your opponent released a negative ad.", approval:-2, votes:-1000 },
{ msg:"A gaffe at a public event hurts your campaign.", approval:-3, votes:-1500 },
{ msg:"A celebrity endorses you!", approval:2, votes:3000 },
{ msg:"Debate performance praised by pundits.", approval:3, votes:2500 },
{ msg:"Bad weather reduces rally turnout.", approval:-1, votes:-500 },
{ msg:"A policy proposal gains national attention!", approval:3, votes:4000 },
{ msg:"Campaign staff error causes scheduling chaos.", approval:-1, votes:-500 },
];
if(Math.random()<0.35){
const e=events[Math.floor(Math.random()*events.length)];
state.approval=Math.min(100,Math.max(0,state.approval+e.approval));
state.votes=Math.max(0,state.votes+e.votes);
addLog('Event: '+e.msg,'');
}
}

function addLog(title,desc){
const el=$('logEntries');
const entry=document.createElement('div');
entry.className='log-entry';
entry.innerHTML=`<span class="day">D${state.day}</span> <span><strong>${title}</strong>${desc?' — '+desc:''}</span>`;
el.prepend(entry);
if(el.children.length>20) el.removeChild(el.lastChild);
}

function endCampaign(){
const win=state.votes>=50000;
const msg=win?'Congratulations! You won the election with '+state.votes.toLocaleString()+' votes!' : 'You lost the election with '+state.votes.toLocaleString()+' votes. Try a different strategy next time.';
addLog('Election Day!',msg);
$('actionsList').innerHTML=`<div class="empty-state" style="padding:30px">Campaign Over — ${msg}<br><br><button class="btn" onclick="location.reload()">Start New Campaign</button></div>`;
}

$('deliverSpeech').addEventListener('click',deliverSpeech);
updateUI();
addLog('Campaign Kickoff','Your campaign for office has begun. You have 30 days and $1,000,000.');
46 changes: 46 additions & 0 deletions Projects/Election Campaign Simulator/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
:root{--bg:#0b1120;--surface:#111827;--card:rgba(30,41,59,0.6);--border:#334155;--gold:#d4a017;--gold-glow:rgba(212,160,23,0.12);--text:#f8fafc;--text2:#cbd5e1;--text3:#64748b;--accent:#93c5fd;--green:#22c55e;--red:#ef4444;--blue:#3b82f6;--radius:10px;--trans:all 0.3s cubic-bezier(0.16,1,0.3,1)}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:var(--bg);color:var(--text2);min-height:100vh}
.app{max-width:1200px;margin:0 auto;padding:20px}
.topbar{text-align:center;padding:20px 0;border-bottom:1px solid var(--border);margin-bottom:20px}
.topbar h1{font-size:22px;font-weight:700;color:var(--gold);letter-spacing:1px}
.topbar .subtitle{font-size:13px;color:var(--text3);margin-top:4px}
.stats-row{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:20px}
.stat-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:16px;text-align:center;backdrop-filter:blur(8px)}
.stat-label{font-size:11px;color:var(--text3);text-transform:uppercase;letter-spacing:0.8px;display:block}
.stat-value{font-family:ui-monospace,Consolas,monospace;font-size:22px;font-weight:700;color:var(--text);margin-top:4px;display:block}
.stat-value.gold{color:var(--gold)}
.main-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:20px}
@media(max-width:800px){.main-grid{grid-template-columns:1fr}.stats-row{grid-template-columns:repeat(2,1fr)}}
.panel{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:20px;backdrop-filter:blur(8px)}
.panel h2{font-size:13px;font-weight:600;color:var(--accent);text-transform:uppercase;letter-spacing:1px;margin-bottom:14px;padding-bottom:8px;border-bottom:1px solid var(--border)}
.actions{display:grid;grid-template-columns:1fr;gap:8px}
.action-btn{padding:12px 16px;background:var(--surface);border:1px solid var(--border);border-radius:8px;color:var(--text2);font-size:13px;cursor:pointer;transition:var(--trans);text-align:left;font-family:inherit}
.action-btn:hover{border-color:var(--gold);background:var(--gold-glow)}
.action-btn .cost{font-family:ui-monospace,Consolas,monospace;font-size:11px;color:var(--gold);display:block;margin-top:3px}
.action-btn:disabled{opacity:0.3;cursor:not-allowed}
.speech-area select,.speech-area textarea{width:100%;padding:10px 12px;background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:8px;font-size:13px;margin-bottom:8px;font-family:inherit;outline:none}
.speech-area select:focus,.speech-area textarea:focus{border-color:var(--gold)}
.speech-area textarea{resize:vertical;min-height:80px}
.btn{padding:10px 24px;background:var(--gold-glow);border:1px solid var(--gold);border-radius:8px;color:var(--gold);font-size:13px;font-weight:500;cursor:pointer;transition:var(--trans);font-family:inherit;width:100%}
.btn:hover{box-shadow:0 0 20px var(--gold-glow)}
.btn:disabled{opacity:0.3;cursor:not-allowed}
.speech-log{margin-top:12px;max-height:200px;overflow-y:auto}
.speech-entry{padding:10px;background:var(--surface);border-radius:6px;margin-bottom:6px;font-size:12px;line-height:1.5}
.speech-entry .topic{color:var(--gold);font-weight:600}
.speech-entry .impact{color:var(--green)}
.sentiment-gauge{margin-bottom:16px}
.gauge-bar{height:12px;background:var(--surface);border-radius:6px;overflow:hidden;border:1px solid var(--border)}
.gauge-fill{height:100%;background:linear-gradient(90deg,var(--red),var(--gold),var(--green));border-radius:6px;transition:width 0.6s cubic-bezier(0.16,1,0.3,1)}
.gauge-labels{display:flex;justify-content:space-between;font-size:10px;color:var(--text3);margin-top:4px}
.gauge-labels span:nth-child(2){color:var(--gold);font-weight:600}
.demographics{display:grid;gap:8px}
.demo-row{display:flex;justify-content:space-between;align-items:center;font-size:12px;padding:4px 0}
.demo-row .label{color:var(--text2)}
.demo-row .val{font-family:ui-monospace,Consolas,monospace;font-size:11px}
.event-log{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:20px;backdrop-filter:blur(8px)}
.event-log h3{font-size:12px;font-weight:600;color:var(--accent);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px}
.log-entries{max-height:180px;overflow-y:auto}
.log-entry{padding:8px 0;border-bottom:1px solid rgba(51,65,85,0.4);font-size:12px;color:var(--text2);line-height:1.5;display:flex;gap:8px}
.log-entry .day{font-family:ui-monospace,Consolas,monospace;color:var(--gold);white-space:nowrap}
.empty-state{text-align:center;padding:20px;color:var(--text3);font-size:12px}
27 changes: 27 additions & 0 deletions Projects/Election Campaign Simulator/thumbnail.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading