Initial commit: Своя Игра - multiplayer quiz game
This commit is contained in:
119
client/src/components/GameBoard.jsx
Normal file
119
client/src/components/GameBoard.jsx
Normal file
@@ -0,0 +1,119 @@
|
||||
function GameBoard({ questions, usedQuestions, onSelectQuestion, currentRound, isHost }) {
|
||||
const isQuestionUsed = (category, points, questionIndex) => {
|
||||
// Ищем этот конкретный вопрос в использованных
|
||||
// Сначала проверяем по questionIndex (новый метод)
|
||||
const foundByIndex = usedQuestions.find(
|
||||
q => q.category === category && q.points === points && q.questionIndex === questionIndex
|
||||
);
|
||||
|
||||
if (foundByIndex) {
|
||||
console.log(`✓ Question used (by index): cat="${category}", pts=${points}, idx=${questionIndex}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Для обратной совместимости: если в usedQuestions нет questionIndex,
|
||||
// проверяем, сколько вопросов с такими баллами уже использовано
|
||||
const usedCount = usedQuestions.filter(
|
||||
q => q.category === category && q.points === points
|
||||
).length;
|
||||
|
||||
if (usedCount === 0) return false;
|
||||
|
||||
// Получаем категорию и находим индекс вопроса среди вопросов с такими же баллами
|
||||
const categoryData = questions.find(cat => cat.name === category);
|
||||
const questionsWithSamePoints = categoryData?.questions
|
||||
.map((q, idx) => ({ ...q, originalIndex: idx }))
|
||||
.filter(q => q.points === points) || [];
|
||||
|
||||
const positionAmongSamePoints = questionsWithSamePoints.findIndex(q => q.originalIndex === questionIndex);
|
||||
|
||||
// Если позиция вопроса меньше количества использованных, значит он уже использован
|
||||
return positionAmongSamePoints >= 0 && positionAmongSamePoints < usedCount;
|
||||
}
|
||||
|
||||
const getPointsForRound = (basePoints, round) => {
|
||||
return round === 2 ? basePoints * 2 : basePoints
|
||||
}
|
||||
|
||||
// Проверить сколько вопросов осталось в категории
|
||||
const hasAvailableQuestions = (category) => {
|
||||
return category.questions.some((q, idx) => !isQuestionUsed(category.name, q.points, idx))
|
||||
}
|
||||
|
||||
// Фильтруем категории - показываем только те, где есть доступные вопросы
|
||||
const availableCategories = questions.filter(hasAvailableQuestions)
|
||||
|
||||
// Лог для отладки
|
||||
console.log('📋 GameBoard render:', {
|
||||
totalCategories: questions.length,
|
||||
availableCategories: availableCategories.length,
|
||||
usedQuestions: usedQuestions
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="bg-slate-800 p-3 md:p-6 rounded-xl shadow-xl border border-slate-700">
|
||||
{!isHost && (
|
||||
<div className="mb-3 md:mb-4 bg-blue-900 p-3 md:p-4 rounded-lg text-center">
|
||||
<p className="text-white text-sm md:text-lg font-medium">
|
||||
Ведущий выбирает вопросы. Будьте готовы отвечать!
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{isHost && (
|
||||
<div className="mb-3 md:mb-4 bg-blue-900 p-3 md:p-4 rounded-lg text-center">
|
||||
<p className="text-white text-sm md:text-lg font-bold">
|
||||
Выберите вопрос
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{availableCategories.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
{availableCategories.map((category, catIdx) => (
|
||||
<div key={catIdx} className="flex flex-col md:flex-row gap-2">
|
||||
{/* Название категории */}
|
||||
<div className="bg-blue-900 p-2 md:p-4 rounded-lg flex items-center justify-center border border-blue-700 md:min-w-[200px]">
|
||||
<h3 className="text-white font-bold text-sm md:text-lg text-center">
|
||||
{category.name}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
{/* Вопросы по номиналам */}
|
||||
<div className="grid grid-cols-5 md:flex gap-1 md:gap-2 flex-1">
|
||||
{category.questions.map((question, questionIndex) => {
|
||||
const displayPoints = getPointsForRound(question.points, currentRound)
|
||||
const isUsed = isQuestionUsed(category.name, question.points, questionIndex)
|
||||
|
||||
return (
|
||||
<button
|
||||
key={questionIndex}
|
||||
onClick={() => !isUsed && isHost && onSelectQuestion(category.name, question.points)}
|
||||
disabled={isUsed || !isHost}
|
||||
className={`flex-1 p-3 md:p-6 rounded-lg font-bold text-base md:text-2xl transition-all duration-200 ${
|
||||
isUsed
|
||||
? 'bg-slate-700 text-gray-500 cursor-not-allowed border border-slate-600'
|
||||
: isHost
|
||||
? 'bg-blue-600 text-white hover:bg-blue-700 cursor-pointer shadow-lg border border-blue-500'
|
||||
: 'bg-blue-600 text-white cursor-default opacity-60 border border-blue-500'
|
||||
}`}
|
||||
>
|
||||
{isUsed ? '—' : displayPoints}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-8 md:py-12 bg-slate-700 rounded-lg border border-slate-600">
|
||||
<p className="text-white text-lg md:text-2xl font-bold px-4">
|
||||
Все вопросы раунда {currentRound} использованы!
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default GameBoard
|
||||
Reference in New Issue
Block a user