Keeping High Scores in a Text File

Keeping high scores in a text file

I'm assuming your goal is to read in the high scores and only add those scores that were made by a new player. If so the questions you have to ask are:

  • How do you handle an old player setting a better score than before?
  • How do you deal with two players with the same name having scores?
  • How do you want to display your high scores?

Personally I wouldn't do this in a text file, but write it in a dictionary and pickle it.

import pickle

high_scores = {"Adam Smith": 65536, "John Doe": 10000}
with open("highscores.pkl","wb") as out:
pickle.dump(high_scores, out)

Then when you have to write a new score:

import collections

Score = collections.namedtuple("Score", ["name","score"]) # just to make things easy
new_score = Score("Joe Schmoe",12000)

with open("highscores.pkl","rb") as in_:
high_scores = pickle.load(in_)
if new_scores.name not in high_scores:
high_scores[new_scores.name] = new_scores.score
with open("highscores.pkl","wb") as out:
pickle.dump(high_scores, out)

This will also help when displaying high scores, because you can do something like:

print("{{TITLE:^{PAGE_WIDTH}}}".format(PAGE_WIDTH=80).format(TITLE="HIGH SCORES"))
print("-" * 80)
for name,score in high_scores.items():
print("{{name:>{col_width}}} | {{score:<{col_width}}}".format(col_width=(80-3)//2).format(name=name, score=score))

The formatting in this bit is a bit overkill for your use case, but if you need to display this on a smaller screen (with fewer columns per page) you'll thank me later! Replace all the 80s with a constant and put your columns-per-page in the constant, something like MAX_WIDTH maybe. Easy peasy.

Read/write txt file for saves

Let me preface by saying I am not familiar with the best practices for storing game related information on a filesystem. That being said, it sounds like you are trying to learn as you develop this, so with that in mind, I would suggest starting out with writing to a simple .txt file.

The basics can actually be found on SO already:

How to create and write to a txt file:
How do I create a file and write to it in Java?

How to read from a txt file:
Reading and displaying data from a .txt file

And the Java tutorials for good measure: https://docs.oracle.com/javase/tutorial/essential/io/file.html

What I would do is:

1. Figure out when you want to trigger a write.

When do you want to update your high scores file? To me, it looks like this would be in your Gameplay class around ln 158, where you determine that the game has ended:

//Change to GameOverEasy state if gameOver is true
if(gameOver == true){


2. Figure out when you need to read in your file to populate Highscores. Poking around your code in pastebin, that to me seems like something you would want to do on startup in the main method of your Blop class, before you start loading game states/looping:

        public static void main(String[] args) throws IOException{

AppGameContainer appgc;
try{
appgc = new AppGameContainer(new Blop(NAME));

//Window size
appgc.setDisplayMode(960, 640, false);
appgc.setShowFPS(false);
appgc.setAlwaysRender(true);
appgc.setTargetFrameRate(60);
appgc.setVSync(true);
Display.setIcon(new ByteBuffer[] {
new ImageIOImageData().imageToByteBuffer(ImageIO.read(new File("res/images/general/Icon16.png")), false, false, null),
new ImageIOImageData().imageToByteBuffer(ImageIO.read(new File("res/images/general/Icon32.png")), false, false, null)
});

//TODO: Read in high scores file and populate Highscores class

appgc.start();
}catch(SlickException e){
e.printStackTrace();
}


3. Figure out how to format your text file. You are ordering the scores already, so you could store them that way as well. Either saving one score per line or using a delimiter like "," or "|" would work with what you currently have.


Start with the simple text file, and change to something else if it suits your needs. If this is a test/learning project, I strongly recommend you keep it simple and stick with a simple .txt file until you wrap your head around it a bit more

A few things to keep in mind:

  1. You are going to run into a lot of exception handling. When reading that file in, you will need to determine if your game should fail to start because you could not load the high scores file? On the other side, is it a critical error when you fail to write to that file?
  2. Always be closing

EDIT:
Regarding your followup questions, you want to use the actual name of the file you are using. Javadocs are your friend. Regarding your second question, check out some other SO posts. It's pretty well covered.

How to read, write and update of your game highscore in pygame from/to file.txt saved.?

I worked with your code, but updating it made the code more complicated. I thought it may be easier to provide a short function to update the score file.

The main steps:

  • Open the existing score file (scores are on single line separated by space)
  • Split the line and convert the scores to integers
  • If the current score is already included, just exit the function
  • Add the current score the score list
  • Sort the list and update the score file

Here is the code:

def update_high_scores():
global score, scores
filename = r"c:/tmp/High-Score1.txt" # file must exist
with open(filename, "r") as file:
line = file.readline() # scores are one line
high_scores = [int(s) for s in line.split()] # read scores as integers
if score in high_scores: # if current score already in high scores
return # no update needed

high_scores.append(score) # add current score

high_scores.sort() # sort scores (low - high)

with open(filename, "w") as file: # updates score file
for high_score in high_scores[::-1]: # write scores in reverse (high - low)
file.write(str(high_score) + " ")

Searching Text Files - High Scores (using Python)

I am doing it only using pure python

First you need to load the file

data = ""
with open(filename, "r") as f:
data = f.read()

You need so keep the best username and his score

best_username = ""
best_score = -1

Now go through each line

for line in data.split("\n"):
username, score = line.split("|") # reads user and his score from line
if score > best_score: # best user we encounterd so far
best_username = username
best_score = score

The result is in best_username. This gets you first user with the highest score

mary|4
john|5
lisa|3
dana|5

returns john

EDIT:

there may be blank line at the end of file, to ignore it use:

for line in data.split("\n"):
if "|" not in line: # skips invalid lines
continue
username, score = line.split("|") # reads user and his score from line
if score > best_score: # best user we encounterd so far
best_username = username
best_score = score

EDIT 2:

You need to convert score to int, should have tested my code

for line in data.split("\n"):
if "|" not in line: # skips invalid lines
continue
username, score = line.split("|") # reads user and his score from line
score = int(score)
if score > best_score: # best user we encounterd so far
best_username = username
best_score = score

Python: is it possible to set a high score without a text file?

At the end of the day, you need to store the score in one type of database or the other, whether it's a file-based database or relational or any other. For one execution of your code, you can certainly keep it in the RAM, but for persistence, there's no way around it. If your use case is simple, you may consider sqlite instead of explicit file-based storage.

Reading Highscorelist from text file into a textBox sorted by score

I would first use a tab as the separator for your player Name and Score as it is easier to parse. Create a struct holding the score and name, then read in the contents of the file, create the list, sort and output.

    //struct to hold the values
struct highScoreEntry
{
public string PlayerName;
public string Score;
public highScoreEntry(string playerName, string playerScore)
{
PlayerName = playerName;
Score = playerScore;
}
}



List<highScoreEntry> allScores = new List<highScoreEntry>();
using (System.IO.StreamReader sr = new StreamReader(@"Path to file"))
{
//skip the first line name and score titles
string line = sr.ReadLine();
while (!sr.EndOfStream)
{
line = sr.ReadLine();
string[] lineParts = line.Split(new string[] { "\t" }, StringSplitOptions.RemoveEmptyEntries);
allScores.Add(new highScoreEntry(lineParts[0], lineParts[1]));
}

}
'sort in descending order using OrderByDescending
List<highScoreEntry> sortedList = allScores.OrderByDescending(i => i.Score).ToList<highScoreEntry>();
string highScoreText = "Player\tScore\r\n";
foreach (highScoreEntry item in sortedList)
{
''can be written directly into the textbox but for the example write it to a string
highScoreText += item.PlayerName + "\t" + item.Score + "\r\n";
}
//add it to the textbox
HighscoreRichTextBox.Text = highScoreText;

}


Related Topics



Leave a reply



Submit