pythonleaderboard

Creating a leaderboard for offline game in Python


For a school project, I'm creating a game that has a score system, and I would like to create some sort of leaderboard. Once finished, the teachers will upload it to a shared server where other students can download a copy of the game, but unfortunately students can't save to that server; if we could, leaderboards would be a piece of cake. There would at most be a few hundred scores to keep track of, and all the computers have access to the internet.

I don't know much about servers or hosting, and I don't know java, html, or any other language commonly used in web development, so other related questions don't really help. My game prints the scoring information to a text file, and from there I don't know how to get it somewhere online that everyone can access.

Is there a way to accomplish such a task with just python?

Here I have the code for updating a leaderboard file (assuming it would just be a text file) once I have the scores. This would assume that I had a copy of the leaderboard and the score file in the same place.

This is the format of my mock-leaderboard (Leaderboards.txt):

Leaderboards

1) JOE  10001
2) ANA  10000
3) JAK  8400
4) AAA  4000
5) ABC  3999

This is what the log-file would print - the initials and score (log.txt):

ABC
3999

Code (works for both python 2.7 and 3.3):

def extract_log_info(log_file = "log.txt"):
    with open(log_file, 'r') as log_info:
        new_name, new_score = [i.strip('\n') for i in log_info.readlines()[:2]]

    new_score = int(new_score)
    return new_name, new_score

def update_leaderboards(new_name, new_score, lb_file = "Leaderboards.txt"):
    cur_index = None
    with open(lb_file, 'r') as lb_info:
        lb_lines = lb_info.readlines()
        lb_lines_cp = list(lb_lines) # Make a copy for iterating over
        for line in lb_lines_cp:
            if 'Leaderboards' in line or line == '\n':
                continue

            # Now we're at the numbers
            position, name, score = [ i for i in line.split() ]

            if new_score > int(score):
                cur_index = lb_lines.index(line)
                cur_place = int(position.strip(')'))
                break

        # If you have reached the bottom of the leaderboard, and there
        # are no scores lower than yours
        if cur_index is None:
            # last_place essentially gets the number of entries thus far
            last_place = int(lb_lines[-1].split()[0].strip(')'))
            entry = "{}) {}\t{}\n".format((last_place+1), new_name, new_score)
            lb_lines.append(entry)
        else: # You've found a score you've beaten
            entry = "{}) {}\t{}\n".format(cur_place, new_name, new_score)
            lb_lines.insert(cur_index, entry)

            lb_lines_cp = list(lb_lines) # Make a copy for iterating over
            for line in lb_lines_cp[cur_index+1:]:
                position, entry_info = line.split(')', 1)
                new_entry_info = str(int(position)+1) + ')' + entry_info
                lb_lines[lb_lines.index(line)] = new_entry_info

    with open(lb_file, 'w') as lb_file_o:
        lb_file_o.writelines(lb_lines)


if __name__ == '__main__':
    name, score = extract_log_info()
    update_leaderboards(name, score)

Some more info:


Solution

  • The easiest is probably to just use MongoDB or something (MongoDB is a NoSQL type database that allows you to save dictionary data easily...)

    You can use the free account at https://mongolab.com (that should give you plenty of space).

    You will need pymongo as well pip install pymongo.

    Then you can simply save records there:

    from pymongo import MongoClient, DESCENDING
    
    uri = "mongodb://test1:test1@ds051990.mongolab.com:51990/joran1"
    my_db_cli = MongoClient(uri)
    db = my_db_cli.joran1  # select the database ... 
    
    my_scores = db.scores  # this will be created if it doesn't exist!
    # add a new score
    my_scores.insert({"user_name": "Leeeeroy Jenkins", "score": 124, "time": "11/24/2014 13:43:22"})
    my_scores.insert({"user_name": "bob smith", "score": 88, "time": "11/24/2014 13:43:22"})
    
    # get a list of high scores (from best to worst)
    print(list(my_scores.find().sort("score", DESCENDING)))
    

    Those credentials will actually work if you want to test the system (keep in mind I added leeroy a few times).