< Day Day Up > |
Hack 60 A Trivia Bot
Turn an IRC bot into an automated quiz show host. Compete with your friends to be first to answer each question. If your channel ever seems to lack excitement, you can rev up the enjoyment factor by introducing a trivia bot that asks questions and waits for someone to respond with the correct answer. Most trivia bots ask a single question and wait for someone to give the correct answer. When the correct answer has been given, the bot will ask another question. This hack will show you how to make a basic trivia bot that stores all of its questions and answers in a text file. More advanced trivia bots can let you store the total scores for each user and may even have time limits for each question. 9.4.1 The CodeTo make your trivia bot easy to extend, you should create a Question class, so each question (and answer) can be stored in a Question object. The Question class also provides an isCorrect method, so you can see if a candidate answer is correct. Create a file called Question.java: public class Question { private String question; private String answer; public Question(String question, String answer) { this.question = question; this.answer = answer; } public String toString( ) { return question; } public String getAnswer( ) { return answer; } public boolean isCorrect(String a) { return answer.equalsIgnoreCase(a); } } The TriviaBot class will be used to maintain a collection of Question objects. Each time a new question is asked, it will be chosen randomly from this collection. As soon as the trivia bot joins a channel, it will ask a question. Whenever someone sends a message to the channel, the trivia bot will check to see if it matches the answer for the current question. If the answer is correct, the trivia bot will announce the sender of that message as being the winner. This trivia bot will also allow users to say the "clue" command. If anybody says "clue" in the channel, the trivia bot will respond by showing how many letters are in the answer. It does this by replacing each letter in the answer with a * character and sending it to the channel. So if the correct answer is "Internet Relay Chat," the bot will send the following to the channel: <Jibbler> clue <TriviaBot> Clue: ******** ***** **** This class extends PircBot to connect to IRC and uses the Random class in the java.util package to generate random question numbers. Create a file called TriviaBot.java: import org.jibble.pircbot.*; import java.util.*; public class TriviaBot extends PircBot { private Question currentQuestion = null; private ArrayList questions = new ArrayList( ); private static Random rand = new Random( ); public TriviaBot(String name) { setName(name); } public void addQuestion(Question question) { questions.add(question); } public void onJoin(String channel, String sender, String login, String hostname) { if (sender.equals(getNick( ))) { setNextQuestion(channel); } } public void onMessage(String channel, String sender, String login, String hostname, String message) { message = message.toLowerCase( ).trim( ); if (currentQuestion.isCorrect(message)) { sendMessage(channel, sender + " is the winner, with the correct" + "answer of" + currentQuestion.getAnswer( )); setNextQuestion(channel); } else if (message.equalsIgnoreCase("clue")) { String clue = currentQuestion.getAnswer( ); clue = clue.replaceAll("[^\\ ]", "*"); sendMessage(channel, "Clue: " + clue); } } private void setNextQuestion(String channel) { currentQuestion = (Question) questions.get(rand.nextInt(questions.size( ))); sendMessage(channel, "Next question: " + currentQuestion); } } The TriviaBot class uses an ArrayList to store each Question object. New questions can be added to the bot with the addQuestion method. The setNextQuestion method is used to pick a random question and announce it to the channel. The onJoin method is overridden and will be called whenever the bot joins a channel. The bot will then ask the first randomly picked question. The onMessage method is overridden and will be called whenever someone sends a message to the channel. If the message matches the correct answer for the current question, the bot will announce that the sender won and it will then pose the next question and carry on as before. If anybody sends the "clue" command, the bot will send the clue to the channel. 9.4.2 Making QuestionsThis bot will be near to useless without a large bundle of questions to ask. For now though, you can just make up a few questions to test the bot, then add more later. Each line of the text file will contain a question and an answer. The | character is used to separate each question and its answer. Create a file called quiz.txt and add some questions: What is the square root of 81?|9 What does IRC stand for?|Internet Relay Chat What is "bot" short for?|robot To make the bot turn each line of this file into a Question object, you must parse the contents before the bot connects to a server. You can add this little bit of code to the main method, which instantiates the bot. import java.io.*; public class TriviaBotMain { public static void main(String[] args) throws Exception { TriviaBot bot = new TriviaBot("TriviaBot"); // Read the questions from the file and add them to the bot. BufferedReader reader = new BufferedReader( new FileReader("./quiz.txt")); String line; while ((line = reader.readLine( )) != null) { String[] tokens = line.split("\\|"); if (tokens.length == 2) { Question question = new Question(tokens[0], tokens[1]); bot.addQuestion(question); } } bot.setVerbose(true); bot.connect("irc.freenode.net"); bot.joinChannel("#irchacks"); } } 9.4.3 Running the HackC:\java\TriviaBot> javac -classpath .;pircbot.jar *.java Run the bot like so: C:\java\TriviaBot> java -classpath .;pircbot.jar TriviaBotMain The bot will then start up. 9.4.4 The ResultsWhen the bot starts up, it will read the questions from quiz.txt, connect to the server, and join the channel #irchacks, as shown in Figure 9-3. Figure 9-3. TriviaBot running in #irchacksNote that without modification, this bot is suitable only for use in a single channel. This is because it stores the current question in a single field (currentQuestion), while multiple channel support would entail having a different variable for each channel. One way to make it suitable for use in multiple channels is to replace this simple variable with a HashMap, which is indexed by the channel name. This approach is implemented in the WelcomeBot [Hack #64] . |
< Day Day Up > |