beeta/bot-sdk/examples/trivia-bot.js
2026-01-05 22:54:27 -05:00

221 lines
6.1 KiB
JavaScript

/**
* Trivia Bot Example
*
* A bot that runs trivia games in chat
*
* Usage:
* node trivia-bot.js <api-key> <server-url> <realm-id>
*
* Commands:
* !trivia start - Start a new trivia game
* !trivia stop - Stop the current game
* !trivia score - Show current scores
* !answer <answer> - Submit an answer
*/
import ChatBot from '../index.js';
// Get arguments
const [,, apiKey, serverUrl, realmId] = process.argv;
if (!apiKey || !serverUrl || !realmId) {
console.log('Usage: node trivia-bot.js <api-key> <server-url> <realm-id>');
process.exit(1);
}
// Trivia questions
const questions = [
{ question: "What planet is known as the Red Planet?", answer: "mars" },
{ question: "What is the largest mammal in the world?", answer: "blue whale" },
{ question: "In what year did the Titanic sink?", answer: "1912" },
{ question: "What is the chemical symbol for gold?", answer: "au" },
{ question: "Who painted the Mona Lisa?", answer: "leonardo da vinci" },
{ question: "What is the capital of Japan?", answer: "tokyo" },
{ question: "How many sides does a hexagon have?", answer: "6" },
{ question: "What is the smallest prime number?", answer: "2" },
{ question: "What element does 'O' represent on the periodic table?", answer: "oxygen" },
{ question: "In what year did World War II end?", answer: "1945" },
{ question: "What is the largest organ in the human body?", answer: "skin" },
{ question: "Who wrote Romeo and Juliet?", answer: "shakespeare" },
{ question: "What is the speed of light in km/s (approximately)?", answer: "300000" },
{ question: "What is the tallest mountain in the world?", answer: "everest" },
{ question: "What gas do plants absorb from the atmosphere?", answer: "carbon dioxide" }
];
// Game state
let gameActive = false;
let currentQuestion = null;
let questionIndex = 0;
let scores = {};
let questionTimeout = null;
let usedQuestions = [];
// Create the bot
const bot = new ChatBot('TriviaBot');
function shuffleArray(array) {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
}
function getNextQuestion() {
if (usedQuestions.length === questions.length) {
usedQuestions = [];
}
const available = questions.filter((_, i) => !usedQuestions.includes(i));
const randomIndex = Math.floor(Math.random() * available.length);
const originalIndex = questions.indexOf(available[randomIndex]);
usedQuestions.push(originalIndex);
return available[randomIndex];
}
function askQuestion() {
if (!gameActive) return;
currentQuestion = getNextQuestion();
questionIndex++;
bot.print(`Question #${questionIndex}: ${currentQuestion.question}`);
// Set timeout for unanswered question
questionTimeout = setTimeout(() => {
if (currentQuestion) {
bot.print(`Time's up! The answer was: ${currentQuestion.answer}`);
currentQuestion = null;
// Ask next question after delay
setTimeout(() => {
if (gameActive) askQuestion();
}, 3000);
}
}, 30000); // 30 seconds to answer
}
function checkAnswer(username, answer) {
if (!currentQuestion) return;
const normalizedAnswer = answer.toLowerCase().trim();
const correctAnswer = currentQuestion.answer.toLowerCase().trim();
if (normalizedAnswer === correctAnswer || normalizedAnswer.includes(correctAnswer) || correctAnswer.includes(normalizedAnswer)) {
clearTimeout(questionTimeout);
// Award points
if (!scores[username]) scores[username] = 0;
scores[username]++;
bot.print(`Correct! ${username} got it right! (+1 point, total: ${scores[username]})`);
currentQuestion = null;
// Ask next question after delay
setTimeout(() => {
if (gameActive) askQuestion();
}, 3000);
}
}
function showScores() {
const sortedScores = Object.entries(scores)
.sort(([, a], [, b]) => b - a)
.slice(0, 10);
if (sortedScores.length === 0) {
bot.print('No scores yet!');
return;
}
let scoreText = 'Leaderboard: ';
sortedScores.forEach(([user, score], i) => {
scoreText += `${i + 1}. ${user}: ${score} pts | `;
});
bot.print(scoreText.slice(0, -3));
}
function startGame() {
if (gameActive) {
bot.print('A game is already in progress!');
return;
}
gameActive = true;
questionIndex = 0;
bot.print('Trivia game starting! Answer with "!answer <your answer>". You have 30 seconds per question.');
setTimeout(() => {
askQuestion();
}, 2000);
}
function stopGame() {
if (!gameActive) {
bot.print('No game is currently running.');
return;
}
gameActive = false;
currentQuestion = null;
clearTimeout(questionTimeout);
bot.print('Trivia game stopped!');
showScores();
}
// Set up message handler
bot.messageHandler = (message) => {
const content = message.content.trim().toLowerCase();
if (content === '!trivia start') {
startGame();
} else if (content === '!trivia stop') {
stopGame();
} else if (content === '!trivia score' || content === '!trivia scores') {
showScores();
} else if (content === '!trivia help') {
bot.print('Commands: !trivia start, !trivia stop, !trivia score, !answer <answer>');
} else if (content.startsWith('!answer ')) {
const answer = message.content.slice(8);
checkAnswer(message.username, answer);
}
};
// Set up event handlers
bot.onJoin = () => {
bot.print('TriviaBot is online! Type "!trivia start" to begin a game.');
};
bot.onError = (error) => {
console.error('Bot error:', error.message);
};
// Connect and join
async function main() {
try {
console.log(`Connecting to ${serverUrl}...`);
await bot.connect(apiKey, serverUrl);
console.log(`Joining room: ${realmId}...`);
await bot.joinRoom(realmId);
console.log('TriviaBot is running. Press Ctrl+C to stop.');
} catch (error) {
console.error('Failed to start bot:', error.message);
process.exit(1);
}
}
// Handle shutdown
process.on('SIGINT', () => {
console.log('\nShutting down bot...');
if (gameActive) stopGame();
bot.disconnect();
process.exit(0);
});
main();