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 80
s 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:
- 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?
- 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
How to Make Print() Accept the User Input in Same Line
Truth Value of a Series Is Ambiguous. Use A.Empty, A.Bool(), A.Item(), A.Any() or A.All()
Unpivot Multiple Columns With Same Name in Pandas Dataframe
Python: Import Cx_Oracle Importerror: No Module Named Cx_Oracle Error Is Thown
Typeerror: Image Data Can Not Convert to Float
How to Decompile a Compiled .Pyc File into a .Py File
How to Create Dynamic Workflows in Airflow
Pyspark Data Frame Converting False and True to 0 and 1
Parsing Outlook .Msg Files With Python
Sum a Column Based on Groupby and Condition
How to Convert a List of Dictionaries to Json in Python/Django
Calculate Sklearn.Roc_Auc_Score for Multi-Class
How to Read a Column Without Header from CSV and Save the Output in a Txt File Using Python
How to Convert a Datetime Object to Milliseconds Since Epoch (Unix Time) in Python
Index All *Except* One Item in Python
Python Pandas: Nameerror: Name Is Not Defined
Replacing Pandas or Numpy Nan With a None to Use With Mysqldb
How to Find the Closest Values in a Pandas Series to an Input Number