const STORAGE_KEY = "euchre-scoreboard"; const defaultState = () => ({ teamUsName: "Us", teamThemName: "Them", teamUsScore: 0, teamThemScore: 0, targetScore: 10, loneEnabled: true, history: [], gameOver: false, }); let state = loadState(); const els = { teamUsName: document.getElementById("teamUsName"), teamThemName: document.getElementById("teamThemName"), teamUsScore: document.getElementById("teamUsScore"), teamThemScore: document.getElementById("teamThemScore"), targetScore: document.getElementById("targetScore"), loneEnabled: document.getElementById("loneEnabled"), historyList: document.getElementById("historyList"), handCount: document.getElementById("handCount"), undoBtn: document.getElementById("undoBtn"), resetBtn: document.getElementById("resetBtn"), settingsBtn: document.getElementById("settingsBtn"), settingsPanel: document.getElementById("settingsPanel"), closeSettings: document.getElementById("closeSettings"), winnerOverlay: document.getElementById("winnerOverlay"), winnerText: document.getElementById("winnerText"), winnerScore: document.getElementById("winnerScore"), newGameBtn: document.getElementById("newGameBtn"), teamUsCard: document.getElementById("teamUsCard"), teamThemCard: document.getElementById("teamThemCard"), }; function loadState() { try { const saved = localStorage.getItem(STORAGE_KEY); if (saved) { return { ...defaultState(), ...JSON.parse(saved) }; } } catch { /* ignore corrupt storage */ } return defaultState(); } function saveState() { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } function teamLabel(team) { return team === "us" ? state.teamUsName : state.teamThemName; } function addScore(team, points, label) { if (state.gameOver) return; const entry = { team, points, label, teamUsScore: state.teamUsScore, teamThemScore: state.teamThemScore, timestamp: Date.now(), }; if (team === "us") { state.teamUsScore += points; } else { state.teamThemScore += points; } state.history.push(entry); checkWinner(); saveState(); render(); } function undoLast() { if (!state.history.length) return; const last = state.history.pop(); state.teamUsScore = last.teamUsScore; state.teamThemScore = last.teamThemScore; state.gameOver = false; saveState(); render(); } function resetGame(skipConfirm = false) { if ( !skipConfirm && state.history.length && !confirm("Start a new game? Current scores will be lost.") ) { return; } state = defaultState(); state.teamUsName = els.teamUsName.value.trim() || "Us"; state.teamThemName = els.teamThemName.value.trim() || "Them"; state.targetScore = Number(els.targetScore.value); state.loneEnabled = els.loneEnabled.checked; saveState(); render(); } function checkWinner() { const target = state.targetScore; state.gameOver = state.teamUsScore >= target || state.teamThemScore >= target; } function renderHistory() { const count = state.history.length; els.handCount.textContent = `${count} hand${count === 1 ? "" : "s"}`; if (!count) { els.historyList.innerHTML = '
  • No hands played yet
  • '; return; } els.historyList.innerHTML = state.history .slice() .reverse() .map((entry, i) => { const handNum = count - i; const name = teamLabel(entry.team); return `
  • #${handNum} — ${name}: ${entry.label} +${entry.points}
  • `; }) .join(""); } function renderWinner() { if (!state.gameOver) { els.winnerOverlay.hidden = true; els.teamUsCard.classList.remove("winner"); els.teamThemCard.classList.remove("winner"); return; } const usWins = state.teamUsScore >= state.targetScore; const winner = usWins ? state.teamUsName : state.teamThemName; const winnerScore = usWins ? state.teamUsScore : state.teamThemScore; const loserScore = usWins ? state.teamThemScore : state.teamUsScore; els.winnerText.textContent = `${winner} wins!`; els.winnerScore.textContent = `${winnerScore} – ${loserScore}`; els.winnerOverlay.hidden = false; if (usWins) { els.teamUsCard.classList.add("winner"); els.teamThemCard.classList.remove("winner"); } else { els.teamThemCard.classList.add("winner"); els.teamUsCard.classList.remove("winner"); } } function updateLoneButtons() { document.querySelectorAll(".lone-btn").forEach((btn) => { btn.classList.toggle("hidden", !state.loneEnabled); }); } function render() { els.teamUsName.value = state.teamUsName; els.teamThemName.value = state.teamThemName; els.teamUsScore.textContent = state.teamUsScore; els.teamThemScore.textContent = state.teamThemScore; els.targetScore.value = String(state.targetScore); els.loneEnabled.checked = state.loneEnabled; els.undoBtn.disabled = !state.history.length; updateLoneButtons(); renderHistory(); renderWinner(); document.querySelectorAll(".btn-score, .btn-euchre").forEach((btn) => { btn.disabled = state.gameOver; }); } document.querySelectorAll(".btn-score, .btn-euchre").forEach((btn) => { btn.addEventListener("click", () => { addScore(btn.dataset.team, Number(btn.dataset.points), btn.dataset.label); }); }); els.undoBtn.addEventListener("click", undoLast); els.resetBtn.addEventListener("click", resetGame); els.newGameBtn.addEventListener("click", () => resetGame(true)); els.settingsBtn.addEventListener("click", () => { els.settingsPanel.hidden = !els.settingsPanel.hidden; }); els.closeSettings.addEventListener("click", () => { state.targetScore = Number(els.targetScore.value); state.loneEnabled = els.loneEnabled.checked; saveState(); render(); els.settingsPanel.hidden = true; }); els.teamUsName.addEventListener("change", () => { state.teamUsName = els.teamUsName.value.trim() || "Us"; saveState(); renderHistory(); }); els.teamThemName.addEventListener("change", () => { state.teamThemName = els.teamThemName.value.trim() || "Them"; saveState(); renderHistory(); }); els.targetScore.addEventListener("change", () => { state.targetScore = Number(els.targetScore.value); checkWinner(); saveState(); render(); }); els.loneEnabled.addEventListener("change", () => { state.loneEnabled = els.loneEnabled.checked; saveState(); render(); }); checkWinner(); saveState(); render();