| .. | ||
| README.md | ||
.tsrc Language Reference
.tsrc (Tiny Soccer Sim Rust C) is a minimal C-like DSL for scripting soccer matches in tssr. It lets you define teams, assign players, script goals, and control output format — all from a plain text file.
Invocation
Via --script flag
tssr --script match.tsrc # table output
tssr --script match.tsrc --json # JSON output
Via shebang
Add this as the first line of your .tsrc file:
#!/usr/bin/env tssr
Then make it executable and run directly:
chmod +x match.tsrc
./match.tsrc
Language Syntax
Team Declaration
string var_name = "Team Name";
Declares a variable that holds a team name. Variables can be referenced later in players[], goal(), and match().
Rules:
- Variable names must be alphanumeric + underscores
- Duplicate variable names are an error
- The string value is the team's display name
Player Assignment
players["Player Name"] = var_name;
players["Player Name"] = "Team Name";
Assigns a player to a team. The right side can be either a previously declared variable or a string literal.
Rules:
- The team (right side) must resolve to a team that appears in
match() - The same player cannot be added to the same team twice
- Variables must be declared before use (forward references are an error)
Scripted Goals
goal(minute, team, player);
Scripts a specific goal event. When any goal() appears, the match score becomes deterministic.
| Argument | Type | Description |
|---|---|---|
minute |
integer (1-90) | Minute the goal was scored |
team |
variable or string | The team that scored |
player |
string literal | The player who scored |
Rules:
- Minute must be between 1 and 90
- Team must be one of the two match teams
- Player must be on that team's roster
- The same player cannot score at the same minute twice
- Variables must be declared before use
Match Selection
match(var_home, var_away);
Selects which two teams play. Required — every .tsrc script must contain exactly one match().
Rules:
- Both variables must be previously declared
- Home and away must be different teams
- Both teams must have at least one player assigned
Output Mode Directive
#define JSON
#define ASCII_TABLE
#define UNICODE_TABLE
Sets the output format for the match. Optional — defaults to UNICODE_TABLE.
Rules:
- Only one output mode
#defineper script - Must be one of the three known modes
- Unknown names produce an error
The --json CLI flag always overrides the script's #define.
Situation Mode Directive
#define SITUATION
Enables hybrid deterministic/stochastic mode. Scripted goals are guaranteed, but additional random goals (up to 5 per team) are also generated.
Rules:
- Requires at least one
goal()call — error without one - Can be combined with any output mode
#define - Scripted goals always appear; random goals vary per run
- Random goals are drawn from the team's roster (or name pools if roster is empty)
Complete Grammar
script = statement*
statement = define | string_decl | player_insert | goal_stmt | match_stmt
define = "#define" (identifier | "SITUATION")
string_decl = "string" identifier "=" string_literal ";"
player_insert = "players" "[" string_literal "]" "=" (identifier | string_literal) ";"
goal_stmt = "goal" "(" number "," (identifier | string_literal) "," string_literal ")" ";"
match_stmt = "match" "(" identifier "," identifier ")" ";"
comment = "//" .* "\n"
shebang = "#!" .* "\n"
Output Modes
| Mode | #define |
CLI flag | Description |
|---|---|---|---|
| Unicode table | UNICODE_TABLE (default) |
— | Box-drawing characters (╔, ═, ║) |
| ASCII table | ASCII_TABLE |
— | ASCII-only (+, -, ` |
| JSON | JSON |
--json |
Machine-readable JSON |
Match Generation Modes
| Mode | #define |
Behavior |
|---|---|---|
| Random | (none) | Everything is randomized |
| Scripted | (none, with goal()) |
Goals, scorers, minutes are exact |
| Situation | SITUATION |
Scripted goals guaranteed + 0-5 random extra goals per team |
Scripted Goals Behavior
Deterministic Mode (goal() without SITUATION)
When goal() is used, the match becomes deterministic:
| Field | Behavior with goal() |
Behavior without |
|---|---|---|
| Score | Count of goals per team | Random 0-5 |
| Scorers | Exact (player, minute) from script |
Random names + minutes |
| Shots | max(score, random(4..=18)) — floor = goals |
Random 4-18 |
| Shots on target | max(score, random(1..shots)) |
Random |
| Possession | Still random | Random |
Situation Mode (goal() with SITUATION)
Hybrid deterministic/stochastic — scripted goals are guaranteed, plus random extras:
| Field | Behavior in SITUATION mode |
|---|---|
| Score | Scripted goals + 0-5 random extra per team |
| Scorers | Exact scripted goals + random from roster/name pools |
| Shots | max(total_score, random(4..=18)) |
| Shots on target | max(total_score, random(1..shots)) |
| Possession | Still random |
Variable Resolution
Variables are resolved at parse time by looking up their declared value:
string home = "GNU United";
string away = "BSD Athletic";
players["Richard Stallman"] = home; // resolves to "GNU United"
players["Theo de Raadt"] = away; // resolves to "BSD Athletic"
goal(12, home, "Richard Stallman"); // goal for "GNU United"
goal(34, "BSD Athletic", "Theo de Raadt"); // literal also works
match(home, away); // GNU United vs BSD Athletic
You can mix variables and literals freely. Forward references (using a variable before its string declaration) are an error.
Validation
The parser is strict. Any inconsistency produces an error and exits immediately.
Error Conditions
| Error | Cause |
|---|---|
undefined variable 'x' |
Variable used before string x = ... declaration |
variable 'x' redefined |
Two string x = ... declarations |
players[...] = "X" which is not a match team |
Roster team isn't in match() |
duplicate player "X" on team "Y" |
Same player added to same team twice |
"X" has no players assigned |
A match team has zero players |
match() has the same team for both home and away |
Both match() args resolve to same team |
no match() directive found |
Missing match() |
goal() minute must be between 1 and 90 |
Invalid minute |
player "X" is not on team "Y" |
Goal references unregistered player |
duplicate goal |
Same player scores same minute twice |
undefined variable 'x' in goal() |
Goal uses undeclared team variable |
duplicate #define |
More than one output mode #define |
unknown #define 'FOO' |
Unrecognized output mode |
#define SITUATION requires at least one goal() call |
SITUATION defined without any goal() |
Full Example
#!/usr/bin/env tssr
// GNU United vs BSD Athletic
#define ASCII_TABLE
string home = "GNU United";
string away = "BSD Athletic";
players["Richard Stallman"] = home;
players["Brian Fox"] = home;
players["Linus Torvalds"] = home;
players["Theo de Raadt"] = away;
players["Jordan Hubbard"] = away;
players["Ken Thompson"] = away;
goal(12, home, "Richard Stallman");
goal(34, away, "Theo de Raadt");
goal(56, home, "Brian Fox");
goal(78, "BSD Athletic", "Ken Thompson");
goal(89, home, "Linus Torvalds");
match(home, away);
Output:
+------------------------------------+
+ TSSR MATCH RESULT +
+------------------------------------+
+ GNU United 3-2 BSD Athletic +
+------------------------------------+
+ +
+Shots 4 5 +
+On Target 3 2 +
+Possession 48% 52% +
+ +
+Goals: +
+GNU United: Richard Stallman (12') +
+GNU United: Brian Fox (56') +
+GNU United: Linus Torvalds (89') +
+BSD Athletic: Theo de Raadt (34') +
+BSD Athletic: Ken Thompson (78') +
+------------------------------------+
Situation Mode Example
#!/usr/bin/env tssr
// Hybrid mode: some goals guaranteed, others random
#define SITUATION
string home = "GNU United";
string away = "BSD Athletic";
players["Richard Stallman"] = home;
players["Brian Fox"] = home;
players["Linus Torvalds"] = home;
players["Theo de Raadt"] = away;
players["Jordan Hubbard"] = away;
players["Ken Thompson"] = away;
goal(12, home, "Richard Stallman"); // guaranteed
goal(67, away, "Theo de Raadt"); // guaranteed
// Up to 5 additional random goals per team will be added
match(home, away);
Each run produces different scores — scripted goals always appear, random goals vary:
Run 1: GNU United 2-3 BSD Athletic
Run 2: GNU United 1-2 BSD Athletic
Run 3: GNU United 2-2 BSD Athletic