viernes, 30 de mayo de 2014

Guess the number, part 4

Almost there!

The high score system I've been trying to implement has proven to be quite an interesting exercise. I thought I had an issue with pickle, and kept running into different errors. Turns out that the true problem lied with the file input/output part of the code.

I came up with this function:

def CheckHighScores(score):
    try:
        scoresFile = open('scores','rb')
    except:
        scoresFile = open('scores','wb+')

    if not scoresFile.read(1):
        scoresList = []
    else:
        scoresList = pickle.load(scoresFile)
    scoresFile.close()

    if not scoresList:
        EnterHighScore(score,scoresList)
    else:
        for counter,i in enumerate(scoresList):
            if counter == 3:
                break
            if score >= i.score:
                EnterHighScore(score,scoresList)
                break



The try block purpose is to try and open the file called 'score' in binary reading mode (because pickle reads binary). The problem is that if the file, for any reason, doesn't exist, the program would crash. The way to create a file if it's not there is opening it in writing mode (appending mode works too, if I'm not mistaken). I use 'wb+' because what I really want to do is read the file, not actually write on it. wb+ means 'write and read in binary mode'.

My big mistake was in the following if block. I searched for a way to find out if a file was empty, and found this method. The point is to try to read the first character of the file. If there are no characters, then the file is empty and there's nothing to read from it. If I tried to load data from an empty file, the program would crash. The important part here, the one with the mistake, is that read() moves a thing called the read pointer of the file. And pickle doesn't like that at all! Since the read pointer is no longer at the beginning of the pickled object, pickle can't recognize it, and sends out an error:

UnpicklingError: Invalid load key'(some character)'

I couldn't find a way to fix this. I went to Stack Overflow to post my question, and luckily I got an answer very quickly. Two of the ways to tackle this problem were:

- Add a seek(0) line after  if not scoresFile.read(1):
- Reformat as a try block, This way the read pointer doesn't get involved.

Personally, I like the first one better because it doesn't allow for an error to occur, so I'm going to use that. The second one looks pretty good, though. The code looks neater.

The last part of this function is the one that actually checks the high score list, determining if the player gets makes the list or not.

    if not scoresList:
        EnterHighScore(score,scoresList)

checks if the list is empty. This would happen at first, when nobody has ever played the game.

        for counter,i in enumerate(scoresList):
            if counter == 3:
                break

This is a very interesting method of counting loops in python. What this means is that the high scores list only holds three names. Before we get the chance of checking a fourth one, the loop gets broken.

            if score >= i.score:
                EnterHighScore(score,scoresList)
                break

Of course, this just checks if the player's score is equal or higher than those on the list.

For completeness, here's the EnterHighScore() function code:

def EnterHighScore(score,scoresList):
    name = input("Enter your name: ")
    newPlayer = player(name,score)
    scoresList.append(newPlayer)
    scoresFile = open('scores','wb')
    pickle.dump(scoresList,scoresFile)
    scoresFile.close()

    for i in scoresList:
        print(i.name + ' - ' + str(i.score))

Now I've got everything I need to make the game work with all its features. I'll post the finished code in a few days.

No hay comentarios:

Publicar un comentario