Leader boards in my Anagrams game


#1

Hello,

I have just finished my program. It is an Anagrams game where you have to make a word out of some random letters in a short amount of time. However, I want to spice up my game a little bit. I want to add a leader board into my game. This is not a leader board that resets every time you exit Processing. I want to create a leader board that lasts forever. Is there any way someone could help me with this?

Thank you


#2

Let’s be very clear about this.

Do you want a GLOBAL leader board, where you can see scores from EVERYONE that has played your game?

Or do you want a LOCAL leader board, that only shows the scores of people that have played on one specific computer?

A LOCAL leader board is easy to do.

A GLOBAL leader board is NOT easy to do.


#3

Definitely a Local leader board.


#4

Hi,

You could use a text file to store the scores.

Then, you can use those methods to read and write data on it:


#5

Thanks @jb4x ! I’ll try this out! :smiley:


#6

@jb4x

So I understand how createWriter() works. It saves my scores into a text file. I got that to work. Every time my game ends, it saves the score into a text file called “Leader Board”. However, I am not to sure how to use createReader(). I also do not know how to display the saved scores into the game itself. Can you help me out with this?

Thanks


#7

Let’s imagine that you have a file like this:

aaa 5000
bbb 4000
ccc 3000
ddd 2000
eee 1000

aaa, bbb, …, are the nickname of your players (with no space for the following code to work).
5000, 4000, …, are their respective high score.

Then, the following code will store them in an ArrayList so you can use them as you want in your code. I put a lot of comments but if you have any questions do not hesitate:

ArrayList<HighScoreTuplet> highScores; // The variable that will contain your high scores list

void setup() {  
  highScores = new ArrayList<HighScoreTuplet>(); // Initialization
  
  BufferedReader reader = createReader("highScore.txt"); // Opening the file containing the high scores
  String line = null; // The variable in which we will store each line
  
  try {
    while ((line = reader.readLine()) != null) { // While there are lines to read we put the result of the content of the next line in the line variable
      String[] pieces = split(line, " "); // Then we split the line to separate the nick name from the value
      highScores.add(new HighScoreTuplet(pieces[0], Integer.parseInt(pieces[1]))); // Then we add a new high score to the list
    }
    reader.close(); // We close when there is no more lines
  } catch (IOException e) { // THis block is played if there is a problem when reading the file
    e.printStackTrace();
  }
  
  
  
  // This block is just to show the content of the high scores list in the console
  for (int i = 0; i < highScores.size(); i++) {
    println(highScores.get(i).name + " - " + highScores.get(i).score);
  }
}



// A class to store a nickname and a score 
class HighScoreTuplet {
  final public String name;
  final public int score;
  
  HighScoreTuplet(final String name, int score) {
    this.name = name;
    this.score = score;
  }
}

#8

Ok I have implemented your code into my game, however I have made some changes because I do not have a way to add a name into the game. So some changes were made were:

//instead of
class HighScoreTuplet {
  final public String name;
  final public int score;
  
  HighScoreTuplet(final String name, int score) {
    this.name = name;
    this.score = score;
  }
}
//I had
class HighScoreTuplet {
  final public int score;
  
  HighScoreTuplet(final int score) {
    this.score = score;
  }
}
//also instead of
try {
    while ((line = reader.readLine()) != null) { 
      String[] pieces = split(line, " "); 
      highScores.add(new HighScoreTuplet(pieces[0], Integer.parseInt(pieces[1]))); 
    }
//I had
try {
      while ((line = reader.readLine()) != null) {
        String[] pieces = split(line, " ");
        leaderBoard.add(new HighScoreTuplet(Integer.parseInt(pieces[0])));
      }
//One final change I made was instead of 
for (int i = 0; i < highScores.size(); i++) {
    println(highScores.get(i).name + " - " + highScores.get(i).score);
  }
//I had
for (int i = 0; i < leaderBoard.size(); i++) {
    println(leaderBoard.get(i).score);
  }


Now how do I know if this is working? Nothing is printing in the console.

To be clear, Right now I am just worried about the score portion of the leader board. I know that seems unconventional to have a leader board without a name but right now I am just focused on the mechanics of how to create a leader board. I just want to have a way to have all the past scores appear a portion of my screen as someone else is playing. Also I want the leader board to not change even if the program is stopped and rebooted.


#9

sorry, but i think you should not have tried that in your " 1000 lines game code "
instead better in a extra little learning project.
and now, as you have more questions, you could just copy paste
that short ( but “runnable” ) code here and we could help you.

but a other point:
i play with something different and see that it can not be used exactly for your question,
still it deals with 2 things you might need:

  • a user interface for get user name ( and password ) and show login status
  • a settings file for that name / password and many more default program settings
  • and deal with the problem that when the file not exists the settings are in the program,
    written as default to ( new created ) file…
    so you are able just to copy the code ( without a file ) and the user start it up as initial default…

if you are interested?

settings file example v02
// make a default processing app with settings file
// but if it not exists, it will be generated.
// usually i like the TABLE way, but here try a different approach: string dict

// now need add a String like a user name / password
// but incl a way for the operator to type it in
// v0.2 take create_settings call out of if show 

// OPEN: a settings editor

String settingsfilename ="data/settings.txt";
StringDict setting;
String[] lines;
int clines;
//_____________________________________________________ check file exists and create file on error
BufferedReader reader;
PrintWriter writer;
//_____________________________________________________ operator input for test user...
import javax.swing.JOptionPane;
String answer, title = "input:", question="pls give me some words";
boolean userok= false, passwdok=false;

boolean show = true;  // diag

//_____________________________________________________
void setup() {
  size(300, 300);
  load_settings();     // check if file exists, if not, it will create a empty file ( and even data/ dir ) 
  // on empty file default settings will be loaded and saved
  login();
}

//_____________________________________________________
void draw() {
  background  (sett_i("bg_R"), sett_i("bg_G"), sett_i("bg_B"));
  fill(0);
  if ( userok && passwdok ) text("hallo "+sett_s("user"), width-80, height-10);
  else                      text(" not login ", width-80, height-10);
  fill        (sett_i("rect_fill_R"), sett_i("rect_fill_G"), sett_i("rect_fill_B"));
  stroke      (sett_i("rect_strk_R"), sett_i("rect_strk_G"), sett_i("rect_strk_B"));  
  strokeWeight(sett_i("rect_strk_W"));
  rect        (sett_i("rect_x"), sett_i("rect_y"), sett_i("rect_w"), sett_i("rect_h"));
}

//_____________________________________________________
int    sett_i(String skey) {   
  return int(setting.get(skey));
}

//_____________________________________________________
String sett_s(String skey) {   
  return setting.get(skey);
}

//_____________________________________________________
void create_default_settings() {  
  if (show) println("if empty file we need start with defaults settings");
  setting = new StringDict();

  setting.set("bg_R", "200");
  setting.set("bg_G", "200");
  setting.set("bg_B", "0");

  setting.set("rect_x", "10");
  setting.set("rect_y", "10");
  setting.set("rect_w", "20");  
  setting.set("rect_h", "30");

  setting.set("rect_fill_R", "0");
  setting.set("rect_fill_G", "200");
  setting.set("rect_fill_B", "0");

  setting.set("rect_strk_R", "0");
  setting.set("rect_strk_G", "0");
  setting.set("rect_strk_B", "200");

  setting.set("rect_strk_W", "3");

  setting.set("user", "");
  setting.set("passwd", "");  // later should use md5..
}

//_____________________________________________________
void write_settings() {   // write each setting to file using lines: varablename=variablevalue
  String[] theKeys;
  String theKey = "";
  String theValue = "";
  int clines = setting.size();
  theKeys = setting.keyArray();
  if (show) println("dict: setting, entries: "+clines);
  lines = new String [clines];
  for ( int i = 0; i < clines; i++ ) {
    theKey = theKeys[i];
    theValue = setting.get(theKey);
    lines[i] = theKey+"="+theValue;
    if (show) println(lines[i]);
  }
  saveStrings(settingsfilename, lines);
}

//_____________________________________________________
void create_settings() { // we found lines in settings.txt file but need to split and save to string dict.
  setting = new StringDict();
  for (int i = 0; i < clines; i++) {
    String[] lvals = split(lines[i], '=');
    setting.set(lvals[0], lvals[1]);
  }
  write_settings();
}

//_____________________________________________________
boolean file_exists() {
  boolean isok = false;
  reader = createReader(settingsfilename);
  if ( reader == null ) { 
    if (show) println("problem: no file: "+settingsfilename);
    // try to write one
    writer = createWriter(settingsfilename);
    writer.flush();
    writer.close();        // wow, that even creates a not existing /data/ dir
    if (show) println("created: pls. check: "+settingsfilename);
  } else { 
    isok = true;
  }
  return isok;
}

//_____________________________________________________
void load_settings() { 
  if ( file_exists() ) if (show) println("file ok ");
  lines = loadStrings(settingsfilename);
  clines = lines.length;
  if (show) { 
    println("read file: "+settingsfilename); 
    println("lines: "+clines); 
    for (String l : lines) println(l);
  }  
  if ( clines == 0 )  create_default_settings();
  else                create_settings();
}

//_____________________________________________________
String textwindow() {
  answer = JOptionPane.showInputDialog(null, question, title, JOptionPane.QUESTION_MESSAGE);
  answer = trim(answer);
  if ( answer == null ) answer = "";
  if (show) println(answer);
  return answer;
}

//_____________________________________________________
void ask_name(boolean writeit) {
  String instr = "";
  userok= false;
  passwdok=false;
  question="pls give me your name";
  instr = textwindow();
  if ( writeit ) { 
    setting.set("user", instr);  
    userok = true;
  } else {   // check correct
    if ( instr.equals(setting.get("user")) ) userok = true;
  }
  question="pls give me password";
  instr = textwindow();
  if ( writeit ) { 
    setting.set("passwd", instr); 
    passwdok = true;
  } else { // check correct
    if ( instr.equals(setting.get("passwd")) ) passwdok = true;
  }
  if ( writeit ) write_settings();
}

//_____________________________________________________
void login() {
  if ( sett_s("user").equals("") )  ask_name(true);   // get name and password and write to settings file
  else                              ask_name(false);  // get name and password and check
  if (show) println("user "+sett_s("user")+" pw "+sett_s("passwd"));
  if (show) println("login: user "+userok+" pw "+passwdok);
}
//_____________________________________________________

have fun!

if you want, there is a bigger version at my blog,
http://kll.engineering-news.org/kllfusion01/articles.php?article_id=154#here16


#10

If you only have scores and no name, you don’t need somthing as complex.

Your txt file would be something like this:

5000
4000
3000
2000
1000

Then, no need for the HighScoreTuplet class since it was used only to keep track of 2 values at the same time. Now it is only one so a simple array would do.

No need to split anymore since there is only 1 value on each line.

The code would simply be:

ArrayList<Integer> highScores;

void setup() {  
  highScores = new ArrayList<Integer>();
  
  BufferedReader reader = createReader("highScore.txt");
  String line = null;
  
  try {
    while ((line = reader.readLine()) != null) {
      highScores.add(Integer.parseInt(line));
    }
    reader.close(); // We close when there is no more lines
  } catch (IOException e) { // THis block is played if there is a problem when reading the file
    e.printStackTrace();
  }
  
  
  
  // This block is just to show the content of the high scores list in the console
  for (int i = 0; i < highScores.size(); i++) {
    println(highScores.get(i));
  }
}

#11

Whenever I start a new game, the text file filled with the scores becomes empty. Why is this?


#12

Were you able to resolve this problem?

Without inspecting the code closely, it two possibilities:

  1. saving the scores to a file while the scores array is empty (e.g. saving before loading)
  2. failing to correctly load the file, then saving the empty array back to the file (resulting in wiping the file)