Last active
June 23, 2025 14:21
-
-
Save Klerith/2c43b0b062c491e952dba1877ac4c6b7 to your computer and use it in GitHub Desktop.
Componente para el juego ScramleWords y la necesidad de un useReducer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ! Importante: | |
// Es necesario componentes de Shadcn/ui | |
// https://ui.shadcn.com/docs/installation/vite | |
import React, { useState } from 'react'; | |
import { Button } from '@/components/ui/button'; | |
import { Input } from '@/components/ui/input'; | |
import { Card, CardContent } from '@/components/ui/card'; | |
import { SkipForward, Play } from 'lucide-react'; | |
const GAME_WORDS = [ | |
'REACT', | |
'JAVASCRIPT', | |
'TYPESCRIPT', | |
'HTML', | |
'ANGULAR', | |
'SOLID', | |
'NODE', | |
'VUEJS', | |
'SVELTE', | |
'EXPRESS', | |
'MONGODB', | |
'POSTGRES', | |
'DOCKER', | |
'KUBERNETES', | |
'WEBPACK', | |
'VITE', | |
'TAILWIND', | |
]; | |
// Esta función mezcla el arreglo para que siempre sea aleatorio | |
const shuffleArray = (array: string[]) => { | |
return array.sort(() => Math.random() - 0.5); | |
}; | |
// Esta función mezcla las letras de la palabra | |
const scrambleWord = (word: string = '') => { | |
return word | |
.split('') | |
.sort(() => Math.random() - 0.5) | |
.join(''); | |
}; | |
export const ScrambleWords = () => { | |
const [words, setWords] = useState(shuffleArray(GAME_WORDS)); | |
const [currentWord, setCurrentWord] = useState(words[0]); | |
const [scrambledWord, setScrambledWord] = useState(scrambleWord(currentWord)); | |
const [guess, setGuess] = useState(''); | |
const [points, setPoints] = useState(0); | |
const [errorCounter, setErrorCounter] = useState(0); | |
const [maxAllowErrors, setMaxAllowErrors] = useState(3); | |
const [skipCounter, setSkipCounter] = useState(0); | |
const [maxSkips, setMaxSkips] = useState(3); | |
const [isGameOver, setIsGameOver] = useState(false); | |
const handleGuessSubmit = (e: React.FormEvent) => { | |
e.preventDefault(); | |
// Game logic will be implemented later | |
console.log('Guess submitted:', guess); | |
}; | |
const handleSkip = () => { | |
console.log('Skipped word'); | |
setGuess(''); | |
}; | |
const handlePlayAgain = () => { | |
console.log('Play again clicked'); | |
setPoints(0); | |
setErrorCounter(0); | |
setGuess(''); | |
}; | |
return ( | |
<div className="min-h-screen bg-gradient-to-br from-purple-100 via-blue-50 to-indigo-100 flex items-center justify-center p-4"> | |
<div className="w-full max-w-md mx-auto"> | |
{/* Header */} | |
<div className="text-center mb-8"> | |
<h1 className="text-4xl font-bold bg-gradient-to-r from-purple-600 to-blue-600 bg-clip-text text-transparent mb-2"> | |
Palabras desordenadas | |
</h1> | |
<p className="text-gray-600"> | |
Desordena las letras para encontrar la palabra! | |
</p> | |
</div> | |
{/* Main Game Card */} | |
<Card className="backdrop-blur-sm bg-white/80 border-0 shadow-xl"> | |
<CardContent className="p-8"> | |
{/* Scrambled Word Display */} | |
<div className="mb-8"> | |
<h2 className="text-center text-sm font-medium text-gray-500 mb-4 uppercase tracking-wide flex items-center justify-center gap-2"> | |
Palabra Desordenada | |
{isGameOver && ( | |
<span className="text-red-500 text-xl"> {currentWord}</span> | |
)} | |
</h2> | |
<div className="flex justify-center gap-2 mb-6"> | |
{scrambledWord.split('').map((letter, index) => ( | |
<div | |
key={index} | |
className="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-lg flex items-center justify-center text-white font-bold text-xl shadow-lg transform hover:scale-105 transition-transform duration-200" | |
style={{ | |
animationDelay: `${index * 0.1}s`, | |
animation: 'fadeInUp 0.6s ease-out forwards', | |
}} | |
> | |
{letter} | |
</div> | |
))} | |
</div> | |
</div> | |
{/* Guess Input */} | |
<form onSubmit={handleGuessSubmit} className="mb-6"> | |
<div className="space-y-4"> | |
<div> | |
<label | |
htmlFor="guess" | |
className="block text-sm font-medium text-gray-700 mb-2" | |
> | |
Adivina la palabra | |
</label> | |
<Input | |
id="guess" | |
type="text" | |
value={guess} | |
onChange={(e) => | |
setGuess(e.target.value.toUpperCase().trim()) | |
} | |
placeholder="Ingresa tu palabra..." | |
className="text-center text-lg font-semibold h-12 border-2 border-indigo-200 focus:border-indigo-500 transition-colors" | |
maxLength={scrambledWord.length} | |
disabled={isGameOver} | |
/> | |
</div> | |
<Button | |
type="submit" | |
className="w-full bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 text-white font-semibold py-3 rounded-lg shadow-lg hover:shadow-xl transform hover:scale-[1.02] transition-all duration-200" | |
disabled={!guess.trim() || isGameOver} | |
> | |
Enviar Adivinanza | |
</Button> | |
</div> | |
</form> | |
{/* Stats */} | |
<div className="grid grid-cols-2 gap-4 mb-6"> | |
<div className="bg-gradient-to-br from-green-50 to-emerald-50 rounded-lg p-4 text-center border border-green-200"> | |
<div className="text-2xl font-bold text-green-600"> | |
{points} / {GAME_WORDS.length} | |
</div> | |
<div className="text-sm text-green-700 font-medium">Puntos</div> | |
</div> | |
<div className="bg-gradient-to-br from-red-50 to-rose-50 rounded-lg p-4 text-center border border-red-200"> | |
<div className="text-2xl font-bold text-red-600"> | |
{errorCounter}/{maxAllowErrors} | |
</div> | |
<div className="text-sm text-red-700 font-medium">Errores</div> | |
</div> | |
</div> | |
{/* Action Buttons */} | |
<div className="grid grid-cols-2 gap-3"> | |
<Button | |
onClick={handleSkip} | |
variant="outline" | |
className="border-2 border-gray-300 hover:border-gray-400 hover:bg-gray-50 transition-colors flex items-center justify-center gap-2" | |
disabled={isGameOver || skipCounter >= maxSkips} | |
> | |
<SkipForward className="w-4 h-4" /> | |
Saltar ({skipCounter} / {maxSkips}) | |
</Button> | |
<Button | |
onClick={handlePlayAgain} | |
variant="outline" | |
className="border-2 border-indigo-300 hover:border-indigo-400 hover:bg-indigo-50 text-indigo-600 transition-colors flex items-center justify-center gap-2" | |
> | |
<Play className="w-4 h-4" /> | |
Jugar de nuevo | |
</Button> | |
</div> | |
</CardContent> | |
</Card> | |
{/* Footer */} | |
<div className="text-center mt-6"> | |
<p className="text-sm text-gray-500"> | |
Desafíate con palabras desordenadas! | |
<br /> | |
<br /> | |
{words.join(', ')} | |
</p> | |
</div> | |
</div> | |
</div> | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment