Ошибка таймера и обработки ответов в многопользовательском Discord Quiz BotJavascript

Форум по Javascript
Ответить Пред. темаСлед. тема
Anonymous
 Ошибка таймера и обработки ответов в многопользовательском Discord Quiz Bot

Сообщение Anonymous »


Привет всем!

Я работаю над многопользовательским ботом Discord для игры-викторины, и я столкнулся с проблемой синхронизации таймера обратного отсчета и обработки ответа. Проблема возникает, когда пользователь отправляет ответ, и ответ обрабатывается в течение короткого времени, когда обратный отсчет подходит к концу. Во время перехода между обработкой ответа и завершением обратного отсчета происходит ошибка, которая прерывает тест и приводит систему в сбойное состояние.
Проблема:Когда пользователь отправляет ответ, он обрабатывается, но во время обработки ответа таймер продолжает работать и может уже истечь, что приводит к ошибке.
Ошибка возникает из-за того, что обратный отсчет и обработка ответа выполняются параллельно. и не синхронизированы должным образом. Это приводит к тому, что по истечении времени таймера система оказывается в недопустимом состоянии.
Как лучше синхронизировать обработку ответов с обратным отсчетом, чтобы поток теста не прерывался?
Вот код:

Код: Выделить всё

`require('dotenv').config();
const { Client, GatewayIntentBits, ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, Events } = require('discord.js');

const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});

const questions = [
{
question: "Which chapter is known for their intense rage in battle, especially when near death?",
options: ["Blood Angels", "Space Wolves", "Iron Hands"],
answer: 0,
time: 10
},
{
question: "What are the elite Imperial guards called who wear golden armor and protect the Emperor?",
options: ["Custodes", "Deathwatch", "Grey Knights"],
answer: 0,
time: 10
},
{
question: "What is the armor color of the Ultramarines?",
options: ["Blue", "Red", "Green"],
answer: 0,
time: 10
},
{
question: "Which Space Marine chapter is famously known for being cursed and suffering extreme misfortune in battle?",
options: ["Lamenters", "Blood Angels", "White Scars"],
answer: 0,
time: 10
},
{
question: "Which Space Marine Chapter is known for its focus on protecting the innocent?",
options: ["Salamanders", "Blood Angels", "Space Wolves"],
answer: 0,
time: 10
},
{
question: "Which Primarch is known for having angelic wings?",
options: ["Sanguinius", "Vulkan", "Horus"],
answer: 0,
time: 10
}
];

let leaderboard = {};
let activeQuestionIndex = 0;
let questionMessage = null;
let countdownInterval = null;
let userAnswers = {};
let messageCache = [];
let ephemeralMessages = {
savedAnswers: [],
alreadyAnswered: [],
quizRunningAlert: [] // Nachrichten, dass das Quiz bereits läuft
};
let quizActive = false; // Neue Variable, um zu prüfen, ob ein Quiz läuft
let startButtonMessage = null; // Variable, um die "Start Quiz"-Nachricht zu speichern

client.once('ready', () => {
console.log('Der Bot ist online!');
});

client.on('messageCreate', async message => {
if (message.author.bot) return;

if (message.content === '!startquiz') {
const row = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('start_quiz')
.setLabel('Start Quiz')
.setStyle(ButtonStyle.Primary)
.setDisabled(quizActive) // Button deaktiviert, wenn ein Quiz läuft
);

startButtonMessage = await message.channel.send({
content: 'Click the button to start the quiz!',
components: [row]
});
}
});

client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isButton()) return;

if (interaction.customId === 'start_quiz') {
if (!quizActive) {
quizActive = true; // Markiere das Quiz als aktiv
await startQuiz(interaction.channel);
} else {
const alreadyStartedMessage = await interaction.reply({
content: "A quiz is already running! Please wait until it is finished.",
ephemeral: true
});

ephemeralMessages.quizRunningAlert.push(alreadyStartedMessage); // Speichern der Nachricht, dass das Quiz bereits läuft
}
} else if (interaction.customId.startsWith('answer_')) {
await handleAnswer(interaction);
}
});

function shuffle(array) {
for (let i = array.length - 1; i > 0;  i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}

async function startQuiz(channel) {
leaderboard = {};
activeQuestionIndex = 0;
userAnswers = {};
messageCache = [];
ephemeralMessages = { savedAnswers: [], alreadyAnswered: [], quizRunningAlert: [] };

// Auswahl von 10 zufälligen Fragen
const selectedQuestions = [...questions];
shuffle(selectedQuestions);
const randomQuestions = selectedQuestions.slice(0, 10);

// Fragenliste mit den ausgewählten Fragen ersetzen
questions.length = 0; // Original-Liste leeren
questions.push(...randomQuestions);

await askNextQuestion(channel);
}

async function askNextQuestion(channel) {
if (activeQuestionIndex >= questions.length) {
return showFinalLeaderboard(channel);
}

const question = questions[activeQuestionIndex];
await askQuestion(channel, question);
activeQuestionIndex++;
}

async function askQuestion(channel, question) {
let timeLeft = question.time;

const embed = new EmbedBuilder()
.setTitle("Question")
.setDescription(question.question)
.setFooter({ text: `Time left: ${timeLeft} Seconds` });

const shuffledOptions = [...question.options];
shuffle(shuffledOptions);

const correctAnswerIndex = shuffledOptions.indexOf(question.options[question.answer]);

const row = new ActionRowBuilder();
shuffledOptions.forEach((option, index) => {
row.addComponents(
new ButtonBuilder()
.setCustomId(`answer_${index}`)
.setLabel(option)
.setStyle(ButtonStyle.Primary)
);
});

questionMessage = await channel.send({ embeds: [embed], components: [row] });
messageCache.push(questionMessage);

countdownInterval = setInterval(async () => {
timeLeft--;

const updatedEmbed = EmbedBuilder.from(embed)
.setFooter({ text: `Time left: ${timeLeft} seconds` });

await questionMessage.edit({ embeds: [updatedEmbed] });

if (timeLeft  {
updatedRow.addComponents(
new ButtonBuilder()
.setCustomId(`answer_${index}`)
.setLabel(option)
.setStyle(index === correctAnswerIndex ? ButtonStyle.Success : ButtonStyle.Danger)
.setDisabled(true)
);
});

const correctEmoji = "✅";
const wrongEmoji = "❌";

let resultMessage = "";
for (const userId in userAnswers) {
const isCorrect = userAnswers[userId] === correctAnswerIndex;
resultMessage += `: ${isCorrect ? correctEmoji + " **Right!**" : wrongEmoji + " **False!**"}\n`;

if (isCorrect) {
const points = Math.floor(Math.random() * (100 - 0 + 1)) + 0;
leaderboard[userId] = (leaderboard[userId] || 0) + points;
}
}

const embed = EmbedBuilder.from(questionMessage.embeds[0])
.setFooter({ text: "Time's up!" })
.setColor(0xFF0000)
.setDescription(`${question.question}\n\n${resultMessage}`);

await questionMessage.edit({ embeds: [embed], components: [updatedRow] });

userAnswers = {};
setTimeout(async () => {
await askNextQuestion(channel);
}, 5000);
}

async function handleAnswer(interaction) {
const [_, answerIndex] = interaction.customId.split('_');
const answer = parseInt(answerIndex);

if (userAnswers[interaction.user.id] !== undefined) {
const alreadyAnsweredMessage = await interaction.reply({
content: "You have already submitted an answer.",
ephemeral: true
});

ephemeralMessages.alreadyAnswered.push(alreadyAnsweredMessage); // Füge diese Nachricht zu den "bereits geantwortet"  Nachrichten hinzu
return;
}

userAnswers[interaction.user.id] = answer;

const updatedRow = new ActionRowBuilder();
questionMessage.components[0].components.forEach((button, index) => {
updatedRow.addComponents(
ButtonBuilder.from(button)
.setStyle(ButtonStyle.Primary)
);
});

const selectedAnswer = questionMessage.components[0].components[answer].label;
const replyMessage = await interaction.reply({
content: `${selectedAnswer} was logged in`,
ephemeral: true
});

ephemeralMessages.savedAnswers.push(replyMessage);
await interaction.message.edit({ components: [updatedRow] });
}

async function showFinalLeaderboard(channel) {
const sortedPlayers = Object.entries(leaderboard).sort((a, b) => b[1] - a[1]).slice(0, 5);
const description = sortedPlayers.map(([userId, score], i) => `${i + 1}. : ${score} Punkte`).join('\n');

const embed = new EmbedBuilder()
.setTitle("🏆 Final score 🏆")
.setDescription(description || "No players.")
.setColor(0xFFD700);

const leaderboardMessage = await channel.send({ embeds: [embed] });

let countdown = 15;

countdownInterval = setInterval(async () => {
await leaderboardMessage.edit({
embeds: [EmbedBuilder.from(embed).setFooter({ text: `End in ${countdown} seconds` })]
});

countdown--;

if (countdown  console.error("Fehler beim Löschen der Nachricht:", err));
}

// Lösche alle ephemeren Nachrichten, die für Benutzer sichtbar waren
for (const msg of ephemeralMessages.savedAnswers) {
await msg.delete().catch(err => console.error("Fehler beim Löschen der ephemeren Nachricht:", err));
}

// Lösche die Nachrichten, dass der Benutzer bereits geantwortet hat
for (const msg of ephemeralMessages.alreadyAnswered) {
await msg.delete().catch(err => console.error("Fehler beim Löschen der Nachricht (bereits geantwortet):", err));
}

// Lösche die Nachrichten, dass das Quiz bereits läuft
for (const msg of ephemeralMessages.quizRunningAlert) {
await msg.delete().catch(err => console.error("Fehler beim Löschen der Nachricht (Quiz läuft bereits):", err));
}

// Deaktiviere den Button
const row = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('start_quiz')
.setLabel('Start Quiz')
.setStyle(ButtonStyle.Primary)
.setDisabled(true)
);

// Deaktiviere den Button in der bestehenden Nachricht
if (startButtonMessage) {
await startButtonMessage.edit({
content: 'The quiz is over. Click to start a new quiz!',
components: [row]
});
}

// Zurücksetzen des Quiz-Status
quizActive = false;
}

client.login(process.env.BOT_TOKEN);`
Обработка ответа занимает больше времени, чем ожидалось, и к моменту обработки ответа пользователя обратный отсчет уже истек. Это приводит к тому, что тест переходит в недопустимое состояние, поскольку система не синхронизируется должным образом по истечении времени таймера.

Подробнее здесь: https://stackoverflow.com/questions/793 ... d-quiz-bot
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Javascript»