Refine guessing game logic

Update the guessing game to handle user-provided questions and optimize computer-generated questions. The game will now grey out numbers divisible by 10 based on user input. Additionally, the computer will prioritize questions that maximize the remaining search space, ensuring a longer guessing period for the user. The "too high/too low" feedback is removed, relying solely on user questions for deduction.
This commit is contained in:
gpt-engineer-app[bot] 2025-08-10 14:11:36 +00:00
parent b0595d1cc7
commit 62c6acc388
2 changed files with 77 additions and 27 deletions

View file

@ -475,7 +475,6 @@ const GuessingGame: React.FC<GuessingGameProps> = ({ showSocialShare = true }) =
{gameState === 'playing' && gameMode === 'user-guesses' && userGuessingMode === 'questions' && (
<QuestionGuessingMode
maxRange={maxRange}
secretNumber={secretNumber!}
guesses={guesses}
feedback={feedback}
validNumbers={validNumbers}
@ -483,6 +482,7 @@ const GuessingGame: React.FC<GuessingGameProps> = ({ showSocialShare = true }) =
setUserGuess={setUserGuess}
onGuess={handleGuess}
onUpdateValidNumbers={setValidNumbers}
onWin={() => setGameState('won')}
/>
)}

View file

@ -7,7 +7,6 @@ import { HelpCircle, CheckCircle, XCircle } from 'lucide-react';
interface QuestionGuessingModeProps {
maxRange: number;
secretNumber: number;
guesses: number[];
feedback: string;
validNumbers: Set<number>;
@ -15,25 +14,26 @@ interface QuestionGuessingModeProps {
setUserGuess: (value: string) => void;
onGuess: (guessValue?: number) => void;
onUpdateValidNumbers: (newValidNumbers: Set<number>) => void;
onWin: () => void;
}
const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
maxRange,
secretNumber,
guesses,
feedback,
validNumbers,
userGuess,
setUserGuess,
onGuess,
onUpdateValidNumbers
onUpdateValidNumbers,
onWin
}) => {
const [question, setQuestion] = useState('');
const [questionHistory, setQuestionHistory] = useState<{question: string, answer: string, understood: boolean}[]>([]);
const [questionFeedback, setQuestionFeedback] = useState('');
// Function to interpret and answer yes/no questions without revealing the secret number
const interpretQuestion = (question: string, secretNumber: number): { understood: boolean, answer: boolean, questionType?: string, value?: number } => {
// Function to determine the optimal answer to keep search space as large as possible
const getOptimalAnswer = (question: string): { understood: boolean, answer: boolean, questionType?: string, value?: number } => {
const q = question.toLowerCase().trim();
// Remove question marks and normalize
@ -43,10 +43,18 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
if (normalizedQ.includes('is') && normalizedQ.includes('number')) {
// Is the number...
if (normalizedQ.includes('even')) {
return { understood: true, answer: secretNumber % 2 === 0, questionType: 'even' };
// Count how many valid numbers are even vs odd
const evenCount = Array.from(validNumbers).filter(n => n % 2 === 0).length;
const oddCount = validNumbers.size - evenCount;
// Choose answer that keeps more numbers
const answer = evenCount > oddCount;
return { understood: true, answer, questionType: 'even' };
}
if (normalizedQ.includes('odd')) {
return { understood: true, answer: secretNumber % 2 !== 0, questionType: 'odd' };
const oddCount = Array.from(validNumbers).filter(n => n % 2 !== 0).length;
const evenCount = validNumbers.size - oddCount;
const answer = oddCount > evenCount;
return { understood: true, answer, questionType: 'odd' };
}
if (normalizedQ.includes('prime')) {
const isPrime = (num: number): boolean => {
@ -56,12 +64,16 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
}
return true;
};
const prime = isPrime(secretNumber);
return { understood: true, answer: prime, questionType: 'prime' };
const primeCount = Array.from(validNumbers).filter(n => isPrime(n)).length;
const nonPrimeCount = validNumbers.size - primeCount;
const answer = primeCount > nonPrimeCount;
return { understood: true, answer, questionType: 'prime' };
}
if (normalizedQ.includes('perfect square')) {
const isPerfectSquare = Math.sqrt(secretNumber) % 1 === 0;
return { understood: true, answer: isPerfectSquare, questionType: 'perfectSquare' };
const perfectSquareCount = Array.from(validNumbers).filter(n => Math.sqrt(n) % 1 === 0).length;
const nonPerfectSquareCount = validNumbers.size - perfectSquareCount;
const answer = perfectSquareCount > nonPerfectSquareCount;
return { understood: true, answer, questionType: 'perfectSquare' };
}
}
@ -70,8 +82,10 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
const matches = normalizedQ.match(/(?:divisible by|multiple of)\s+(\d+)/);
if (matches) {
const divisor = parseInt(matches[1]);
const isDivisible = secretNumber % divisor === 0;
return { understood: true, answer: isDivisible, questionType: 'divisible', value: divisor };
const divisibleCount = Array.from(validNumbers).filter(n => n % divisor === 0).length;
const nonDivisibleCount = validNumbers.size - divisibleCount;
const answer = divisibleCount > nonDivisibleCount;
return { understood: true, answer, questionType: 'divisible', value: divisor };
}
}
@ -80,8 +94,10 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
const matches = normalizedQ.match(/(?:greater than|bigger than|larger than)\s+(\d+)/);
if (matches) {
const threshold = parseInt(matches[1]);
const isGreater = secretNumber > threshold;
return { understood: true, answer: isGreater, questionType: 'greaterThan', value: threshold };
const greaterCount = Array.from(validNumbers).filter(n => n > threshold).length;
const lessEqualCount = validNumbers.size - greaterCount;
const answer = greaterCount > lessEqualCount;
return { understood: true, answer, questionType: 'greaterThan', value: threshold };
}
}
@ -89,8 +105,10 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
const matches = normalizedQ.match(/(?:less than|smaller than)\s+(\d+)/);
if (matches) {
const threshold = parseInt(matches[1]);
const isLess = secretNumber < threshold;
return { understood: true, answer: isLess, questionType: 'lessThan', value: threshold };
const lessCount = Array.from(validNumbers).filter(n => n < threshold).length;
const greaterEqualCount = validNumbers.size - lessCount;
const answer = lessCount > greaterEqualCount;
return { understood: true, answer, questionType: 'lessThan', value: threshold };
}
}
@ -99,8 +117,10 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
const matches = normalizedQ.match(/contain(?:s)?\s+(?:the\s+)?digit\s+(\d)/);
if (matches) {
const digit = matches[1];
const contains = secretNumber.toString().includes(digit);
return { understood: true, answer: contains, questionType: 'containsDigit', value: parseInt(digit) };
const containsCount = Array.from(validNumbers).filter(n => n.toString().includes(digit)).length;
const doesntContainCount = validNumbers.size - containsCount;
const answer = containsCount > doesntContainCount;
return { understood: true, answer, questionType: 'containsDigit', value: parseInt(digit) };
}
}
@ -109,8 +129,14 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
const matches = normalizedQ.match(/(?:is it|is the number)\s+(\d+)/);
if (matches) {
const num = parseInt(matches[1]);
const isEqual = secretNumber === num;
return { understood: true, answer: isEqual, questionType: 'equals', value: num };
// If there's only one number left and they're asking about it, we must answer truthfully
if (validNumbers.size === 1) {
const answer = validNumbers.has(num);
return { understood: true, answer, questionType: 'equals', value: num };
}
// Otherwise, say no to keep the game going unless this number isn't even valid
const answer = false;
return { understood: true, answer, questionType: 'equals', value: num };
}
}
@ -187,7 +213,7 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
const handleQuestionSubmit = () => {
if (!question.trim()) return;
const result = interpretQuestion(question, secretNumber);
const result = getOptimalAnswer(question);
if (result.understood && result.questionType) {
const answer = result.answer ? 'Yes' : 'No';
@ -213,6 +239,30 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
setQuestion('');
};
// Handle final number guess - just check if it's the only remaining valid number
const handleFinalGuess = (guessValue?: number) => {
const guess = guessValue || parseInt(userGuess);
if (isNaN(guess) || guess < 1 || guess > maxRange) {
return;
}
if (validNumbers.size === 1 && validNumbers.has(guess)) {
onWin();
} else if (validNumbers.has(guess)) {
// Remove this number from valid numbers since it's not the answer
const newValidNumbers = new Set(validNumbers);
newValidNumbers.delete(guess);
onUpdateValidNumbers(newValidNumbers);
// Check if we're down to one number
if (newValidNumbers.size === 1) {
onWin();
}
}
setUserGuess('');
};
return (
<div className="space-y-6">
<div className="text-center space-y-2">
@ -285,7 +335,7 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
{/* Number Grid Display */}
<div className="space-y-4">
<h4 className="font-semibold text-center">Click a number to make your final guess:</h4>
<h4 className="font-semibold text-center">Click a number to make your final guess ({validNumbers.size} possibilities remaining):</h4>
<div className="grid grid-cols-8 sm:grid-cols-10 md:grid-cols-12 lg:grid-cols-16 gap-1 max-h-64 overflow-y-auto p-2 border rounded-lg">
{Array.from({ length: maxRange }, (_, i) => i + 1).map(num => {
const isValid = validNumbers.has(num);
@ -302,7 +352,7 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
${isGuessed ? 'bg-accent text-accent-foreground' : ''}
${isValid && !isGuessed ? 'hover:bg-accent/10' : ''}
`}
onClick={() => isValid && !isGuessed && onGuess(num)}
onClick={() => isValid && !isGuessed && handleFinalGuess(num)}
disabled={!isValid || isGuessed}
>
{num}
@ -318,11 +368,11 @@ const QuestionGuessingMode: React.FC<QuestionGuessingModeProps> = ({
placeholder="Or type your final guess"
value={userGuess}
onChange={(e) => setUserGuess(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && onGuess()}
onKeyDown={(e) => e.key === 'Enter' && handleFinalGuess()}
min={1}
max={maxRange}
/>
<Button onClick={() => onGuess()} disabled={!userGuess}>
<Button onClick={() => handleFinalGuess()} disabled={!userGuess}>
Guess
</Button>
</div>