Bullrun Rounds: Game Data Analytics
Bullrun Rounds is a card-based game where each round produces a JSON record of player actions, card plays, and outcomes. The raw data is rich but inaccessible — sitting in per-round JSON files with no tooling to aggregate, compare, or visualize it.
The problem
Players and organizers had no easy way to analyze multi-round game data. Questions that should take seconds — who is winning across rounds, which cards perform best, how a specific player's strategy evolves — required manual inspection of individual JSON files. There was no leaderboard, no card-level statistics, no way to see trends across a session. The data existed; the insight did not.
Approach
The solution is a Python analytics toolkit built on pandas, numpy, matplotlib, and seaborn. The design is straightforward: load, normalize, aggregate, visualize.
The loader reads round JSON files and normalizes them into pandas DataFrames. Each round becomes a row with structured columns — players, cards played, scores, round outcome. This normalization step is the foundation; everything downstream operates on clean tabular data rather than raw nested JSON.
Aggregation functions compute player-level and card-level statistics across all loaded rounds. Player stats include win rate, average score, card frequency, and round-by-round performance. Card stats track how often each card appears, its win correlation, and average score contribution. These are not exotic metrics — they are the questions players actually ask, computed once and cached.
Visualization uses matplotlib and seaborn to produce the reports people want to see: leaderboards ranked by cumulative score, card performance heatmaps, player performance over time, and distribution plots for score spreads. Seaborn's statistical plotting handles the aggregation visuals; matplotlib covers the structured charts.
What was built
The toolkit delivers four core outputs:
- Automated leaderboard analysis. A single command loads all round files, computes cumulative standings, and ranks players by total score and win count. The leaderboard updates as new round files are added — no manual recalculation.
- Player statistics. Per-player breakdowns covering games played, win rate, average margin, most-used cards, and score trajectory across rounds. Each player gets a profile the toolkit can regenerate on demand.
- Card statistics. Every card tracked across the dataset: appearance frequency, win rate when played, average score contribution, and correlation with round outcomes. This surfaces which cards are actually strong versus which are just popular.
- Visual reports. Seaborn and matplotlib charts saved as image files — leaderboards, card heatmaps, player trend lines, score distributions. These are the deliverables organizers share with players after a session.
Results
The toolkit turns a folder of JSON files into a full analytics report in one run. What used to require manual file-by-file inspection now produces leaderboards, card performance tables, and visual charts automatically. Players get immediate feedback on their performance across rounds. Organizers get card balance data — which cards win too often, which are underplayed — without building spreadsheets by hand.
The pandas and numpy foundation handles the data wrangling efficiently; even with hundreds of rounds, aggregation runs in seconds. Seaborn's built-in statistical aesthetics mean the charts look clean without custom styling work.
Takeaway
Game data is only useful when it is queryable. Raw round logs sitting in files answer no questions. A thin analytics layer — load to DataFrames, aggregate with pandas, visualize with seaborn — converts a pile of JSON into leaderboards, card balance reports, and player insights. The toolkit is small because it does not try to be a platform. It reads data, computes the statistics people actually ask for, and draws the charts they want to see. That is enough.
