Some Tricky Things About Creating a High Scores List
July 18th, 2009 by craigetMy project lately has been adding a Net-based high scores list to a game on the Android marketplace. While the game has a decent number of downloads, I think it gets kinda boring after a few plays through. Hopefully allowing players to compete with each other for the highest score will boost the fun/challenge (and thus the ratings and sales)
Allowing players to submit high scores to a global ranking raises quite a few issues that are absent in a non-networked high scores list. Following are some of the ideas I’ve come up with. If you’ve tried something similar, I’d love to hear your approach.
A couple of interesting issues:
1. WebView or Android UI
2. Routine networking challenges
3. Serialization
4. Storing the high scores on the server
5. Letting players choose names
6. Preventing hacks
There are two main ways to display high scores – either using a WebView to display an HTML high score list or building a regular Android UI. For now I’ve opted for the regular UI because it integrates better with the look of the app. However, that decision comes at a price — with a WebView/HTML UI, you can make changes on the webserver and it immediately affects every client. With the regular UI, if there’s a problem, you can’t push the fix. All you can do is publish an update and hope everyone downloads it.
There are two important things to remember about networking for a high scores list (or just in general) – first, the connection may be unavailable for a variety of reasons (the device may not be connected to the network, or the server could be down, etc). So the code needs to detect being unable to connect and handle it appropriately. Secondly, a connection could be slow or time-out. Together this means the connection should be handled in a separate thread or the UI will hang and Android will kill the app.
There are several reasonable ways to transfer the data. I found JSON to be the simplest encoding because the Java API is straightforward and it is only requires 1 line of PHP on the server to unpack a JSON structure into either an Object or an associate array. Nice!
Storing the high scores on the server is pretty easy – just drop them in a SQL database. I’m still struggling with the best way to handle the growth of the table. Depending on the number of players, the scores table may grow quite substantially (though, the growth should be somewhat bounded as the top scores trend higher and closer to the absolute limit). One possibility is to setup cron or some automated task to periodically wipe out scores below a certain threshold. Another possibility is to check each time a score is submitted whether anything needs to be deleted. Yet another possibility is to just keep all the scores and delete them manually from time to time, since there will be thousands or tens-of-thousands, not millions or billions. Fortunately, deciding what to keep is a server-only issue, so it is easy to keep everything now and postpone the decision based on actual usage and growth.
Another tricky issue is letting players choose names for the high score list. Since my game is appropriate for all ages, I don’t really want some bozo submitting filthy or offensive names. One approach is to not worry about it. Another approach is to try filtering the submitted names. Inevitably, any filtering is bound to miss something that’s offensive to someone. Furthermore, if the filtering is noticed, that turns it into a challenge for the player, who may now wonder: “what’s the most awful thing i can sneak past the filter”? While unlikely, that could get bad fast and having a high score list that requires daily moderation is no good. Another idea would be allowing only 3 letters for the names. That eliminates the 4-letter words, but initials-only makes a high score list less fun. Right now, I plan to wait and see if there is actually a problem before trying to fix it.
And saving the best for last — how to prevent someone from hacking the high scores list? Alas, it can’t really be done. No matter how you arrange the code, ultimately the player is responsible for truthfully submitting his own score. Because it is pretty easy to watch the data in-transit, the best you can do is to make it more complicated. One option is a checksum – send an additional parameter that is a salted hash of, say, the name and score. This is not bad and should deter half-hearted attempts, however the salt may be discoverable and any encryption or checksum is doomed to fail since the player controls the client. Another interesting option is submitting snapshot data of the game in-progress. However, that requires the server to know quite a bit about the game and what a valid state looks like. A super-crazy option would be storing all the game state on the server and only transferring player input (keypresses, screen touches) over the wire. That could actually work – if the game has an element of randomness, the only way to cheat would be to write a semi-intelligent bot. (If the game is deterministic, the player could just replay a winning series of moves) But.. the overhead of running all the logic and serving hundreds or thousands of simultaneous clients makes it unrealistic for a typical game. Since there is no monetary incentive to winning my game, I’m not too worried about this, but my optimism may be misplaced. Much more on this here.
Finally, an idea which I’ve dropped for the moment is a weekly high scores list (in addition to all-time high scores). This would make a high score achievable for a new or less determined player and prevents that inevitable stagnation as the all-time high scores get closer and closer to the maximum possible. One tricky part about a weekly list is that once again you need to rely on the client to be truthful about when each score was achieved. The current plan is to see how things go with the regular high score list, and then evaluate whether a weekly/daily/monthly list makes sense.
Eh, well. That’s what’s been on my mind lately. For something that sounds simple at first, there really are quite a lot of issues to consider in every part of the code. For now, the implementation is almost complete, so I can’t wait to see how it goes. If it works out well, I’ll try to follow up with actual code instead of random musings.

Warning: call_user_func(ich_comments_plugin_cb) [function.call-user-func]: First argument is expected to be a valid callback in /home/maldroid/public_html/craiget.com/wp-includes/comment-template.php on line 1308