| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>Pattern Sprint Interview Game</title> |
| <style> |
| :root { |
| --navy: #071833; |
| --blue: #2563eb; |
| --green: #16a34a; |
| --red: #dc2626; |
| --yellow: #facc15; |
| --purple: #7c3aed; |
| --orange: #f97316; |
| --gray: #f3f4f6; |
| --dark-gray: #374151; |
| --white: #ffffff; |
| --border: #d1d5db; |
| } |
| |
| * { |
| box-sizing: border-box; |
| } |
| |
| body { |
| margin: 0; |
| min-height: 100vh; |
| font-family: Arial, Helvetica, sans-serif; |
| background: linear-gradient(135deg, #eef2ff, #f8fafc); |
| color: var(--navy); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| padding: 24px; |
| } |
| |
| .app { |
| width: min(1100px, 100%); |
| background: var(--white); |
| border: 2px solid #e5e7eb; |
| border-radius: 22px; |
| box-shadow: 0 20px 50px rgba(7, 24, 51, 0.15); |
| overflow: hidden; |
| } |
| |
| header { |
| background: var(--navy); |
| color: var(--white); |
| padding: 24px 28px; |
| } |
| |
| header h1 { |
| margin: 0; |
| font-size: clamp(28px, 4vw, 44px); |
| letter-spacing: -1px; |
| } |
| |
| header p { |
| margin: 8px 0 0; |
| font-size: 17px; |
| opacity: 0.9; |
| } |
| |
| .main { |
| display: grid; |
| grid-template-columns: 1.4fr 0.9fr; |
| gap: 20px; |
| padding: 24px; |
| } |
| |
| .panel { |
| border: 2px solid #e5e7eb; |
| border-radius: 18px; |
| background: #ffffff; |
| padding: 22px; |
| } |
| |
| .game-area { |
| min-height: 520px; |
| display: flex; |
| flex-direction: column; |
| justify-content: space-between; |
| } |
| |
| .status-row { |
| display: grid; |
| grid-template-columns: repeat(4, 1fr); |
| gap: 12px; |
| margin-bottom: 18px; |
| } |
| |
| .stat { |
| background: var(--gray); |
| border-radius: 14px; |
| padding: 14px; |
| text-align: center; |
| border: 1px solid #e5e7eb; |
| } |
| |
| .stat .label { |
| font-size: 13px; |
| color: var(--dark-gray); |
| margin-bottom: 4px; |
| } |
| |
| .stat .value { |
| font-size: 24px; |
| font-weight: 800; |
| } |
| |
| .screen { |
| flex: 1; |
| border: 3px dashed #c7d2fe; |
| border-radius: 18px; |
| background: #f8fafc; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| text-align: center; |
| padding: 28px; |
| margin-bottom: 18px; |
| min-height: 260px; |
| } |
| |
| .screen h2 { |
| font-size: clamp(28px, 4vw, 44px); |
| margin: 0 0 12px; |
| } |
| |
| .screen p { |
| font-size: 18px; |
| line-height: 1.45; |
| margin: 8px 0; |
| } |
| |
| .sequence-display { |
| display: flex; |
| flex-wrap: wrap; |
| justify-content: center; |
| gap: 14px; |
| margin: 20px 0; |
| } |
| |
| .tile { |
| width: 78px; |
| height: 78px; |
| border-radius: 18px; |
| display: grid; |
| place-items: center; |
| font-weight: 900; |
| font-size: 22px; |
| color: white; |
| box-shadow: 0 12px 20px rgba(0, 0, 0, 0.18); |
| border: 3px solid rgba(255, 255, 255, 0.7); |
| user-select: none; |
| } |
| |
| .tile.small { |
| width: 56px; |
| height: 56px; |
| border-radius: 14px; |
| font-size: 17px; |
| cursor: pointer; |
| transition: transform 0.15s, box-shadow 0.15s; |
| } |
| |
| .tile.small:hover { |
| transform: translateY(-3px); |
| box-shadow: 0 16px 24px rgba(0, 0, 0, 0.2); |
| } |
| |
| .Blue { background: var(--blue); } |
| .Green { background: var(--green); } |
| .Red { background: var(--red); } |
| .Yellow { background: #ca8a04; } |
| .Purple { background: var(--purple); } |
| .Orange { background: var(--orange); } |
| |
| .choice-grid { |
| display: grid; |
| grid-template-columns: 1fr 1fr; |
| gap: 12px; |
| width: 100%; |
| max-width: 720px; |
| margin: 0 auto; |
| } |
| |
| .choice { |
| background: white; |
| border: 2px solid var(--border); |
| border-radius: 16px; |
| padding: 14px; |
| cursor: pointer; |
| transition: all 0.15s ease; |
| text-align: left; |
| font-weight: 700; |
| } |
| |
| .choice:hover { |
| border-color: var(--blue); |
| transform: translateY(-2px); |
| box-shadow: 0 10px 18px rgba(37, 99, 235, 0.12); |
| } |
| |
| .choice.correct { |
| border-color: var(--green); |
| background: #ecfdf5; |
| } |
| |
| .choice.wrong { |
| border-color: var(--red); |
| background: #fef2f2; |
| } |
| |
| .button-row { |
| display: flex; |
| flex-wrap: wrap; |
| gap: 12px; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| button { |
| border: none; |
| border-radius: 14px; |
| padding: 14px 20px; |
| font-size: 16px; |
| font-weight: 800; |
| cursor: pointer; |
| transition: transform 0.15s, opacity 0.15s; |
| } |
| |
| button:hover { |
| transform: translateY(-2px); |
| } |
| |
| button:disabled { |
| opacity: 0.5; |
| cursor: not-allowed; |
| transform: none; |
| } |
| |
| .primary { |
| background: var(--blue); |
| color: white; |
| } |
| |
| .secondary { |
| background: #e5e7eb; |
| color: var(--navy); |
| } |
| |
| .danger { |
| background: var(--red); |
| color: white; |
| } |
| |
| .side h2 { |
| margin: 0 0 12px; |
| font-size: 26px; |
| } |
| |
| .side-section { |
| margin-bottom: 22px; |
| padding-bottom: 18px; |
| border-bottom: 1px solid #e5e7eb; |
| } |
| |
| .side-section:last-child { |
| border-bottom: none; |
| margin-bottom: 0; |
| padding-bottom: 0; |
| } |
| |
| .meter-wrap { |
| margin: 12px 0; |
| } |
| |
| .meter-label { |
| display: flex; |
| justify-content: space-between; |
| font-weight: 700; |
| margin-bottom: 6px; |
| font-size: 14px; |
| } |
| |
| .meter { |
| height: 12px; |
| background: #e5e7eb; |
| border-radius: 999px; |
| overflow: hidden; |
| } |
| |
| .meter-fill { |
| height: 100%; |
| width: 0%; |
| background: var(--blue); |
| transition: width 0.4s ease; |
| } |
| |
| .history { |
| max-height: 210px; |
| overflow-y: auto; |
| padding-right: 6px; |
| } |
| |
| .history-item { |
| background: #f9fafb; |
| border: 1px solid #e5e7eb; |
| border-radius: 12px; |
| padding: 10px; |
| margin-bottom: 8px; |
| font-size: 14px; |
| } |
| |
| .feedback { |
| font-size: 20px; |
| font-weight: 900; |
| min-height: 30px; |
| text-align: center; |
| margin: 8px 0 14px; |
| } |
| |
| .good { color: var(--green); } |
| .bad { color: var(--red); } |
| .neutral { color: var(--dark-gray); } |
| |
| .report { |
| text-align: left; |
| max-width: 760px; |
| margin: 0 auto; |
| } |
| |
| .report h2 { |
| text-align: center; |
| } |
| |
| .report-card { |
| background: white; |
| border: 2px solid #e5e7eb; |
| border-radius: 16px; |
| padding: 16px; |
| margin: 12px 0; |
| } |
| |
| .report-card strong { |
| color: var(--navy); |
| } |
| |
| .hidden { |
| display: none !important; |
| } |
| |
| @media (max-width: 850px) { |
| .main { |
| grid-template-columns: 1fr; |
| } |
| |
| .status-row { |
| grid-template-columns: 1fr 1fr; |
| } |
| |
| .choice-grid { |
| grid-template-columns: 1fr; |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <div class="app"> |
| <header> |
| <h1>Pattern Sprint</h1> |
| <p>A gamified interview assessment for memory, attention, speed, and learning improvement.</p> |
| </header> |
|
|
| <main class="main"> |
| <section class="panel game-area"> |
| <div> |
| <div class="status-row"> |
| <div class="stat"> |
| <div class="label">Round</div> |
| <div class="value" id="roundValue">0/8</div> |
| </div> |
| <div class="stat"> |
| <div class="label">Score</div> |
| <div class="value" id="scoreValue">0</div> |
| </div> |
| <div class="stat"> |
| <div class="label">Accuracy</div> |
| <div class="value" id="accuracyValue">0%</div> |
| </div> |
| <div class="stat"> |
| <div class="label">Timer</div> |
| <div class="value" id="timerValue">--</div> |
| </div> |
| </div> |
|
|
| <div class="screen" id="screen"> |
| <div> |
| <h2>Ready?</h2> |
| <p>You will see a short color pattern. Memorize it before it disappears.</p> |
| <p>Then choose the matching sequence as quickly and accurately as possible.</p> |
| </div> |
| </div> |
|
|
| <div class="feedback neutral" id="feedback">Press Start to begin.</div> |
| </div> |
|
|
| <div class="button-row"> |
| <button class="primary" id="startBtn">Start Game</button> |
| <button class="secondary" id="nextBtn" disabled>Next Round</button> |
| <button class="danger" id="resetBtn">Reset</button> |
| </div> |
| </section> |
|
|
| <aside class="panel side"> |
| <div class="side-section"> |
| <h2>Assessment Signals</h2> |
| <div class="meter-wrap"> |
| <div class="meter-label"><span>Working Memory</span><span id="memoryScore">0%</span></div> |
| <div class="meter"><div class="meter-fill" id="memoryFill"></div></div> |
| </div> |
| <div class="meter-wrap"> |
| <div class="meter-label"><span>Attention</span><span id="attentionScore">0%</span></div> |
| <div class="meter"><div class="meter-fill" id="attentionFill"></div></div> |
| </div> |
| <div class="meter-wrap"> |
| <div class="meter-label"><span>Speed</span><span id="speedScore">0%</span></div> |
| <div class="meter"><div class="meter-fill" id="speedFill"></div></div> |
| </div> |
| <div class="meter-wrap"> |
| <div class="meter-label"><span>Learning Trend</span><span id="learningScore">0%</span></div> |
| <div class="meter"><div class="meter-fill" id="learningFill"></div></div> |
| </div> |
| </div> |
|
|
| <div class="side-section"> |
| <h2>Game Rules</h2> |
| <p><strong>1.</strong> Watch the sequence.</p> |
| <p><strong>2.</strong> Remember the order.</p> |
| <p><strong>3.</strong> Pick the correct answer.</p> |
| <p><strong>4.</strong> Later rounds get harder.</p> |
| </div> |
|
|
| <div class="side-section"> |
| <h2>Round History</h2> |
| <div class="history" id="history"></div> |
| </div> |
| </aside> |
| </main> |
| </div> |
|
|
| <script> |
| const COLORS = ["Blue", "Green", "Red", "Yellow", "Purple", "Orange"]; |
| const TOTAL_ROUNDS = 8; |
| |
| const state = { |
| round: 0, |
| score: 0, |
| correct: 0, |
| attempts: 0, |
| currentSequence: [], |
| roundStartTime: null, |
| timerInterval: null, |
| responseTimes: [], |
| history: [], |
| acceptingAnswer: false |
| }; |
| |
| const els = { |
| screen: document.getElementById("screen"), |
| feedback: document.getElementById("feedback"), |
| roundValue: document.getElementById("roundValue"), |
| scoreValue: document.getElementById("scoreValue"), |
| accuracyValue: document.getElementById("accuracyValue"), |
| timerValue: document.getElementById("timerValue"), |
| startBtn: document.getElementById("startBtn"), |
| nextBtn: document.getElementById("nextBtn"), |
| resetBtn: document.getElementById("resetBtn"), |
| history: document.getElementById("history"), |
| memoryScore: document.getElementById("memoryScore"), |
| attentionScore: document.getElementById("attentionScore"), |
| speedScore: document.getElementById("speedScore"), |
| learningScore: document.getElementById("learningScore"), |
| memoryFill: document.getElementById("memoryFill"), |
| attentionFill: document.getElementById("attentionFill"), |
| speedFill: document.getElementById("speedFill"), |
| learningFill: document.getElementById("learningFill") |
| }; |
| |
| function randomItem(arr) { |
| return arr[Math.floor(Math.random() * arr.length)]; |
| } |
| |
| function createSequence(length) { |
| const seq = []; |
| for (let i = 0; i < length; i++) { |
| seq.push(randomItem(COLORS)); |
| } |
| return seq; |
| } |
| |
| function sequenceToText(seq) { |
| return seq.join(" → "); |
| } |
| |
| function makeTile(color, small = false) { |
| const div = document.createElement("div"); |
| div.className = `tile ${small ? "small" : ""} ${color}`; |
| div.textContent = color[0]; |
| div.title = color; |
| return div; |
| } |
| |
| function renderSequence(seq, small = false) { |
| const wrapper = document.createElement("div"); |
| wrapper.className = "sequence-display"; |
| seq.forEach(color => wrapper.appendChild(makeTile(color, small))); |
| return wrapper; |
| } |
| |
| function shuffle(array) { |
| const copy = [...array]; |
| for (let i = copy.length - 1; i > 0; i--) { |
| const j = Math.floor(Math.random() * (i + 1)); |
| [copy[i], copy[j]] = [copy[j], copy[i]]; |
| } |
| return copy; |
| } |
| |
| function mutateSequence(seq) { |
| const mutated = [...seq]; |
| const mutationType = Math.floor(Math.random() * 3); |
| |
| if (mutationType === 0 && mutated.length > 1) { |
| const i = Math.floor(Math.random() * mutated.length); |
| let j = Math.floor(Math.random() * mutated.length); |
| while (j === i) j = Math.floor(Math.random() * mutated.length); |
| [mutated[i], mutated[j]] = [mutated[j], mutated[i]]; |
| } else if (mutationType === 1) { |
| const i = Math.floor(Math.random() * mutated.length); |
| let newColor = randomItem(COLORS); |
| while (newColor === mutated[i]) newColor = randomItem(COLORS); |
| mutated[i] = newColor; |
| } else { |
| mutated.reverse(); |
| } |
| |
| return mutated; |
| } |
| |
| function createChoices(correctSeq) { |
| const choices = [correctSeq]; |
| const seen = new Set([sequenceToText(correctSeq)]); |
| |
| while (choices.length < 4) { |
| const mutated = mutateSequence(correctSeq); |
| const key = sequenceToText(mutated); |
| if (!seen.has(key)) { |
| choices.push(mutated); |
| seen.add(key); |
| } |
| } |
| |
| return shuffle(choices); |
| } |
| |
| function setFeedback(text, type = "neutral") { |
| els.feedback.textContent = text; |
| els.feedback.className = `feedback ${type}`; |
| } |
| |
| function updateStats() { |
| const accuracy = state.attempts ? Math.round((state.correct / state.attempts) * 100) : 0; |
| els.roundValue.textContent = `${state.round}/${TOTAL_ROUNDS}`; |
| els.scoreValue.textContent = state.score; |
| els.accuracyValue.textContent = `${accuracy}%`; |
| |
| const memory = accuracy; |
| const attention = calculateAttentionScore(); |
| const speed = calculateSpeedScore(); |
| const learning = calculateLearningTrend(); |
| |
| updateMeter("memory", memory); |
| updateMeter("attention", attention); |
| updateMeter("speed", speed); |
| updateMeter("learning", learning); |
| } |
| |
| function updateMeter(name, value) { |
| const clamped = Math.max(0, Math.min(100, Math.round(value))); |
| els[`${name}Score`].textContent = `${clamped}%`; |
| els[`${name}Fill`].style.width = `${clamped}%`; |
| } |
| |
| function calculateAttentionScore() { |
| if (state.history.length === 0) return 0; |
| const harderRounds = state.history.filter(item => item.length >= 5); |
| if (harderRounds.length === 0) return Math.round((state.correct / Math.max(1, state.attempts)) * 100); |
| const correctHard = harderRounds.filter(item => item.correct).length; |
| return (correctHard / harderRounds.length) * 100; |
| } |
| |
| function calculateSpeedScore() { |
| if (state.responseTimes.length === 0) return 0; |
| const avg = state.responseTimes.reduce((a, b) => a + b, 0) / state.responseTimes.length; |
| return Math.max(0, Math.min(100, 100 - (avg - 1.5) * 18)); |
| } |
| |
| function calculateLearningTrend() { |
| if (state.history.length < 4) return 0; |
| const midpoint = Math.floor(state.history.length / 2); |
| const firstHalf = state.history.slice(0, midpoint); |
| const secondHalf = state.history.slice(midpoint); |
| const firstAccuracy = firstHalf.filter(x => x.correct).length / firstHalf.length; |
| const secondAccuracy = secondHalf.filter(x => x.correct).length / secondHalf.length; |
| const improvement = secondAccuracy - firstAccuracy; |
| return Math.max(0, Math.min(100, 50 + improvement * 100)); |
| } |
| |
| function updateHistory() { |
| els.history.innerHTML = ""; |
| state.history.slice().reverse().forEach(item => { |
| const div = document.createElement("div"); |
| div.className = "history-item"; |
| div.innerHTML = ` |
| <strong>Round ${item.round}</strong> - ${item.correct ? "Correct" : "Incorrect"}<br> |
| Length: ${item.length} | Time: ${item.time.toFixed(2)}s | Points: ${item.points} |
| `; |
| els.history.appendChild(div); |
| }); |
| } |
| |
| function startTimer() { |
| state.roundStartTime = performance.now(); |
| els.timerValue.textContent = "0.0"; |
| clearInterval(state.timerInterval); |
| state.timerInterval = setInterval(() => { |
| const seconds = (performance.now() - state.roundStartTime) / 1000; |
| els.timerValue.textContent = seconds.toFixed(1); |
| }, 100); |
| } |
| |
| function stopTimer() { |
| clearInterval(state.timerInterval); |
| const seconds = (performance.now() - state.roundStartTime) / 1000; |
| els.timerValue.textContent = seconds.toFixed(1); |
| return seconds; |
| } |
| |
| function startGame() { |
| resetGame(false); |
| els.startBtn.disabled = true; |
| els.nextBtn.disabled = true; |
| nextRound(); |
| } |
| |
| function nextRound() { |
| if (state.round >= TOTAL_ROUNDS) { |
| showReport(); |
| return; |
| } |
| |
| state.round += 1; |
| state.acceptingAnswer = false; |
| els.nextBtn.disabled = true; |
| setFeedback("Memorize the pattern...", "neutral"); |
| updateStats(); |
| |
| const length = Math.min(3 + Math.floor((state.round - 1) / 2), 7); |
| state.currentSequence = createSequence(length); |
| |
| els.screen.innerHTML = ""; |
| const content = document.createElement("div"); |
| content.innerHTML = `<h2>Round ${state.round}</h2><p>Watch carefully.</p>`; |
| content.appendChild(renderSequence(state.currentSequence)); |
| els.screen.appendChild(content); |
| |
| const displayTime = Math.max(1300, 2600 - state.round * 120); |
| setTimeout(showChoices, displayTime); |
| } |
| |
| function showChoices() { |
| state.acceptingAnswer = true; |
| setFeedback("Choose the exact matching sequence.", "neutral"); |
| startTimer(); |
| |
| const choices = createChoices(state.currentSequence); |
| els.screen.innerHTML = ""; |
| |
| const content = document.createElement("div"); |
| content.style.width = "100%"; |
| content.innerHTML = `<h2>Select the Match</h2><p>The original pattern is hidden.</p>`; |
| |
| const grid = document.createElement("div"); |
| grid.className = "choice-grid"; |
| |
| choices.forEach((choiceSeq, index) => { |
| const button = document.createElement("button"); |
| button.className = "choice"; |
| button.setAttribute("aria-label", `Choice ${index + 1}: ${sequenceToText(choiceSeq)}`); |
| button.innerHTML = `<div style="margin-bottom: 8px;">Choice ${index + 1}</div><div>${sequenceToText(choiceSeq)}</div>`; |
| button.addEventListener("click", () => handleAnswer(button, choiceSeq)); |
| grid.appendChild(button); |
| }); |
| |
| content.appendChild(grid); |
| els.screen.appendChild(content); |
| } |
| |
| function handleAnswer(button, selectedSeq) { |
| if (!state.acceptingAnswer) return; |
| state.acceptingAnswer = false; |
| |
| const responseTime = stopTimer(); |
| const isCorrect = sequenceToText(selectedSeq) === sequenceToText(state.currentSequence); |
| const sequenceLength = state.currentSequence.length; |
| const speedBonus = Math.max(0, Math.round(30 - responseTime * 4)); |
| const points = isCorrect ? sequenceLength * 20 + speedBonus : 0; |
| |
| state.attempts += 1; |
| state.responseTimes.push(responseTime); |
| if (isCorrect) { |
| state.correct += 1; |
| state.score += points; |
| button.classList.add("correct"); |
| setFeedback(`Correct! +${points} points`, "good"); |
| } else { |
| button.classList.add("wrong"); |
| setFeedback("Not quite. Review the correct pattern below.", "bad"); |
| } |
| |
| document.querySelectorAll(".choice").forEach(choice => { |
| if (choice.textContent.includes(sequenceToText(state.currentSequence))) { |
| choice.classList.add("correct"); |
| } |
| choice.disabled = true; |
| }); |
| |
| state.history.push({ |
| round: state.round, |
| correct: isCorrect, |
| length: sequenceLength, |
| time: responseTime, |
| points |
| }); |
| |
| updateStats(); |
| updateHistory(); |
| showCorrectPattern(); |
| |
| if (state.round >= TOTAL_ROUNDS) { |
| els.nextBtn.textContent = "View Report"; |
| } else { |
| els.nextBtn.textContent = "Next Round"; |
| } |
| els.nextBtn.disabled = false; |
| } |
| |
| function showCorrectPattern() { |
| const existing = els.screen.querySelector(".correct-pattern"); |
| if (existing) existing.remove(); |
| |
| const div = document.createElement("div"); |
| div.className = "correct-pattern"; |
| div.style.marginTop = "18px"; |
| div.innerHTML = `<p><strong>Correct pattern:</strong> ${sequenceToText(state.currentSequence)}</p>`; |
| els.screen.firstElementChild.appendChild(div); |
| } |
| |
| function showReport() { |
| clearInterval(state.timerInterval); |
| els.startBtn.disabled = false; |
| els.nextBtn.disabled = true; |
| els.nextBtn.textContent = "Next Round"; |
| |
| const accuracy = state.attempts ? Math.round((state.correct / state.attempts) * 100) : 0; |
| const avgTime = state.responseTimes.length |
| ? state.responseTimes.reduce((a, b) => a + b, 0) / state.responseTimes.length |
| : 0; |
| |
| const memory = accuracy; |
| const attention = Math.round(calculateAttentionScore()); |
| const speed = Math.round(calculateSpeedScore()); |
| const learning = Math.round(calculateLearningTrend()); |
| |
| let recommendation = "Balanced performance. Use this as one signal, not a final hiring decision."; |
| if (memory >= 80 && speed >= 70) recommendation = "Strong pattern recognition and fast decision-making under time pressure."; |
| if (memory < 60 && learning >= 60) recommendation = "Early misses improved over time, suggesting coachability and learning adaptation."; |
| if (memory < 50) recommendation = "May need additional job-relevant assessment before drawing conclusions."; |
| |
| els.screen.innerHTML = ` |
| <div class="report"> |
| <h2>Candidate Assessment Report</h2> |
| <div class="report-card"><strong>Total Score:</strong> ${state.score}</div> |
| <div class="report-card"><strong>Accuracy:</strong> ${accuracy}% (${state.correct}/${state.attempts} correct)</div> |
| <div class="report-card"><strong>Average Response Time:</strong> ${avgTime.toFixed(2)} seconds</div> |
| <div class="report-card"><strong>Working Memory:</strong> ${memory}%</div> |
| <div class="report-card"><strong>Attention Under Difficulty:</strong> ${attention}%</div> |
| <div class="report-card"><strong>Decision Speed:</strong> ${speed}%</div> |
| <div class="report-card"><strong>Learning Trend:</strong> ${learning}%</div> |
| <div class="report-card"><strong>Interpretation:</strong> ${recommendation}</div> |
| <div class="report-card"><strong>Fairness Note:</strong> This game should only support hiring decisions when combined with human review, job-relevant tasks, accessibility options, and bias monitoring.</div> |
| </div> |
| `; |
| |
| setFeedback("Game complete. Review the assessment report.", "good"); |
| updateStats(); |
| } |
| |
| function resetGame(showStartScreen = true) { |
| clearInterval(state.timerInterval); |
| state.round = 0; |
| state.score = 0; |
| state.correct = 0; |
| state.attempts = 0; |
| state.currentSequence = []; |
| state.roundStartTime = null; |
| state.responseTimes = []; |
| state.history = []; |
| state.acceptingAnswer = false; |
| |
| els.startBtn.disabled = false; |
| els.nextBtn.disabled = true; |
| els.nextBtn.textContent = "Next Round"; |
| els.timerValue.textContent = "--"; |
| els.history.innerHTML = ""; |
| |
| if (showStartScreen) { |
| els.screen.innerHTML = ` |
| <div> |
| <h2>Ready?</h2> |
| <p>You will see a short color pattern. Memorize it before it disappears.</p> |
| <p>Then choose the matching sequence as quickly and accurately as possible.</p> |
| </div> |
| `; |
| setFeedback("Press Start to begin.", "neutral"); |
| } |
| |
| updateStats(); |
| } |
| |
| els.startBtn.addEventListener("click", startGame); |
| els.nextBtn.addEventListener("click", nextRound); |
| els.resetBtn.addEventListener("click", () => resetGame(true)); |
| |
| resetGame(true); |
| </script> |
| </body> |
| </html> |