How to fix my leaderboard for my Music Quiz - python

I'm making a Music Quiz for a school project.
I've made a working game however I cannot get the leaderboard (which should be text and is saved as leaderboard.txt) to show different names as it overwrites the previous name.
For example, if "Sam" was to get a score of 9 and "Ben" was to get a score of 3, it would show up as "Ben-3-9" which is not what I'm after.
I am trying to get my leaderboard to work like:
Sam - 9
Ben - 3
...
My code looks like this right now:
username = input("What is your username?")
# this will ask for the persons name
password = str(input("What is the password?"))
# this will ask for a password which has been set already
if password == "1234":
print("User Authenticated")
# if the password is incorrect, tell the user so and exit
elif password != "1234":
print("Password Denied")
exit()
# GAME
# Creating a score variable
score=0
x = 0
# Reading song names and artist from the file
read = open("songnames.txt", "r")
songs = read.readlines()
songlist = []
# Removing the 'new line' code
for i in range(len(songs)):
songlist.append(songs[i].strip('\n'))
while x == 0:
# Randomly choosing a song and artist from the list
import random
choice = random.choice(songlist)
artist, song = choice.split('-')
# Splitting the song into the first letters of each word
songs = song.split()
letters = [word[0] for word in songs]
# Loop for guessing the answer
for x in range(0, 2):
print(artist, "".join(letters))
guess = str(input("Guess the song!"))
if guess == song:
if x == 0:
score = score + 3
break
if x == 1:
score = score + 1
break
quit()
# Printing score, Then waiting to start loop again.
import time
print("Your score is", score)
print("Nice Work!")
time.sleep(3)
leaderboard = open("leaderboard.txt", "r+")
leaderboard.write(username + '-' + '{}'.format(score))
leaderboard.close()
leaderboard = open("leaderboard.txt", "r+")
leaderboardlist = leaderboard.readlines()
print(leaderboardlist)
leaderboard.close()
PS: this is not 100% my code I am trying to get help from different places as my school has not taught us how to code yet due to the pandemic closing down schools.

When you do this:
leaderboard = open("leaderboard.txt", "r+")
leaderboard.write(username + '-' + '{}'.format(score))
you open the leaderboard in read-and-write mode, but it will start writing at the beginning of the file, overwriting whatever is there. If you just want to add new scores to the leaderboard, the simplest would be to open the file in "append" mode "a":
with open("leaderboard.txt", "a") as leaderboard:
leaderboard.write(username + '-' + '{}'.format(score))
Alternatively, you could open the file in "r" mode, then first read all the lines (scores) in a list or dictionary, merge / update them with the current player's new score (e.g. adding to the last score, replacing the last score, or getting the max of the new and last score of that player), and then open the file again in "w" mode and write the updated scores. (Left as an exercise to the reader.)

The problem lies within the final few lines of code, where you are writing to the leaderboard.txt file.
Using "r+" indicates that you are updating (reading and writing) the file. Opening a file this way, moves the cursor at the beginning of the file. Therefore any attempt to write to the file will override whatever is already there.
The proper way to do it, is to open the file using "a" (or "a+" if you are planning to read as well). This is append mode and will move the cursor to the end of the file.
Some other general notes:
Use the with-as statement to handle closing the file automatically after you are done.
Use f-strings as opposed to string concatenation to increase readability
With that in mind, here's the code:
with open("leaderboards.txt", "a") as f:
f.write(f"{username}-{score}")
For more on files, check this question.
For more on f-strings, check this quite extensive overview of them.

Related

Reading from and printing records from a file

I need to be able to read from a file and print records if a variable entered is pre-existent in the file. I have tried to open the file as 'f' however that would only read the first line in the file, heres my code:
problem = input("Please select from one of these: sink, faucet, toilet, shower, heater, other: \n")
temporaryFile = open("plumberInfo.txt" , "r")
for row in temporaryFile:
record = row.split(",")
if record[6] == problem:
Pforename = record[1]
Psurname = record[2]
Pfee = record[3]
Pexperience = record[4]
Prate = record[5]
print("You have selected", Pforename, Psurname, "they have", Pexperience , "years of experience and they specialise in", problem, "\n")
else:
print("Invalid input")
plumberSearch() #This part isn't relevant
Also below I have attached some contents of the file:
743,Auryn,Smith,42.00,6,44.50,faucet,extra
583,Michael,Lanlow,25.00,8,75.00,sink,extra
731,Hanna,Taylor,42.00,14,55.00,heater,extra
981,Tomie,Agen,32.00,6,44.50,toilet,extra
I don't understand the problem as it worked fine for when I was searching by the ID ([record0]). There is no traceback error, it just states invalid input which means record[6] != problem, however it is equal.
When I try the code on my machine, printing record shows me that the last item contains a new line character at the end. Thus when you search for sink, you're essentially doing the search sink == sink\n, hence why you get invalid input.
Reading in the file also reads in the new line, and you need to be aware. You would need to remove it before doing the comparison.

How do I overwrite part of a text file in Python?

I have a text file that contains users username, password and highest score, however I want to overwrite their high score when the achieve a high score. However I only want to overwrite that specific value and no others.
This is my text file (called 'users.txt') :
david 1234abc 34 hannah 5678defg 12 conor 4d3c2b1a 21
For example, if 'hannah' gets a new score of 15, I want to change 12 to 15
Here is what I've tried:
# splitting the file
file = open("users.txt","r")
read = file.read()
users = read.split()
file.close()
# finding indexs for username, password and score
usernamePosition1 = users.index(user)
passwordPosition1 = usernamePosition1 + 1
scorePosition1 = passwordPosition1 + 1
file = open("users.txt","a")
# setting previous high score to an integer
player1OldScore = int(users[scorePosition1])
if player1Score > player1OldScore:
# setting in back to a str for text file
player1ScoreStr = str(player1Score)
# from here on i dont really know what i was doing
users.insert([scorePosition1],player1ScoreStr)
file.write(users)
print(player2 + "\n \nAchieved a new high score")
else:
print("\n \n" + player1 + " , you didn't achieve a new high score")
Your text file format is rather brittle. If David uses "hannah" as a password, then when Hannah tries to update her score, instead of locating her score (the sixth field), it will find her name as the second field and try using the fourth field (her name) as her score! Anyone using a space in their password would also cause problems, although a sneaky person could use “abcd 1000000” as their initial password and seed their initial score as one million.
These problems can be fixed by:
Using 1 line per user, or
Searching for user names only in the first of every 3 fields
And
disallowing spaces in passwords, or
coding/encrypting the passwords
In any case, you must read in and store the existing data, and then write out the entire dataset to the file. The reason is the data is not stored in fixed-width fields. A score changing from 99 to 100 will require moving all subsequent characters of the file one character forward, which is not a modification you can make to the file without actually reading and rewriting it in it’s entirety.
You are going to need to find and replace the strings. This means you will need to format the users.txt file in a way that you are able to simply replace the user data. If you have each user and their data on a seperate line this should be fairly easy:
import string
s = open("users.txt","r+")
for line in s.readlines():
print line
string.replace(line, 'hannah 5678defg 12','hannah gfed8765 21')
print line
s.close()
You have the right idea (note that I your code will only work for 1 user, but I'll let you figure out how to extend it), but there is no way to change the file without writing the entire file.
As such I recommend something like this:
...
file = open("users.txt","w") # change this from 'a' to 'w' to overwrite
player1OldScore = int(users[scorePosition1])
if player1Score > player1OldScore:
users[scorePosition1] = str(player1Score) # change the score
file.write(" ".join(users)) # write a string with spaces between elements
print(player2 + "\n \nAchieved a new high score")
...

Finding the smallest number in a .dat file containing multiple data types | Python

Context: I have written a program that asks the user to enter the name and score (integer) for a user-defined quantity of players. The program then formats, slices and stores the values in a file named golf.dat
Issue: I am trying to expand my program to allow it to identify the player with the lowest score and print the name and score of the lowest scorer.
My code:
def playerDataInput(playerQuantity):
outputFile = open("golf.dat", "w")
for currentPlayer in range (1, playerQuantity + 1):
playerName = (input("Please enter player " + format(currentPlayer, "d",)+"'s name: "))
playerScore = (input("Please enter player " + format(currentPlayer, "d",)+"'s score: "))
outputFile.write(playerName + "\n")
outputFile.write(str(playerScore) + "\n")
outputFile.close()
def playerDataOutput():
inputFile = open("golf.dat", "r")
playerName = inputFile.readline()
while playerName != "":
playerScore = inputFile.readline()
playerName = playerName.rstrip("\n")
playerScore = playerScore.rstrip("\n")
print(playerName + ("'s score was:"), playerScore)
playerName = inputFile.readline()
inputFile.close()
def lowestScorer():
integers = open("golf.dat", "r")
lowestScore = 0
for score in integers:
if lowestScore >= int(score.strip()):
lowestScore = int(score.strip())
integers.close()
print("The lowest score was: ", lowestScore)
I've tried: I have tried (in vein) to write a function (lowestScorer) to extract and display the lowest value, but it didn't occur to me at first, but this is obviously going to fail, based on the way my data is stored.
Where you can help: suggest if there is any Pythonic way of adapting my code (rather than re-writing), to allow my program to identify and display the name and scorer of the lowest scorer / integer, saved in my golf.dat file?
My suspicion is that I should have written this program with two lists that hold names and scores respective and then written these to golf.dat (for easy extraction and analysis) or created these two lists (as sublists, thus holding names and integer score values separately) but gone a step further and saved them within a master list.

My program is printing value following the order of my .txt file and I don't want that to happen

I want to prompt the user to input specific data from a text file(keys) so my dictionary can give the value for each of them.
It works like this:
fin=open('\\python34\\lib\\toys.txt')
toys = {}
for word in fin:
x=fin.readline()
x = word.replace("\n",",").split(",")
a = x[0]
b=x[1]
toys[a]=str(b)
i = input("Please enter the code:")
if i in toys:
print(i," is the code for a= ", toys[i],)
else:
print('Try again')
if i == 'quit':
break
but it prints 'try again' if I input a random key from my list. (which is the following:
D1,Tyrannasaurous
D2,Apatasauros
D3,Velociraptor
D4,Tricerotops
D5,Pterodactyl
T1,Diesel-Electric
T2,Steam Engine
T3,Box Car
T4,Tanker Car
T5,Caboose
B1,Baseball
B2,Basketball
B3,Football
B4,Softball
B5,Tennis Ball
B6,Vollyeball
B7,Rugby Ball
B8,Cricket Ball
B9,Medicine Ball
but if I do it in order it works. How can I fix this program so I can input any key at any time and it will still print its corresponding value?
You need to read in the whole file before prompting for your search term. So you'll need two loops -- one to get the whole data in, and a second loop to search through he data.
Here's what your updated code will look like. I replaced the file input with an array so that I could run it using a web tool:
fin=['D1,Tyrannasaurous','D2,Apatasauros','D3,Velociraptor' ]
toys = {}
for word in fin:
x = word.replace("\n",",").split(",")
a = x[0]
b=x[1]
toys[a]=str(b)
while 1:
i = input("\nPlease enter the code:")
if i in toys:
print(i," is the code for a= ", toys[i],)
else:
print('\nTry again')
if i == 'quit':
break
Output here: https://repl.it/BVxh
To read the file into dictionary:
with open('toys.txt') as file:
toys = dict(line.strip().split(',') for line in file)
To print values corresponding to the input keys provided by a user from a command-line interactively until quit key is received:
for code in iter(lambda: input("Please enter the code:"), 'quit'):
if code in toys:
print(code, "is the code for toy:", toys[code])
else:
print(code, 'is not found. Try again')
It uses two-argument iter(func, sentinel).

Allowing a user to restore a deleted item from a python list

I am writing a program that will allow a user to decode a word (an encoded football team) that has been imported from a text file. Another text file contains the decoded football team. The user will be allowed to take a guess at decoding the word and selecting letters to replace in the word until he guesses them all correctly (then game over).
Thanks to some help I received here I was able to adapt some code that allowed me to record each character swap the user made by appending both the old and new letters through enumeration to an indices list.
I need the user to be able to choose to delete a previous character swap and that is where I am falling down at the minute. I know how to undo the previous change (thanks to some help here) but I want the user to be able to see the previous swaps listed in one go and then choose a letter to restore to its original place in the decoded letter. Here is the main function of the code so far:
def play():
global encoded
global plaintext
x = 40
for i in range(x):#give the user 40 goes maxiumum
print("\nThe encoded team is {0}\n".format("".join(encoded)))
choose = input("What character would you like to replace?")
indices = []
for i, j in enumerate(encoded):
if j == choose:
indices.append(i)
replace = input("What character would you like to replace it with")
for i in indices:
encoded[i] = replace
changes.append((choose, replace, indices))
for choose, replace, indices in changes:
print("Replaced '{0}' with '{1}'".format(choose, replace))
undo = input("Would you like to undo any changes - type 'undo'? ").lower()
if undo == "undo":
print("Here are the previous letters you have swapped ")
for i , j in enumerate (changes):
for c in changes:
for i in indices:
print(choose, replace)
Here are my text file calls and list definitions:
with open("football.txt","r") as file_one:
Encoded_Team = file_one.read()
with open("football_Solved.txt","r") as file_two:
Team = file_two.read()
encoded = list(Encoded_Team)
plaintext = list(Team)
changes = []
print("\nThe encoded team is {0}\n".format("".join(encoded)))
print("You will have 15 goes maxium")
menu()
Here is the menu:
def menu():
play_game = print("1. Play the game")
instruc = print("2. Instructions")
question = input("Enter choice")
if question == "2":
print("You will given a list of coded words, you have to replace the symbols to letters to get the word")
print("\n")
menu()
else:
play()
I am trying to develop the following piece of code from the main function so it allows the user to choose a previous character swap to undo - I know I need to enumerate but I am just not able to piece it together. Any ideas?
undo = input("Would you like to undo any changes - type 'undo'? ").lower()
if undo == "undo":
print("Here are the previous letters you have swapped ")
for i , j in enumerate (changes):
for c in changes:
for i in indices:
print(choose, replace)
I have added the following code to display the previous pairings chosen:
if undo == "undo":
for index, change in enumerate(changes):
chosen, replaced, indices = change
pairs.append(change)
for change in pairs:
print(chosen, replaced)
But instead of displaying the two last pairing, it will display the last pairing twice
What character would you like to replace?M
What character would you like to replace it withL
Replaced 'M' with 'L'
Would you like to undo any changes - type 'undo'?
The encoded team is Ljwfsqppm
What character would you like to replace?j
What character would you like to replace it withi
Replaced 'M' with 'L'
Would you like to undo any changes - type 'undo'? undo
j i
j i
Replaced 'j' with 'i'
Would you like to undo any changes - type 'undo'?
Any idea?

Categories