views:

582

answers:

5

I'm making a stupid little game that saves your score in a highscores.txt file.

My problem is sorting the lines. Here's what I have so far.

Maybe an alphanumeric sorter for python would help? Thanks.

import os.path
import string

def main():
    #Check if the file exists
    file_exists = os.path.exists("highscores.txt")

    score = 500
    name = "Nicholas"

    #If the file doesn't exist, create one with the high scores format.
    if file_exists == False:
     f = open("highscores.txt", "w")
     f.write('Guppies High Scores\n1000..........Name\n750..........Name\n600..........Name\n450..........Name\n300..........Name')

    new_score = str(score) + ".........." + name

    f = open("highscores.txt", "r+")
    words = f.readlines()
    print words

main()
+4  A: 

after words = f.readlines(), try something like:

headers = words.pop(0)

def myway(aline):
  i = 0
  while aline[i].isdigit():
    i += 1
  score = int(aline[:i])
  return score

words.sort(key=myway, reverse=True)

words.insert(0, headers)

The key (;-) idea is to make a function that returns the "sorting key" from each item (here, a line). I'm trying to write it in the simplest possible way: see how many leading digits there are, then turn them all into an int, and return that.

Alex Martelli
Thanks Alex! But when I insert that in my code, I'm getting an error:SyntaxError: Non-ASCII character '\xc2' in file read.py on line 24, but no encoding declared; see http://www.python.org/peps/pep-0263.html for detailsAny ideas what that's from? Thanks again!
Nicholas
@Nicholas, there's no non-ASCII text (and in particular no `0xc2` -- in Latin-1, that would be an uppercase-A with a circumflex) in the code I posted, and so of course I have absolutely no idea how you managed to get one into _your_ code. If you can't spot it in your own code (?!), maybe post that code in a question -- but this really has zero to do with _this_ question, which I appear to have answered satisfactorily, so I suggest you make it a _separate_ question.
Alex Martelli
A: 

Doing a simple string sort on your

new_score = str(score) + ".........." + name

items isn't going to work since, for example str(1000) < str(500). In other words, 1000 will come before 500 in an alphanumeric sort.

Alex's answer is good in that it demonstrates the use of a sort key function, but here is another solution which is a bit simpler and has the added advantage of visuallaly aligning the high score displays.

What you need to do is right align your numbers in a fixed field of the maximum size of the scores, thus (assuming 5 digits max and ver < 3.0):

new_score = "%5d........%s" % (score, name)

or for Python ver 3.x:

new_score = "{0:5d}........{1}".format(score, name)

For each new_score append it to the words list (you could use a better name here) and sort it reversed before printing. Or you could use the bisect.insort library function rather than doing a list.append.

Also, a more Pythonic form than

if file_exists == False:

is:

if not file_exists:
Don O'Donnell
A: 

Hi Nicholas, I guess something went wrong when you pasted from Alex's answer, so here is your code with a sort in there


import os.path

def main():
    #Check if the file exists
    file_exists = os.path.exists("highscores.txt")

    score = 500
    name = "Nicholas"

    #If the file doesn't exist, create one with the high scores format.
    if file_exists == False:
        f = open("highscores.txt", "w")
        f.write('Guppies High Scores\n1000..........Name\n750..........Name\n600..........Name\n450..........Name\n300..........Name')

    new_score = str(score) + ".........." + name +"\n"

    f = open("highscores.txt", "r+")
    words = f.readlines()

    headers = words.pop(0)

    def anotherway(aline):
      score="" 
      for c in aline:
          if c.isdigit():
              score+=c
          else:
              break
      return int(score)

    words.append(new_score)
    words.sort(key=anotherway, reverse=True)

    words.insert(0, headers)

    print "".join(words)

main()
gnibbler
+1  A: 

I'd like to encourage you to store your high scores in a more robust format. In particular I suggest JSON.

import simplejson as json  # Python 2.x
# import json  # Python 3.x

d = {}
d["version"] = 1
d["highscores"] = [[100, "Steve"], [200, "Ken"], [400, "Denise"]]
s = json.dumps(d)
print s
# prints:
# {"version": 1, "highscores": [[100, "Steve"], [200, "Ken"], [400, "Denise"]]}


d2 = json.loads(s)
for score, name in sorted(d2["highscores"], reverse=True):
    print "%5d\t%s" % (score, name)

# prints:
#  400  Denise
#  200  Ken
#  100  Steve

Using JSON will keep you from having to write your own parser to recover data from saved files such as high score tables. You can just tuck everything into a dictionary and trivially get it all back.

Note that I tucked in a version number, the version number of your high score save format. If you ever change the save format of your data, having a version number in there will be a very good thing.

steveha
+1: or yaml, if you would like it to be more human readable (and do not need to send over the wire)
van
Or you could be traditional and use the Python `pickle` module. That can save any Python data type, and it's included in every Python install. Not very human-readable though.
steveha
A: 

What you want is probably what's generally known as a "Natural Sort". Searching for "natural sort python" gives many results, but there's some good discussion on ASPN.

Alec Thomas