fix: implement prefix-conflict detection for speed memory quiz

- Add smart timeout logic to prevent accidental auto-acceptance of prefixes
- Detect when input number is prefix of other quiz numbers (e.g., 1 vs 18)
- Apply 500ms delay only for actual conflicts, preserve instant magic otherwise
- Add robust timeout management with proper cleanup on quiz end/reset
- Initialize prefixAcceptanceTimeout in constructor for memory safety
- Add isPrefix() helper function for clean conflict detection
- Prevent race conditions by clearing existing timeouts before setting new ones
- Maintain seamless UX while eliminating user confusion from prefix conflicts

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-09-11 08:15:33 -05:00
parent 556a830540
commit 01b00b5a40

View File

@@ -5075,6 +5075,7 @@ def generate_web_flashcards(numbers, config, output_path):
this.currentInput = '';
this.incorrectGuesses = 0;
this.finishButtonsBound = false;
this.prefixAcceptanceTimeout = null; // Timeout management for prefix conflicts
this.initializeCards();
this.bindEvents();
@@ -5341,6 +5342,12 @@ def generate_web_flashcards(numbers, config, output_path):
const display = document.getElementById('number-display');
const typingSpan = document.getElementById('current-typing');
// Always clear any existing timeout first
if (this.prefixAcceptanceTimeout) {{
clearTimeout(this.prefixAcceptanceTimeout);
this.prefixAcceptanceTimeout = null;
}}
// Reset visual feedback
display.classList.remove('correct', 'incorrect');
@@ -5363,14 +5370,27 @@ def generate_web_flashcards(numbers, config, output_path):
// Check if this number is in our correct answers and not already found
if (this.correctAnswers.includes(number) && !this.foundNumbers.includes(number)) {{
// Correct number found!
this.acceptCorrectNumber(number, input, display);
// Check if this input is a prefix of any other correct answers
if (!this.isPrefix(value, this.correctAnswers)) {{
// Safe to auto-accept immediately - no timeout needed
this.acceptCorrectNumber(number, input, display);
}} else {{
// Brief delay for potential prefixes - store timeout ID
this.prefixAcceptanceTimeout = setTimeout(() => {{
this.prefixAcceptanceTimeout = null; // Clear reference
this.acceptCorrectNumber(number, input, display);
}}, 500);
}}
}} else if (value.length >= 2 && !this.correctAnswers.includes(number)) {{
// Wrong number (only trigger after at least 2 digits to avoid false positives)
this.handleIncorrectGuess(input, display);
}}
}}
isPrefix(input, numbers) {{
return numbers.some(n => n.toString().startsWith(input) && n.toString() !== input);
}}
acceptCorrectNumber(number, input, display) {{
// Add to found numbers
this.foundNumbers.push(number);
@@ -5584,6 +5604,7 @@ def generate_web_flashcards(numbers, config, output_path):
endQuiz() {{
// Stop the current quiz and return to configuration
this.cleanupQuizState();
this.resetQuiz();
}}
@@ -5599,6 +5620,18 @@ def generate_web_flashcards(numbers, config, output_path):
this.incorrectGuesses = 0;
this.finishButtonsBound = false;
// Clean up any pending timeouts
this.cleanupQuizState();
}}
cleanupQuizState() {{
// Clear any pending prefix acceptance timeout
if (this.prefixAcceptanceTimeout) {{
clearTimeout(this.prefixAcceptanceTimeout);
this.prefixAcceptanceTimeout = null;
}}
// Clear smart input
const smartInput = document.getElementById('smart-input');
if (smartInput) {{