This is a score tracking system developed for a group ping pong environment. It was originally written in Python and runs on a Raspberry Pi. I have rebuilt the app in React, and have hosted it online. You can now run this project directly in your browser by going here.
The system uses the Elo rating system to dynamically adjust player scores based on game outcomes, rewarding wins against higher-ranked opponents. Players' scores are tracked over time, with both monthly and lifetime win/loss records. The system offers a user-friendly way to manage players, view leaderboards, and track ongoing games.
It also includes management and security functionalities like password-protected player profiles, the ability to add and delete user profiles, and the ability to manually edit a score.
.png)
Score Formula and Tracking
The formula to track the score is a bit complex, as it factors in the total amount won or lost, and the "expected outcome" of the other players. If you were expected to win and get beat by an underdog, you will lose a lot more than if you lose to someone who is ranked closely to you. Additionally, if you lose by a lot, you lose more points than if you lost by 1 or 2 game points.
Score change is calculated by:
K = 70 + point_difference*6
# Calculate the K factor based on the point difference
if player_is_unranked and opponent_is_unranked:
K = K*1.15 # Both players are unranked, 15% increase in volatility
elif player_is_unranked:
K = K*1.15 # 15% increase in volatility for unranked player
elif opponent_is_unranked:
K = 20 # The ranked player only gains/loses a maximum of 20 points
else:
pass # Both players are ranked, normal scoring applies
result = 1 if won else 0
expected_score = 1 / (1 + 10 ** ((opponent.score - self.score) / 400))
score_change = K * (result - expected_score)
self.score += score_change
self.games_played += 1
To change the volatility of the score calculations, increase K.
To view a player's lifetime score, and see their score over time, double-click on a player name. You will see a display like this:
.png)
Note that lifetime score is distinct from "monthly" score. For more info on that, see admin controls.
The Scoreboard
There is a scoreboard display that takes up the screen while a game is in progress. This can be controlled by key inputs or with a mouse. When a game ends from this state, the game history, player scores/rankings, and data display are all updated automatically.
.png)
Player Accounts
I set up a pretty basic player account system where you can create a profile with a password, and you need to enter that password each time you want to play. This is to prevent a bad actor from coming in and creating a lot of artificial wins/losses for certain players, but it is a pretty weak security feature. In the original Python version, passwords were stored as plaintext in players.txt, so they only served as a basic deterrent against malicious behavior.
The Software (Legacy Python Version)
This section describes the original Python version, which I wrote when Ping Pong Pi was a locally run program. I have since rebuilt the app in React, so the file structure is very different. If you connect your Google account to the website, it actually stores your game data on the cloud, which is cool. I have polished some of this stuff, but feel free to check out the web app GitHub repo if you are interested in looking at the current code.
The older code, built in Python, is in the original Ping-Pong-Pi repo.
Running the Program
To use the program, just run ping_pong.py, and load in the scores. I would recommend loading the program with the test files (included in the GitHub repo), as it can have some weird behaviors/crash when trying to load in game history and there are only blank files. Once you create a player profile, feel free to delete the dummy accounts. I never ended up fixing this, since there wasn't any demand for it.
Here's an interactive view of the Ping-Pong-Pi project directory structure:
- 📁 game_data
- 📁 modules
- 📄 README.md
- 📄 ping_pong.py
- 📄 settings.py
Note that all of the game history files are stored in the same directory as the primary program engine. I attempted to break up the functions of the program into modules, but a majority of the logic stayed in ping_pong.py.
This program was built for a TV display, where many people could watch and play. It was set up in a room where it was always on; ping pong was the only thing that happened in that room. I say this to explain that this program is not optimized for smaller screen sizes, and it is intended to stay on between games. Some of the features will be lost if the program is turned off and on between games.
Controls and Usage
All of the game controls are mapped to number keys (this is because I controlled the program with a numpad; see "The Hardware" for more on that). These controls can be found/modified in keyPressEvent() in scoreboardDialog.py. All of the controls have on-screen buttons as well, but here is the key mapping.
.png)
Admin Controls
Certain functions are behind an admin passcode, like the ability to manually set a score or delete players. To set the admin password, it needs to be hard-coded into ping_pong.py, in open_admin_controls_dialog().
The admin controls popup is pictured here as well. The "reset all scores" button does not delete lifetime scores; it just sets the current game to a blank slate. I use this to implement a "monthly score" feature, but you could reset the scoreboard as little or as frequently as needed.
.png)
The Hardware
This runs on a Raspberry Pi 3, which is just what I had available when I started this mini-project. I originally intended to wire buttons to the Pi, so you could hit buttons to change the score mid-game. I ended up using a Bluetooth numpad, as this was much easier to set up with the Python scripts. I painted numbers (like +1 and -1) to correspond to player actions, but there was not much tech customization that went into this. I am using a mouse & keyboard Bluetooth bundle for the main menu screen, which allows users to use a mouse to select their profile and check out game scores and history.
.png)
.png)
.png)