Alright.. Fixed it by making PlayerScore class static
Seems to be working well
Doesn't track streaks or anything right now, but does run trivia
Still gets messed up from time to time on hints and answering questions, but if you just let it keep running it'll make itself right in a question or two.
There's certainly plenty to add.. a top 5 list, streak tracking, etc, but as it is it'll do what most people want
Here's a jar:
www.witcheshovel.com/WartsStuff/WartTrivia.jarAnd the knowledge.txt that I have right now (over 14000 questions):
www.witcheshovel.com/WartsStuff/knowledge.txtAnd the current code:
import javax.swing.*;
import callback_interfaces.*;
import exceptions.*;
import plugin_interfaces.*;
import java.util.*;
import java.util.regex.*;
import java.io.*;
import java.util.Timer;
import java.util.TimerTask;
/************************************
*
* RunTrivia
* Designed to run a trivia game in a chat channel..
* Fairly straight forward..
* Hopefully add score keepin and such..
* Modeled after the trivia answer bot by Derrenks
*
************************************/
public class PluginMain extends GenericPluginInterface implements CommandCallback, EventCallback
{
private PublicExposedFunctions out;
private static StaticExposedFunctions staticFuncs;
private String BOTNAME = "TriviaBot";
private Vector knowledge; //Contents of knowledge.txt
private String question;
private String answer;
private String oldAnswer = "nothing";
private boolean needReset;
private boolean triviaOn=false;
private boolean questionAsked=false;
private int questionNumber;
private HintThread hintThread;
private Hashtable<String, PlayerScore> scoreTable;
private PlayerScore playerScore;
static private Random gen = new Random();
public void load(StaticExposedFunctions staticFuncs) {
PluginMain.staticFuncs = staticFuncs;
}
public void activate(PublicExposedFunctions out, PluginCallbackRegister register) {
this.out = out;
register.registerCommandPlugin(this, "trivia", 0, false, "ANL", "", "Turns trivia on/off.", null);
register.registerEventPlugin(this, null);
knowledge = new Vector();
loadFile();
loadScores();
}
public void deactivate(PluginCallbackRegister register) {saveScores(); }
public String getName() { return "Wart's Trivia"; }
public String getVersion() { return "0.0.1"; }
public String getAuthorName() { return "Wart"; }
public String getAuthorWebsite() { return "http://www.wartsworld.com"; }
public String getAuthorEmail() { return "wart@wartsworld.com"; }
public String getShortDescription() { return "Runs trivia"; }
public String getLongDescription() { return "Runs a trivia program by picking questions from the specified file in the bot folder"; }
public Properties getDefaultSettingValues() {
//proceeding # because javaop displays them alphabetically...
Properties p = new Properties();
p.setProperty("1. Text to proceed question", ":+:");
p.setProperty("2. Acknowledge correct answers", "%n got it!");
p.setProperty("3. Answer format", "The answer was: ");
p.setProperty("4. Number of hints to provide", "3");
p.setProperty("5. Hint character", "-");
p.setProperty("6. Knowledge file", "knowledge.txt");
p.setProperty("7. Hint Delay", "7000");
p.setProperty("8. Score File", "scores.txt");
return p;
}
public Properties getSettingsDescription()
{
Properties p = new Properties();
p.setProperty("1. Text to proceed question", "Text to put before a question. i.e. ClanBot@USEast: :+:What is the orc builder?");
p.setProperty("2. Acknowledge correct answers", "How to say who answered the question. Use %n to denote the persons name. ie %n got the answer right!");
p.setProperty("3. Answer format", "How to display the correct answer. ie The answer was %a.");
p.setProperty("4. Number of hints to provide", "How many hints to provide before telling the answer.");
p.setProperty("5. Hint character", "Character to substitute in for letters.. ie: Hint: P--n for Peon");
p.setProperty("6. Knowledge file", "Name of file to load questions/answers from. - This may not work correctly");
p.setProperty("7. Hint Delay", "Time to wait between hints (milli seconds)");
p.setProperty("8. Score File", "Name of file to keep scores in.");
return p;
}
public JComponent getComponent(String settingName, String value) {
return null; //all settings are text fields
}
public Properties getGlobalDefaultSettingValues() {
Properties p = new Properties();
return p;
}
public Properties getGlobalSettingsDescription() {
Properties p = new Properties();
return p;
}
public JComponent getGlobalComponent(String settingName, String value) {
return null;
}
public boolean isRequiredPlugin() {
return true; //not sure what this actually does - Me either :-/
}
//Open File - Read file into array
private void loadFile() {
String knowledgeFile = getSetting("6. Knowledge file");
if(knowledgeFile == "") return; //probably not needed but...
try {
BufferedReader input = new BufferedReader(new FileReader(new File(knowledgeFile)));
String line;
//format is Question and answer on same line with * inbetween
// i.e Is this a trivia plugin?*Yes
while((line = input.readLine()) != null) {
knowledge.add(line);
}
input.close();
} catch(Exception e) { }
}
//Open Score File
private void loadScores() {
try {
String scoreFile = getSetting("8. Score File");
FileInputStream fileIn = new FileInputStream (scoreFile);
ObjectInputStream objectIn = new ObjectInputStream(new BufferedInputStream(fileIn));
Object object = objectIn.readObject();
scoreTable = (Hashtable)object;
objectIn.close();
fileIn.close();
} catch (Exception e) {createNewScore();} //score file doesn't exist
}
private void createNewScore() {
scoreTable = new Hashtable<String, PlayerScore>(500);
}
private void saveScores() {
try {
out.showMessage("Hash a a string: " + scoreTable.toString());
String scoreFile = getSetting("8. Score File");
FileOutputStream fileOut = new FileOutputStream (scoreFile);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
Object scores = (Object)scoreTable;
//objectOut.writeObject(scores);
objectOut.writeObject(scoreTable);
objectOut.close();
fileOut.close();
}
catch (NotSerializableException a) {out.showMessage("Not serializable Exeption: " + a);}
catch (Exception e) {out.showMessage("Failed to save file with error:" + e);}
}
//Find question - File must be in format: Question*Answer
public void findQuestion() {
questionNumber = gen.nextInt(knowledge.size());
out.showMessage("Knowledge size is: " + knowledge.size());
// while(questionNumber%2 != 0) {
// questionNumber = gen.nextInt(knowledge.size());
// }
String textLine = (String)knowledge.get(questionNumber);
int asteriskAt = textLine.indexOf('*');
question = textLine.substring(0,asteriskAt);
answer = textLine.substring(asteriskAt+1);
out.showMessage("Answer is: " + answer);
// question = (String)knowledge.get(questionNumber);
// answer = (String)knowledge.get(questionNumber+1);
}
//Ask Question - if trivia on
public void askQuestion() throws IOException, PluginException {
if(!triviaOn) return;
if(!questionAsked) {
out.sendText(getSetting("1. Text to proceed question") + " Q#" + questionNumber + " " + question);
questionAsked=true;
}
//Hint thread
int tempNumber = questionNumber;
int hintMax = Integer.parseInt(getSetting("4. Number of hints to provide"));
int currentHint=0;
char[] hint = new char[answer.length()];
int hintDelay = Integer.parseInt(getSetting("7. Hint Delay"));
char hintChar = getSetting("5. Hint character").charAt(0);
hintThread = new HintThread(hintDelay,hintMax,answer.length(),hintChar);
hintThread.start();
}
//Listen for correct answers
public void talk(String user, String text, int ping, int flags) throws IOException, PluginException {
if(!triviaOn || !questionAsked) return; //Trivia not on or no question asked
if(needReset && oldAnswer == answer) { //No answer
needReset=false;
resetFromHint();
}
else if(text.equalsIgnoreCase(answer) && questionAsked) { //Correct answer
oldAnswer=answer;
questionAsked=false;
hintThread = null;
int score = addToScore(user);
out.sendTextPriority(user + " got it right and has now answered " + score + " questions! The answer was: " + answer,10);
resetFromHint();
}
}
//Correct Answer --> Keep Score
private int addToScore(String guesser) {
//See if person is already in hash
if(scoreTable.containsKey(guesser)) {
//if so add to their score
playerScore = scoreTable.get(guesser);
playerScore.incTotalCorrect();
playerScore.incLongestStreak();
scoreTable.put(guesser,playerScore);
return playerScore.getTotalCorrect();
}
else {
//if not add them to hash
playerScore = new PlayerScore(guesser);
playerScore.incLongestStreak();
playerScore.incTotalCorrect();
scoreTable.put(guesser, playerScore);
return playerScore.getTotalCorrect();
}
}
public String getAnswer() {
return answer;
}
public int getRandom(int randMax) {
return gen.nextInt(randMax);
}
public void sayOutLoud(String text) {
try{ out.sendText(text); }
catch (Exception e) {}
}
public void resetFromHint() {
if(!triviaOn) return;
oldAnswer = answer;
findQuestion();
try {Thread.sleep(5000);}
catch (Exception e2) {out.showMessage("Didn't sleep after reset");}
try {askQuestion(); }
catch (Exception e) {}
}
public void sayToConsole(String text) {
try{ out.showMessage(text);}
catch (Exception e) {}
}
public void emote(String user, String text, int ping, int flags) throws IOException, PluginException {}
public void whisperFrom(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void whisperTo(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void userShow(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void userJoin(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void userLeave(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void userFlags(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void error(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void info(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void broadcast(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
public void channel(String user, String statstring, int ping, int flags) throws IOException, PluginException {}
private String getSetting(String name) {
return out.getLocalSetting(getName(), name);
}
public void commandExecuted(String user, String command, String[] args, int loudness, Object data) throws PluginException, IOException {
if (command.equalsIgnoreCase("trivia")) {
if(triviaOn) {
triviaOn=false;
out.sendText("Trivia Turned Off");
questionAsked = false;
}
else {
triviaOn=true;
out.sendText("Trivia Turned On");
findQuestion();
askQuestion();
}
}
}
private class HintThread extends Thread {
private int hintDelay,hintMax,answerLength;
private char hintChar;
public HintThread(int hintDelay,int hintMax,int answerLength, char hintChar) {
setPriority(MIN_PRIORITY);
this.hintDelay = hintDelay;
this.hintMax = hintMax;
this.answerLength = answerLength;
this.hintChar = hintChar;
this.setName("Hint-thread");
}
public void run() {
if(!triviaOn || !questionAsked) return; //Does this work in a thread?
// setPriority(MIN_PRIORITY);
int currentHint;
char[] hint = new char[answerLength];
for(int i=0;i<answerLength;i++) {
hint[i] = hintChar; //Make hint word all ----
}
try{
for(currentHint=0;currentHint<hintMax;currentHint++)
{
Thread.sleep(hintDelay);
if(questionAsked==false) return;
if(oldAnswer==answer) return;
//give hint - 1/4(?) of the letters - would be nice to make this configurable
//This is done by getting a random char of the string and replacing it with the correct one
for(int j=0;j<(answerLength/3);j++) {
int temp = gen.nextInt(answerLength);
hint[temp] = answer.charAt(temp);
}
out.sendTextPriority("Hint: " + String.valueOf(hint),PRIORITY_NORMAL);
}
Thread.sleep(hintDelay);
if(oldAnswer==answer) return;
if(questionAsked==false) return;
questionAsked=false;
out.sendTextPriority("The answer is: " + answer,10);
// needReset=true;
out.showMessage("hintDelay is: " + hintDelay);
Thread.sleep(hintDelay);
resetFromHint();
}catch(Exception e){}
}
}
public static class PlayerScore implements Serializable { //Class for keeping player scores
String playerName;
int longestStreak=0;
int totalCorrect=0;
public PlayerScore() {}
public PlayerScore(String name) {
playerName = name;
}
public void setTotalCorrect(int newCorrect) {
totalCorrect = newCorrect;
}
public void incTotalCorrect() {
totalCorrect++;
}
public void setLongestStreak(int streak) {
longestStreak=streak;
}
public void incLongestStreak() {
longestStreak++;
}
public String getName() {
return playerName;
}
public int getStreak() {
return longestStreak;
}
public int getTotalCorrect() {
return totalCorrect;
}
}
}