sto-k-odnomu/src/components/Game.jsx

258 lines
8.2 KiB
React
Raw Normal View History

2025-12-31 16:53:26 +00:00
import { useState } from 'react'
import Question from './Question'
2025-12-31 17:05:48 +00:00
import Players from './Players'
import PlayersModal from './PlayersModal'
2025-12-31 17:13:24 +00:00
import QuestionsModal from './QuestionsModal'
2025-12-31 17:05:48 +00:00
import Score from './Score'
2025-12-31 17:13:24 +00:00
import { questions as initialQuestions } from '../data/questions'
2025-12-31 16:53:26 +00:00
import './Game.css'
const Game = () => {
2025-12-31 17:05:48 +00:00
const [players, setPlayers] = useState([])
const [currentPlayerId, setCurrentPlayerId] = useState(null)
const [playerScores, setPlayerScores] = useState({})
2025-12-31 17:13:24 +00:00
const [questions, setQuestions] = useState(initialQuestions)
2025-12-31 16:53:26 +00:00
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0)
const [gameOver, setGameOver] = useState(false)
const [revealedAnswers, setRevealedAnswers] = useState([])
2025-12-31 17:05:48 +00:00
const [isPlayersModalOpen, setIsPlayersModalOpen] = useState(false)
2025-12-31 17:13:24 +00:00
const [isQuestionsModalOpen, setIsQuestionsModalOpen] = useState(false)
2025-12-31 16:53:26 +00:00
const currentQuestion = questions[currentQuestionIndex]
const isLastQuestion = currentQuestionIndex === questions.length - 1
2025-12-31 17:05:48 +00:00
const handleAddPlayer = (name) => {
const newPlayer = {
id: Date.now(),
name: name,
}
const updatedPlayers = [...players, newPlayer]
setPlayers(updatedPlayers)
// Если это первый участник, делаем его текущим
if (updatedPlayers.length === 1) {
setCurrentPlayerId(newPlayer.id)
setPlayerScores({ [newPlayer.id]: 0 })
} else {
setPlayerScores({ ...playerScores, [newPlayer.id]: 0 })
}
}
const handleSelectPlayer = (playerId) => {
setCurrentPlayerId(playerId)
}
const handleRemovePlayer = (playerId) => {
const updatedPlayers = players.filter(p => p.id !== playerId)
setPlayers(updatedPlayers)
const updatedScores = { ...playerScores }
delete updatedScores[playerId]
setPlayerScores(updatedScores)
// Если удалили текущего участника, выбираем другого
if (currentPlayerId === playerId) {
if (updatedPlayers.length > 0) {
setCurrentPlayerId(updatedPlayers[0].id)
} else {
setCurrentPlayerId(null)
}
}
}
const getNextPlayerId = () => {
if (players.length === 0) return null
if (players.length === 1) return currentPlayerId
const currentIndex = players.findIndex(p => p.id === currentPlayerId)
const nextIndex = (currentIndex + 1) % players.length
return players[nextIndex].id
}
2025-12-31 16:53:26 +00:00
const handleAnswerClick = (answerIndex, points) => {
if (revealedAnswers.includes(answerIndex)) return
2025-12-31 17:05:48 +00:00
if (!currentPlayerId) return
2025-12-31 17:13:24 +00:00
if (!currentQuestion) return
2025-12-31 16:53:26 +00:00
2025-12-31 17:05:48 +00:00
const isLastAnswer = revealedAnswers.length === currentQuestion.answers.length - 1
2025-12-31 16:53:26 +00:00
setRevealedAnswers([...revealedAnswers, answerIndex])
2025-12-31 17:05:48 +00:00
// Добавляем очки текущему участнику
setPlayerScores({
...playerScores,
[currentPlayerId]: (playerScores[currentPlayerId] || 0) + points,
})
2025-12-31 16:53:26 +00:00
2025-12-31 17:05:48 +00:00
// Переходим к следующему участнику только если это не последний ответ
if (!isLastAnswer) {
const nextPlayerId = getNextPlayerId()
if (nextPlayerId) {
setTimeout(() => {
setCurrentPlayerId(nextPlayerId)
}, 500)
}
} else {
// Если это последний ответ, переходим к следующему участнику перед следующим вопросом
2025-12-31 16:53:26 +00:00
setTimeout(() => {
2025-12-31 17:05:48 +00:00
const nextPlayerId = getNextPlayerId()
if (nextPlayerId) {
setCurrentPlayerId(nextPlayerId)
}
2025-12-31 16:53:26 +00:00
if (isLastQuestion) {
setGameOver(true)
} else {
2025-12-31 17:05:48 +00:00
setTimeout(() => {
nextQuestion()
}, 500)
2025-12-31 16:53:26 +00:00
}
}, 2000)
}
}
const nextQuestion = () => {
setCurrentQuestionIndex(currentQuestionIndex + 1)
setRevealedAnswers([])
}
const restartGame = () => {
setCurrentQuestionIndex(0)
setGameOver(false)
setRevealedAnswers([])
2025-12-31 17:05:48 +00:00
const initialScores = {}
players.forEach(player => {
initialScores[player.id] = 0
})
setPlayerScores(initialScores)
if (players.length > 0) {
setCurrentPlayerId(players[0].id)
}
2025-12-31 16:53:26 +00:00
}
2025-12-31 17:13:24 +00:00
const handleUpdateQuestions = (updatedQuestions) => {
setQuestions(updatedQuestions)
// Если текущий вопрос был удален, сбрасываем индекс
if (currentQuestionIndex >= updatedQuestions.length) {
setCurrentQuestionIndex(0)
setRevealedAnswers([])
}
}
2025-12-31 16:53:26 +00:00
if (gameOver) {
2025-12-31 17:05:48 +00:00
// Находим победителя(ей)
const scores = Object.values(playerScores)
const maxScore = scores.length > 0 ? Math.max(...scores) : 0
const winners = players.filter(p => playerScores[p.id] === maxScore)
2025-12-31 16:53:26 +00:00
return (
<div className="game-over">
<div className="game-over-content">
<h2 className="game-over-title">🎉 Игра окончена! 🎉</h2>
2025-12-31 17:05:48 +00:00
<div className="final-scores">
<h3 className="final-scores-title">Итоговые результаты:</h3>
{players
.sort((a, b) => (playerScores[b.id] || 0) - (playerScores[a.id] || 0))
.map((player) => (
<div
key={player.id}
className={`final-score-item ${
winners.includes(player) ? 'final-score-winner' : ''
}`}
>
<span className="final-score-name">{player.name}</span>
<span className="final-score-value">
{playerScores[player.id] || 0} очков
</span>
</div>
))}
</div>
2025-12-31 16:53:26 +00:00
<button className="restart-button" onClick={restartGame}>
Играть снова
</button>
</div>
</div>
)
}
return (
<div className="game">
2025-12-31 17:05:48 +00:00
<PlayersModal
isOpen={isPlayersModalOpen}
onClose={() => setIsPlayersModalOpen(false)}
players={players}
onAddPlayer={handleAddPlayer}
onRemovePlayer={handleRemovePlayer}
2025-12-31 16:53:26 +00:00
/>
2025-12-31 17:05:48 +00:00
2025-12-31 17:13:24 +00:00
<QuestionsModal
isOpen={isQuestionsModalOpen}
onClose={() => setIsQuestionsModalOpen(false)}
questions={questions}
onUpdateQuestions={handleUpdateQuestions}
/>
2025-12-31 17:05:48 +00:00
<div className="game-header">
2025-12-31 17:13:24 +00:00
<div className="game-header-buttons">
<button
className="manage-players-button"
onClick={() => setIsPlayersModalOpen(true)}
>
{players.length === 0 ? 'Добавить участников' : 'Управление участниками'}
</button>
<button
className="manage-questions-button"
onClick={() => setIsQuestionsModalOpen(true)}
>
Управление вопросами
</button>
</div>
2025-12-31 17:05:48 +00:00
{players.length > 0 && (
<Players
players={players}
currentPlayerId={currentPlayerId}
playerScores={playerScores}
onSelectPlayer={handleSelectPlayer}
/>
)}
</div>
{players.length > 0 && currentPlayerId ? (
<>
2025-12-31 17:13:24 +00:00
{questions.length === 0 ? (
<div className="no-players-message">
<p>Добавьте вопросы, чтобы начать игру</p>
</div>
) : currentQuestion ? (
<>
<Score
score={playerScores[currentPlayerId] || 0}
questionNumber={currentQuestionIndex + 1}
totalQuestions={questions.length}
/>
<Question
question={currentQuestion}
questionNumber={currentQuestionIndex + 1}
onAnswerClick={handleAnswerClick}
revealedAnswers={revealedAnswers}
/>
</>
) : (
<div className="no-players-message">
<p>Ошибка: вопрос не найден</p>
</div>
)}
2025-12-31 17:05:48 +00:00
</>
) : (
<div className="no-players-message">
<p>Добавьте участников, чтобы начать игру</p>
</div>
)}
2025-12-31 16:53:26 +00:00
</div>
)
}
export default Game