Last commit not found
import { useState, KeyboardEvent, useEffect } from "react"; | |
import { getRandomWord } from "@/lib/words"; | |
import { motion } from "framer-motion"; | |
import { generateAIResponse, guessWord } from "@/services/mistralService"; | |
import { useToast } from "@/components/ui/use-toast"; | |
import { WelcomeScreen } from "./game/WelcomeScreen"; | |
import { WordDisplay } from "./game/WordDisplay"; | |
import { SentenceBuilder } from "./game/SentenceBuilder"; | |
import { GuessDisplay } from "./game/GuessDisplay"; | |
import { GameOver } from "./game/GameOver"; | |
type GameState = "welcome" | "showing-word" | "building-sentence" | "showing-guess" | "game-over"; | |
export const GameContainer = () => { | |
const [gameState, setGameState] = useState<GameState>("welcome"); | |
const [currentWord, setCurrentWord] = useState<string>(""); | |
const [sentence, setSentence] = useState<string[]>([]); | |
const [playerInput, setPlayerInput] = useState<string>(""); | |
const [isAiThinking, setIsAiThinking] = useState(false); | |
const [aiGuess, setAiGuess] = useState<string>(""); | |
const [successfulRounds, setSuccessfulRounds] = useState<number>(0); | |
const [totalWords, setTotalWords] = useState<number>(0); | |
const { toast } = useToast(); | |
useEffect(() => { | |
const handleKeyPress = (e: KeyboardEvent) => { | |
if (e.key === 'Enter') { | |
if (gameState === 'welcome') { | |
handleStart(); | |
} else if (gameState === 'showing-word') { | |
handleContinue(); | |
} else if (gameState === 'game-over' || gameState === 'showing-guess') { | |
const correct = isGuessCorrect(); | |
if (correct) { | |
handleNextRound(); | |
} else { | |
setGameState("game-over"); | |
} | |
} | |
} | |
}; | |
window.addEventListener('keydown', handleKeyPress as any); | |
return () => window.removeEventListener('keydown', handleKeyPress as any); | |
}, [gameState, aiGuess, currentWord]); | |
const handleStart = () => { | |
const word = getRandomWord(); | |
setCurrentWord(word); | |
setGameState("showing-word"); | |
setSuccessfulRounds(0); | |
setTotalWords(0); | |
console.log("Game started with word:", word); | |
}; | |
const handlePlayerWord = async (e: React.FormEvent) => { | |
e.preventDefault(); | |
if (!playerInput.trim()) return; | |
const word = playerInput.trim(); | |
const newSentence = [...sentence, word]; | |
setSentence(newSentence); | |
setPlayerInput(""); | |
setTotalWords(prev => prev + 1); | |
setIsAiThinking(true); | |
try { | |
const aiWord = await generateAIResponse(currentWord, newSentence); | |
const newSentenceWithAi = [...newSentence, aiWord]; | |
setSentence(newSentenceWithAi); | |
setTotalWords(prev => prev + 1); | |
} catch (error) { | |
console.error('Error in AI turn:', error); | |
toast({ | |
title: "AI Response Delayed", | |
description: "The AI is currently busy. Please try adding another word or wait a moment.", | |
variant: "default", | |
}); | |
} finally { | |
setIsAiThinking(false); | |
} | |
}; | |
const handleMakeGuess = async () => { | |
if (sentence.length === 0) return; | |
setIsAiThinking(true); | |
try { | |
const finalSentence = sentence.join(' '); | |
const guess = await guessWord(finalSentence); | |
setAiGuess(guess); | |
setGameState("showing-guess"); | |
} catch (error) { | |
console.error('Error getting AI guess:', error); | |
toast({ | |
title: "AI Response Delayed", | |
description: "The AI is currently busy. Please try again in a moment.", | |
variant: "default", | |
}); | |
} finally { | |
setIsAiThinking(false); | |
} | |
}; | |
const handleNextRound = () => { | |
if (handleGuessComplete()) { | |
const word = getRandomWord(); | |
setCurrentWord(word); | |
setGameState("showing-word"); | |
setSentence([]); | |
setAiGuess(""); | |
console.log("Next round started with word:", word); | |
} else { | |
setGameState("game-over"); | |
} | |
}; | |
const handlePlayAgain = () => { | |
setGameState("welcome"); | |
setSentence([]); | |
setAiGuess(""); | |
setCurrentWord(""); | |
setSuccessfulRounds(0); | |
setTotalWords(0); | |
}; | |
const handleContinue = () => { | |
setGameState("building-sentence"); | |
setSentence([]); | |
}; | |
const isGuessCorrect = () => { | |
return aiGuess.toLowerCase() === currentWord.toLowerCase(); | |
}; | |
const handleGuessComplete = () => { | |
if (isGuessCorrect()) { | |
setSuccessfulRounds(prev => prev + 1); | |
return true; | |
} | |
return false; | |
}; | |
const getAverageWordsPerRound = () => { | |
if (successfulRounds === 0) return 0; | |
return totalWords / (successfulRounds + 1); // The total words include the ones in the failed last round, so we also count it in the denominator | |
}; | |
return ( | |
<div className="flex min-h-screen items-center justify-center p-4"> | |
<motion.div | |
initial={{ opacity: 0, y: 20 }} | |
animate={{ opacity: 1, y: 0 }} | |
className="w-full max-w-md rounded-xl bg-white p-8 shadow-lg" | |
> | |
{gameState === "welcome" ? ( | |
<WelcomeScreen onStart={handleStart} /> | |
) : gameState === "showing-word" ? ( | |
<WordDisplay | |
currentWord={currentWord} | |
successfulRounds={successfulRounds} | |
onContinue={handleContinue} | |
/> | |
) : gameState === "building-sentence" ? ( | |
<SentenceBuilder | |
currentWord={currentWord} | |
successfulRounds={successfulRounds} | |
sentence={sentence} | |
playerInput={playerInput} | |
isAiThinking={isAiThinking} | |
onInputChange={setPlayerInput} | |
onSubmitWord={handlePlayerWord} | |
onMakeGuess={handleMakeGuess} | |
/> | |
) : gameState === "showing-guess" ? ( | |
<GuessDisplay | |
sentence={sentence} | |
aiGuess={aiGuess} | |
currentWord={currentWord} | |
onNextRound={handleNextRound} | |
onPlayAgain={handlePlayAgain} | |
currentScore={successfulRounds} | |
avgWordsPerRound={getAverageWordsPerRound()} | |
/> | |
) : gameState === "game-over" ? ( | |
<GameOver | |
successfulRounds={successfulRounds} | |
onPlayAgain={handlePlayAgain} | |
/> | |
) : null} | |
</motion.div> | |
</div> | |
); | |
}; | |