Skip to content

Commit 7b8f946

Browse files
authored
Merge pull request #33 from code4policy/fix-visualisation
Fix visualisation
2 parents 31b0bbe + 905a916 commit 7b8f946

3 files changed

Lines changed: 151 additions & 177 deletions

File tree

app.js

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,33 +37,6 @@ if (mobileToggle && navMenu) {
3737

3838
// ---------------------------
3939
// Story 1.2 mini-game placeholder
40-
// ---------------------------
41-
const modeZero = document.getElementById("mode-zero");
42-
const modePositive = document.getElementById("mode-positive");
43-
const gameResult = document.getElementById("game-result");
44-
45-
function renderGame(mode) {
46-
if (mode === "zero") {
47-
modeZero.classList.remove("btn--ghost");
48-
modePositive.classList.add("btn--ghost");
49-
gameResult.innerHTML = `
50-
<div class="result__title">Outcome: fixed pie</div>
51-
<div class="result__body">Total resources are fixed. One player’s gain implies another player’s loss.</div>
52-
<div class="result__summary"><strong>Summary:</strong> Net total stays constant.</div>
53-
`;
54-
} else {
55-
modePositive.classList.remove("btn--ghost");
56-
modeZero.classList.add("btn--ghost");
57-
gameResult.innerHTML = `
58-
<div class="result__title">Outcome: growing pie</div>
59-
<div class="result__body">Total resources can expand. Gains may occur without requiring others to lose.</div>
60-
<div class="result__summary"><strong>Summary:</strong> Net total can increase.</div>
61-
`;
62-
}
63-
}
64-
65-
modeZero.addEventListener("click", () => renderGame("zero"));
66-
modePositive.addEventListener("click", () => renderGame("positive"));
6740

6841
// ---------------------------
6942
// Story 2: survey (4 questions) + scoring + benchmark stats

index.html

Lines changed: 1 addition & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -304,156 +304,6 @@ <h2>Mini game (2-minute intuition demo)</h2>
304304
</div>
305305
</div>
306306

307-
<script>
308-
const gameContainer = {
309-
start: document.getElementById('game-start'),
310-
playing: document.getElementById('game-playing'),
311-
results: document.getElementById('game-results'),
312-
choicePhase: document.getElementById('choice-phase'),
313-
resultPhase: document.getElementById('result-phase')
314-
};
315-
316-
let gameState = {
317-
mode: null,
318-
round: 1,
319-
yourScore: 0,
320-
theirScore: 0,
321-
yourMove: null,
322-
theirMove: null,
323-
history: []
324-
};
325-
326-
const gamePayoff = {
327-
zeroSum: {
328-
cc: { you: 3, them: 3 },
329-
cd: { you: 6, them: 0 },
330-
dc: { you: 0, them: 6 },
331-
dd: { you: 1, them: 1 }
332-
},
333-
positiveSum: {
334-
cc: { you: 6, them: 6 },
335-
cd: { you: 4, them: 8 },
336-
dc: { you: 8, them: 4 },
337-
dd: { you: 2, them: 2 }
338-
}
339-
};
340-
341-
function showScreen(screen) {
342-
gameContainer.start.style.display = 'none';
343-
gameContainer.playing.style.display = 'none';
344-
gameContainer.results.style.display = 'none';
345-
screen.style.display = 'block';
346-
}
347-
348-
function startGame(mode) {
349-
gameState = {
350-
mode: mode,
351-
round: 1,
352-
yourScore: 0,
353-
theirScore: 0,
354-
yourMove: null,
355-
theirMove: null,
356-
history: []
357-
};
358-
showScreen(gameContainer.playing);
359-
gameContainer.resultPhase.style.display = 'none';
360-
gameContainer.choicePhase.style.display = 'block';
361-
updateScoreDisplay();
362-
}
363-
364-
function updateScoreDisplay() {
365-
document.getElementById('round-number').textContent = gameState.round;
366-
document.getElementById('your-score').textContent = gameState.yourScore;
367-
document.getElementById('their-score').textContent = gameState.theirScore;
368-
}
369-
370-
function getOpponentMove(yourMove) {
371-
if (gameState.mode === 'zero-sum') {
372-
return Math.random() > 0.3 ? 'compete' : 'collab';
373-
} else {
374-
return Math.random() > 0.2 ? 'collab' : 'compete';
375-
}
376-
}
377-
378-
function processRound(yourMove) {
379-
gameState.yourMove = yourMove;
380-
gameState.theirMove = getOpponentMove(yourMove);
381-
382-
const payoffSet = gameState.mode === 'zero-sum' ? gamePayoff.zeroSum : gamePayoff.positiveSum;
383-
const key = (yourMove === 'compete' ? 'c' : 'd') + (gameState.theirMove === 'compete' ? 'c' : 'd');
384-
const payoff = payoffSet[key];
385-
386-
gameState.yourScore += payoff.you;
387-
gameState.theirScore += payoff.them;
388-
gameState.history.push({ your: yourMove, their: gameState.theirMove, payoff });
389-
390-
// Display results
391-
document.getElementById('your-move-display').textContent = yourMove === 'compete' ? '⚔️ Compete' : '🤝 Collaborate';
392-
document.getElementById('their-move-display').textContent = gameState.theirMove === 'compete' ? '⚔️ Compete' : '🤝 Collaborate';
393-
document.getElementById('round-your-gain').textContent = '+' + payoff.you;
394-
document.getElementById('round-their-gain').textContent = '+' + payoff.them;
395-
396-
let insight = '';
397-
if (yourMove === 'compete' && gameState.theirMove === 'compete') {
398-
insight = '⚔️ Both competed! The market shrinks. Low gains for both.';
399-
} else if (yourMove === 'collab' && gameState.theirMove === 'collab') {
400-
insight = '🤝 Both collaborated! The market grows. High gains for everyone.';
401-
} else if (yourMove === 'compete' && gameState.theirMove === 'collab') {
402-
insight = '😱 You exploited their trust. You won this round, but trust is broken.';
403-
} else {
404-
insight = '😢 They exploited your trust. Your collaborative approach backfired.';
405-
}
406-
document.getElementById('round-insight').innerHTML = '<strong style="color: #f97316;">💡</strong> ' + insight;
407-
408-
updateScoreDisplay();
409-
gameContainer.choicePhase.style.display = 'none';
410-
gameContainer.resultPhase.style.display = 'block';
411-
}
412-
413-
function endGame() {
414-
document.getElementById('final-your-score').textContent = gameState.yourScore;
415-
document.getElementById('final-their-score').textContent = gameState.theirScore;
416-
417-
let conclusion = '';
418-
if (gameState.yourScore > gameState.theirScore + 5) {
419-
conclusion = '🏆 <strong>You won through competition!</strong> But this mindset often leads to mutual destruction in real situations. In zero-sum thinking, everyone loses in the long run.';
420-
} else if (gameState.yourScore < gameState.theirScore - 5) {
421-
conclusion = '😔 <strong>You lost because you trusted too much.</strong> But collaboration works best when both parties are committed to mutual benefit.';
422-
} else if (gameState.yourScore > gameState.theirScore) {
423-
conclusion = '⚡ <strong>You slightly won!</strong> Your strategy had moments of success, but the key insight: if both had collaborated, you\'d both have higher scores.';
424-
} else if (gameState.yourScore < gameState.theirScore) {
425-
conclusion = '🤔 <strong>They slightly won.</strong> This shows the reality of the prisoner\'s dilemma: individual incentives vs. collective benefit.';
426-
} else {
427-
conclusion = '🤝 <strong>It\'s a tie!</strong> Balanced strategies can lead to equal outcomes, but maximum mutual benefit comes from cooperation.';
428-
}
429-
430-
document.getElementById('conclusion-text').innerHTML = conclusion;
431-
showScreen(gameContainer.results);
432-
}
433-
434-
// Event Listeners
435-
document.getElementById('start-zero-sum').addEventListener('click', () => startGame('zero-sum'));
436-
document.getElementById('start-positive-sum').addEventListener('click', () => startGame('positive-sum'));
437-
438-
document.getElementById('choice-compete').addEventListener('click', () => processRound('compete'));
439-
document.getElementById('choice-collab').addEventListener('click', () => processRound('collab'));
440-
441-
document.getElementById('next-round-btn').addEventListener('click', () => {
442-
if (gameState.round < 3) {
443-
gameState.round++;
444-
updateScoreDisplay();
445-
gameContainer.choicePhase.style.display = 'block';
446-
gameContainer.resultPhase.style.display = 'none';
447-
} else {
448-
endGame();
449-
}
450-
});
451-
452-
document.getElementById('play-again-btn').addEventListener('click', () => {
453-
showScreen(gameContainer.start);
454-
});
455-
</script>
456-
457307
<div class="card video-card">
458308
<div class="video-header">
459309
<span class="video-badge">🎬 Video</span>
@@ -923,6 +773,7 @@ <h3 class="team-member-name">Social Economics Lab</h3>
923773
</footer>
924774

925775
<script src="./lib/data/mockDataViz.js"></script>
776+
<script src="./lib/game.js"></script>
926777
<script src="./app.js"></script>
927778
</body>
928779
</html>

lib/game.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Game containers and state
2+
const gameContainer = {
3+
start: document.getElementById('game-start'),
4+
playing: document.getElementById('game-playing'),
5+
results: document.getElementById('game-results'),
6+
choicePhase: document.getElementById('choice-phase'),
7+
resultPhase: document.getElementById('result-phase')
8+
};
9+
10+
let gameState = {
11+
mode: null,
12+
round: 1,
13+
yourScore: 0,
14+
theirScore: 0,
15+
yourMove: null,
16+
theirMove: null,
17+
history: []
18+
};
19+
20+
const gamePayoff = {
21+
zeroSum: {
22+
cc: { you: 3, them: 3 },
23+
cd: { you: 6, them: 0 },
24+
dc: { you: 0, them: 6 },
25+
dd: { you: 1, them: 1 }
26+
},
27+
positiveSum: {
28+
cc: { you: 6, them: 6 },
29+
cd: { you: 4, them: 8 },
30+
dc: { you: 8, them: 4 },
31+
dd: { you: 2, them: 2 }
32+
}
33+
};
34+
35+
function showScreen(screen) {
36+
gameContainer.start.style.display = 'none';
37+
gameContainer.playing.style.display = 'none';
38+
gameContainer.results.style.display = 'none';
39+
screen.style.display = 'block';
40+
}
41+
42+
function startGame(mode) {
43+
gameState = {
44+
mode: mode,
45+
round: 1,
46+
yourScore: 0,
47+
theirScore: 0,
48+
yourMove: null,
49+
theirMove: null,
50+
history: []
51+
};
52+
showScreen(gameContainer.playing);
53+
gameContainer.resultPhase.style.display = 'none';
54+
gameContainer.choicePhase.style.display = 'block';
55+
updateScoreDisplay();
56+
}
57+
58+
function updateScoreDisplay() {
59+
document.getElementById('round-number').textContent = gameState.round;
60+
document.getElementById('your-score').textContent = gameState.yourScore;
61+
document.getElementById('their-score').textContent = gameState.theirScore;
62+
}
63+
64+
function getOpponentMove(yourMove) {
65+
if (gameState.mode === 'zero-sum') {
66+
return Math.random() > 0.3 ? 'compete' : 'collab';
67+
} else {
68+
return Math.random() > 0.2 ? 'collab' : 'compete';
69+
}
70+
}
71+
72+
function processRound(yourMove) {
73+
gameState.yourMove = yourMove;
74+
gameState.theirMove = getOpponentMove(yourMove);
75+
76+
const payoffSet = gameState.mode === 'zero-sum' ? gamePayoff.zeroSum : gamePayoff.positiveSum;
77+
const key = (yourMove === 'compete' ? 'c' : 'd') + (gameState.theirMove === 'compete' ? 'c' : 'd');
78+
const payoff = payoffSet[key];
79+
80+
gameState.yourScore += payoff.you;
81+
gameState.theirScore += payoff.them;
82+
gameState.history.push({ your: yourMove, their: gameState.theirMove, payoff });
83+
84+
// Display results
85+
document.getElementById('your-move-display').textContent = yourMove === 'compete' ? '⚔️ Compete' : '🤝 Collaborate';
86+
document.getElementById('their-move-display').textContent = gameState.theirMove === 'compete' ? '⚔️ Compete' : '🤝 Collaborate';
87+
document.getElementById('round-your-gain').textContent = '+' + payoff.you;
88+
document.getElementById('round-their-gain').textContent = '+' + payoff.them;
89+
90+
let insight = '';
91+
if (yourMove === 'compete' && gameState.theirMove === 'compete') {
92+
insight = '⚔️ Both competed! The market shrinks. Low gains for both.';
93+
} else if (yourMove === 'collab' && gameState.theirMove === 'collab') {
94+
insight = '🤝 Both collaborated! The market grows. High gains for everyone.';
95+
} else if (yourMove === 'compete' && gameState.theirMove === 'collab') {
96+
insight = '😱 You exploited their trust. You won this round, but trust is broken.';
97+
} else {
98+
insight = '😢 They exploited your trust. Your collaborative approach backfired.';
99+
}
100+
document.getElementById('round-insight').innerHTML = '<strong style="color: #f97316;">💡</strong> ' + insight;
101+
102+
updateScoreDisplay();
103+
gameContainer.choicePhase.style.display = 'none';
104+
gameContainer.resultPhase.style.display = 'block';
105+
}
106+
107+
function endGame() {
108+
document.getElementById('final-your-score').textContent = gameState.yourScore;
109+
document.getElementById('final-their-score').textContent = gameState.theirScore;
110+
111+
let conclusion = '';
112+
if (gameState.yourScore > gameState.theirScore + 5) {
113+
conclusion = '🏆 <strong>You won through competition!</strong> But this mindset often leads to mutual destruction in real situations. In zero-sum thinking, everyone loses in the long run.';
114+
} else if (gameState.yourScore < gameState.theirScore - 5) {
115+
conclusion = '😔 <strong>You lost because you trusted too much.</strong> But collaboration works best when both parties are committed to mutual benefit.';
116+
} else if (gameState.yourScore > gameState.theirScore) {
117+
conclusion = '⚡ <strong>You slightly won!</strong> Your strategy had moments of success, but the key insight: if both had collaborated, you\'d both have higher scores.';
118+
} else if (gameState.yourScore < gameState.theirScore) {
119+
conclusion = '🤔 <strong>They slightly won.</strong> This shows the reality of the prisoner\'s dilemma: individual incentives vs. collective benefit.';
120+
} else {
121+
conclusion = '🤝 <strong>It\'s a tie!</strong> Balanced strategies can lead to equal outcomes, but maximum mutual benefit comes from cooperation.';
122+
}
123+
124+
document.getElementById('conclusion-text').innerHTML = conclusion;
125+
showScreen(gameContainer.results);
126+
}
127+
128+
// Event Listeners
129+
document.addEventListener('DOMContentLoaded', function() {
130+
document.getElementById('start-zero-sum').addEventListener('click', () => startGame('zero-sum'));
131+
document.getElementById('start-positive-sum').addEventListener('click', () => startGame('positive-sum'));
132+
133+
document.getElementById('choice-compete').addEventListener('click', () => processRound('compete'));
134+
document.getElementById('choice-collab').addEventListener('click', () => processRound('collab'));
135+
136+
document.getElementById('next-round-btn').addEventListener('click', () => {
137+
if (gameState.round < 3) {
138+
gameState.round++;
139+
updateScoreDisplay();
140+
gameContainer.choicePhase.style.display = 'block';
141+
gameContainer.resultPhase.style.display = 'none';
142+
} else {
143+
endGame();
144+
}
145+
});
146+
147+
document.getElementById('play-again-btn').addEventListener('click', () => {
148+
showScreen(gameContainer.start);
149+
});
150+
});

0 commit comments

Comments
 (0)