A blazing-fast CLI that generates completely random soccer matches on the spot — or run scripted matches with the
.tsrc (Tiny Soccer Sim Rust C) language.
- Rust 100%
| src | ||
| tests | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| gnu-bsd-soccer.tsrc | ||
| README.md | ||
| scripted_match.tsrc | ||
| test_match.tsrc | ||
tssr — Tiny Soccer Simulator Rust
A blazing-fast CLI that generates completely random soccer matches on the spot — or run scripted matches with the .tsrc (Tiny Soccer Sim Rust C) language.
Build
cargo build --release
The binary will be at target/release/tssr.
Usage
./tssr # random match (table output)
./tssr --json # random match (JSON output)
./tssr --script match.tsrc # scripted match (table output)
./tssr --script match.tsrc --json # scripted match (JSON output)
./tssr --help # show usage info
Shebang
.tsrc scripts can be run directly with a shebang:
#!/usr/bin/env tssr
string home = "Team A";
string away = "Team B";
// ...
match(home, away);
chmod +x match.tsrc
./match.tsrc
Output
Table mode (default)
╔════════════════════════════════════════╗
║ TSSR MATCH RESULT ║
╠════════════════════════════════════════╣
║ Man Page City 2 - 1 Libre Pool║
╠════════════════════════════════════════╣
║ ║
║ Shots 10 8 ║
║ On Target 4 3 ║
║ Possession 55% 45% ║
║ ║
╠════════════════════════════════════════╣
║ Goals: ║
║ Man Page City: Marco Smith (23') ║
║ Man Page City: Leo Brown (67') ║
║ Libre Pool: Dan Garcia (45') ║
╚════════════════════════════════════════╝
JSON mode (--json)
{
"home": {
"team": "Man Page City",
"score": 2,
"shots": 10,
"shots_on_target": 4,
"possession": 55,
"scorers": [
{"player": "Marco Smith", "minute": 23},
{"player": "Leo Brown", "minute": 67}
]
},
"away": {
"team": "Libre Pool",
"score": 1,
"shots": 8,
"shots_on_target": 3,
"possession": 45,
"scorers": [
{"player": "Dan Garcia", "minute": 45}
]
}
}
.tsrc Scripting Language
.tsrc (Tiny Soccer Sim Rust C) is a minimal C-like DSL for defining teams, players, and match events programmatically.
Language Reference
// Declare a team variable
string var_name = "Team Name";
// Assign a player to a team (by variable or literal)
players["Player Name"] = var_name;
players["Player Name"] = "Team Name";
// Script a goal: minute (1-90), team (var or literal), player (literal)
goal(45, var_name, "Player Name");
goal(45, "Team Name", "Player Name");
// Select teams for the match (required)
match(var_home, var_away);
Rules
- Variables must be declared with
stringbefore use match()directive is required — references variable namesplayers[]references team names (values), not variable names — but variables are resolved automaticallygoal()arguments:minute, team, player— team can be variable or literal- All semicolons are required
//for single-line comments- Strict validation: any inconsistency produces an error with a helpful message and exits immediately
Validation Errors
The parser is strict — it will fail with a clear message if:
- A variable is used before being declared
- A variable is defined twice
- A player is added to a team that isn't in
match() - A player is added to the same team twice
- A goal references a player not on that team
- A goal references a team not in the match
- A goal minute is outside 1–90
- The same player scores at the same minute twice
- A match team has no players assigned
match()references the same team for both home and away
Scripted Goals
When goal() is used, the match becomes deterministic:
- Score is derived from the count of scripted goals per team
- Goal scorers and minutes are exactly as specified
- Shots and shots-on-target are floored at the goal count
- Possession remains randomized
Without goal(), everything is fully randomized.
Team Names (Random Mode)
When no script is provided, teams are randomly selected from PES-style parodies referencing free software and open source:
- Man Page City, Libre Pool, ArsenAL, Shellsea, TomThumb FC
- Real Madread, BarcelON, BayErR, Door Mount, Inter Mission
- Man Unixited, A-JaX, CellTick, RanGERS, LaZIO, RomaAEM
- Port OS, BenFICA, Fine Node, AC M1Lan, PSGROOT
- Free BSD Athletic, Kernel Panic, Tor Valdes, Debian United
- Arch Lisbon, NixOS City, Fork Enoord, Branchand FC, Merge Conflict
Stats Included
- Score
- Shots & shots on target
- Possession percentage
- Goal scorers with minute of goal
Example Files
| File | Description |
|---|---|
scripted_match.tsrc |
GNU United vs BSD Athletic — 5 scripted goals with mixed variable/literal team references |
gnu-bsd-soccer.tsrc |
Variable-reference players, random goals |
test_match.tsrc |
Intentionally broken — demonstrates error handling |
Testing
cargo test
13 integration tests cover:
- Goal validation (player on team, minute range, duplicates)
- Script validation (undefined variables, same team, missing match, no players)
- Happy paths (valid script, variable references, full scripted match)
Performance
- Single runtime dependency (
rand) tempfileis a dev-dependency only (for tests)- Release profile uses LTO, single codegen unit, panic=abort, and symbol stripping
- Designed for sub-second cold compilation and instant execution
- Binary size: ~340KB stripped