CS206_Game / index.html
Peterhe123's picture
Deploy sunk cost game (update space)
d57a1a6 verified
Raw History Blame Contribute Delete
10.9 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#071b45" />
<meta name="description" content="A free static classroom Sunk Cost game for COMSCI/ECON 206." />
<title>Sunk Cost Game · COMSCI/ECON 206</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- ============ TOP BAR ============ -->
<header class="topbar">
<div class="brand">
<span class="brand-emoji" aria-hidden="true">🪙</span>
<span class="brand-name">COMSCI/ECON 206</span>
<span class="brand-sub">Computational Microeconomics</span>
</div>
<nav class="steps" aria-label="Game steps">
<button class="step is-active" data-step="1">1&nbsp;Inquiry</button>
<button class="step" data-step="2">2&nbsp;Decision</button>
<button class="step" data-step="3">3&nbsp;Reveal</button>
<button class="step" data-step="4">4&nbsp;Reflect</button>
</nav>
</header>
<main class="shell">
<!-- ============ STEP 1 · INQUIRY / LANDING ============ -->
<section class="view" id="view-inquiry" data-view="1">
<div class="week-badge">Week 3 · Practice Laboratory</div>
<h1 class="hero-title">A wasted cost. <em>Two rational choices.</em></h1>
<p class="hero-sub">
If money is already gone and unrecoverable, what does a self-interest benchmark
predict — and what will people actually choose?
</p>
<div class="tag-row">
<span class="tag">Private by design · no server, login, or tracking</span>
</div>
<div class="scenario card">
<h2>The half-finished project</h2>
<p>
Your company has already spent <strong>$100,000</strong> on Project&nbsp;X, and it is now clearly
underperforming. Finishing it would cost another <strong>$50,000</strong>. The same $50,000 could instead
launch Project&nbsp;Y, whose expected returns are much higher.
</p>
<p class="muted">
You must allocate the remaining <strong>10 points</strong> (each = $5,000) between
“keep funding X” and “switch to Y.”
</p>
</div>
<div class="roles">
<article class="role-card" data-role="manager">
<div class="role-kicker">Role A</div>
<h3>Play the Manager</h3>
<p>You already paid the $100,000. You decide how to spend the next $50,000.</p>
<button class="btn" data-begin="manager">Begin decision →</button>
</article>
<article class="role-card" data-role="advisor">
<div class="role-kicker">Role B</div>
<h3>Play the Advisor</h3>
<p>Fresh eyes, no sunk cost. You see the same numbers and decide.</p>
<button class="btn" data-begin="advisor">Begin decision →</button>
</article>
</div>
<div class="benchmark card">
<h2>The self-interest benchmark</h2>
<p>
Because the $100,000 is gone either way, a strictly rational decider ignores it and
puts <strong>all 10 points into Project Y</strong> — <strong>0 into X</strong>. Sunk costs must not drive
tomorrow’s choices. Emotional attachment or loss aversion may produce a different observation.
</p>
</div>
</section>
<!-- ============ STEP 2 · DECISION ============ -->
<section class="view" id="view-decision" data-view="2" hidden>
<div class="week-badge">Step 2 · Decision</div>
<h1 class="hero-title small">Where does the next <em>$50,000</em> go?</h1>
<div class="card decision-card">
<div class="role-kicker" id="decision-role-kicker">Role A · Manager</div>
<h2 id="decision-role-title">Allocate the next $50,000</h2>
<p class="muted" id="decision-role-copy">
Drag the slider to split 10 points between continuing Project X and switching to Project Y.
</p>
<div class="slider-block">
<div class="slider-scale">
<span>Project X (continue)</span>
<span id="slider-x">5</span> · <span id="slider-y">5</span>
<span>Project Y (switch)</span>
</div>
<input type="range" id="sunk-slider" min="0" max="10" value="5" step="1" aria-label="Allocate points" />
<div class="slider-bars">
<div class="bar-x" id="bar-x"><span>X</span></div>
<div class="bar-y" id="bar-y"><span>Y</span></div>
</div>
<div class="money-readout">
<span id="money-x">$25,000 → X</span>
<span id="money-y">$25,000 → Y</span>
</div>
</div>
<div class="btn-row">
<button class="btn ghost" data-reset="reset">Reset</button>
<button class="btn" id="lock-decision">Lock decision →</button>
</div>
</div>
</section>
<!-- ============ STEP 3 · REVEAL ============ -->
<section class="view" id="view-reveal" data-view="3" hidden>
<div class="week-badge">Step 3 · Reveal</div>
<h1 class="hero-title small">What the benchmark <em>predicts</em></h1>
<div class="card reveal-card">
<div class="reveal-verdict" id="reveal-verdict"></div>
<p class="muted" id="reveal-text"></p>
<div class="reveal-compare">
<div>
<span class="role-kicker">Rational benchmark</span>
<p><strong>0 points → X</strong> · all 10 → Y</p>
<p class="muted">Sunk cost is ignored.</p>
</div>
<div>
<span class="role-kicker">Your choice</span>
<p><strong id="reveal-your-x">0 → X</strong> · <span id="reveal-your-y">10 → Y</span></p>
<p class="muted" id="reveal-your-verdict"></p>
</div>
</div>
</div>
<div class="btn-row">
<button class="btn" id="to-reflect">See the lesson →</button>
</div>
</section>
<!-- ============ STEP 4 · REFLECT ============ -->
<section class="view" id="view-reflect" data-view="4" hidden>
<div class="week-badge">Step 4 · Reflect</div>
<h1 class="hero-title small">The sunk cost <em>fallacy</em></h1>
<ol class="lessons card">
<li>
<strong>Only future costs and benefits matter.</strong> Money already spent is gone
whether you continue or stop — it should never tip the scale.
</li>
<li>
<strong>Decision-makers with sunk costs behave differently.</strong> The Manager (who paid)
is systematically more likely to keep funding X than the Advisor (who didn’t), even with
identical numbers.
</li>
<li>
<strong>Good decisions are made from the outside.</strong> Ask: “If I hadn’t already spent
the $100,000, would I still choose X?” If not, cut losses now.
</li>
</ol>
<div class="btn-row">
<button class="btn" id="restart">Play again ↺</button>
</div>
</section>
</main>
<footer class="foot">
COMSCI/ECON 206 · Autumn 2026 · Browser-only classroom demonstration · No centralized data collection
</footer>
<script>
(function () {
"use strict";
const ROLES = {
manager: {
kicker: "Role A · Manager",
title: "You already paid the $100,000",
copy: "You are emotionally invested. Drag the slider to split 10 points between continuing Project X and switching to Project Y."
},
advisor: {
kicker: "Role B · Advisor",
title: "Fresh eyes, no sunk cost",
copy: "You never paid the $100,000. You see the exact same numbers. Drag the slider to split 10 points between X and Y."
}
};
const slider = document.getElementById("sunk-slider");
const barX = document.getElementById("bar-x");
const barY = document.getElementById("bar-y");
const moneyX = document.getElementById("money-x");
const moneyY = document.getElementById("money-y");
let role = null;
let x = 5;
function showStep(n) {
document.querySelectorAll(".view").forEach(function (v) {
v.hidden = Number(v.dataset.view) !== n;
});
document.querySelectorAll(".step").forEach(function (s) {
s.classList.toggle("is-active", Number(s.dataset.step) === n);
});
window.scrollTo({ top: 0, behavior: "smooth" });
}
function renderSlider() {
x = Number(slider.value);
barX.style.width = (x * 10) + "%";
barY.style.width = ((10 - x) * 10) + "%";
moneyX.textContent = "$" + (x * 5000).toLocaleString() + " → X";
moneyY.textContent = "$" + ((10 - x) * 5000).toLocaleString() + " → Y";
}
function startDecision(which) {
role = which;
document.getElementById("decision-role-kicker").textContent = ROLES[which].kicker;
document.getElementById("decision-role-title").textContent = ROLES[which].title;
document.getElementById("decision-role-copy").textContent = ROLES[which].copy;
slider.value = 5;
renderSlider();
showStep(2);
}
function lockDecision() {
renderSlider();
const verdict =
x === 0
? "Perfectly rational — you ignored the sunk cost."
: x <= 3
? "Mostly rational — a little sunk-cost pull, but you switched."
: x <= 7
? "Strong sunk-cost pull — the spent $100,000 is dragging your decision."
: "Classic sunk-cost fallacy — the unrecoverable $100,000 decided for you.";
document.getElementById("reveal-verdict").textContent = verdict;
document.getElementById("reveal-text").innerHTML =
role === "manager"
? "You were the <strong>Manager</strong> who paid. Losing $100,000 already, people systematically throw good money after bad. Your choice shows exactly how the sunk cost bends the decision."
: "You were the <strong>Advisor</strong> with fresh eyes. With no sunk cost, the rational benchmark is far easier to reach — exactly why outsiders see it so clearly.";
document.getElementById("reveal-your-x").textContent = x + " → X";
document.getElementById("reveal-your-y").textContent = (10 - x) + " → Y";
document.getElementById("reveal-your-verdict").textContent =
x === 0 ? "Textbook rational." : "The sunk cost pulled you.";
showStep(3);
}
document.querySelectorAll("[data-begin]").forEach(function (b) {
b.addEventListener("click", function () {
startDecision(b.getAttribute("data-begin"));
});
});
document.querySelectorAll("[data-reset]").forEach(function (b) {
b.addEventListener("click", function () {
slider.value = 5;
renderSlider();
});
});
slider.addEventListener("input", renderSlider);
document.getElementById("lock-decision").addEventListener("click", lockDecision);
document.getElementById("to-reflect").addEventListener("click", function () {
showStep(4);
});
document.getElementById("restart").addEventListener("click", function () {
role = null;
slider.value = 5;
renderSlider();
showStep(1);
});
// Keyboard/Enter also works on the step buttons.
document.querySelectorAll(".step").forEach(function (s) {
s.addEventListener("click", function () {
// Free navigation between already-visited steps is allowed.
showStep(Number(s.dataset.step));
});
});
renderSlider();
})();
</script>
</body>
</html>