Introduction¶
transcripts18xx¶
A Python package to parse and process game transcripts from 18xx.games. It produces structured data suitable for analysis, modeling and visualization.
Installation¶
Python library can be installed with poetry. Run the following command:
poetry add git+ssh://git@github.com:codePascal/transcripts18xx.git
Or use https instead of ssh:
poetry add git+https://git@github.com:codePascal/transcripts18xx.git
See the poetry documentation for more information.
Library usage¶
Game transcripts¶
Game transcripts should be in plain text format as shown below:
-- Phase 2 (Operating Rounds: 1 | Train Limit: 4 | Available Tiles: Yellow) --
[23:29] player1 bids $165 for Camden & Amboy
[23:30] player2 bids $75 for Delaware & Hudson
[23:30] player3 bids $115 for Mohawk & Hudson
[23:31] player4 bids $120 for Mohawk & Hudson
[23:32] player1 buys Schuylkill Valley for $20
[23:32] player2 bids $170 for Camden & Amboy
[23:32] player3 bids $175 for Camden & Amboy
[23:33] player4 buys Champlain & St.Lawrence for $40
[23:33] player2 wins the auction for Delaware & Hudson with the only bid of $75
These raw transcripts must follow a consistent naming convention:
<game_type>_<game_id>.txt
game_type: Abbreviation of the 18xx variant (e.g.,1830,1889)game_id: The 6-digit game ID
Transcript parser¶
The core of the library is the TranscriptParser class.
It implements a transcript parser that takes the path to the transcript and the
game type as argument and generates a parsed transcript in CSV format and
complementing metadata in JSON format.
>>> import transcripts18xx as trx
>>> transcript_path = Path('1830_123456.txt')
>>> game_type = trx.Games.G1830.select()
>>> parser = trx.TranscriptParser(transcript_path, game_type)
>>> parser.parse()
This will create two new files within the transcript directory:
/
├── 1830_123456.txt
├── 1830_123456_final.csv --> The parsed final transcript data
└── 1830_123456_metadata.json --> The metadata of the game
Transcript context¶
To handle multiple parsed transcripts, the TranscriptContext is implemented.
It implements a dataclass that contains the relevant metadata as well as paths
to the raw transcript, final data and metadata. Further, it can be used to load
metadata or dataframe of the record.
>>> import transcripts18xx as trx
>>> transcript_path = Path('1830_123456.txt')
>>> trx_ctx = trx.TranscriptContext.from_raw(transcript_path)
Output Artifacts¶
Parsed transcript¶
The parsing output is saved as Pandas DataFrame and contains detailed game state information and can be structured into three major column groups.
An example is shown here: 1830_201210_final.csv
Core actions and events¶
These columns track key actions and events, involved entities and game flow:
Category |
Column |
Description |
Column Density |
|---|---|---|---|
General Metadata |
|
Game phase (e.g., 2, 3, D) |
dense |
|
Type of action or event (e.g., Bid, BuyShare) |
dense |
|
|
Round identifier (e.g., SR 1, OR 3.1) |
dense |
|
|
Sequence number within game |
dense |
|
|
Group of which type is part of (e.g., Action or Event) |
dense |
|
|
Major stock and operating round (e.g., SR 1, OR 3`) |
dense |
|
Player Actions |
|
Player involved |
sparse |
|
Amount of money in $ involved |
sparse |
|
|
Source involved (e.g., IPO, market, Depot, player, company) |
sparse |
|
|
Private company involved |
sparse |
|
|
Share percentage involved |
sparse |
|
Company Context |
|
Company involved |
sparse |
|
Share price at the time |
sparse |
|
Map and Tokens |
|
Hex location on the map |
sparse |
|
Tile placed |
sparse |
|
|
Orientation of the tile |
sparse |
|
|
Direction of the tile |
sparse |
|
Train Operations |
|
Train involved |
sparse |
|
Route run by the train |
sparse |
|
|
Train being replaced |
sparse |
|
|
New train being acquired |
sparse |
|
|
Payout per share in dividend |
sparse |
Besides the general metadata, the other columns are sparsely filled as they will be used most often for a specific event or action only.
Player state columns¶
Each player has a dedicated block of columns which represents its state at any point in time.
<player>_cash— Cash on hand<player>_privates— Private companies owned, including their values<player>_value— Net worth at this point<player>_priority_deal— Whether the player has the priority deal token<player>_shares_<company>— Shareholding in each company ( e.g.player1_shares_B&O)
Company state columns¶
Each company has a set of attributes describing its state at any point in time.
<company>_cash— Company treasury<company>_privates— Privates owned by the company<company>_ipo— Shares remaining in IPO<company>_market— Shares in market<company>_president— President player<company>_share_price— Current market price<company>_trains_<trains>— Train counts by type (e.g.PRR_trains_2)
Game metadata¶
The game metadata complements the processed CSV file. It provides game information, the final game state, player results, a verification result and unprocessed lines during parsing.
An example is shown here: 1830_201210_metadata.json
Game information¶
Field |
Description |
|---|---|
|
Game variant (e.g., 1830) |
|
Game ID |
|
Total number of players |
|
Game end condition (e.g., BankBroke, PlayerGoesBankrupt) |
|
Player with the highest value in the end |
Player mapping¶
The mapping field records how usernames were anonymized to <player>.
This is useful for identifying which real player corresponds to which parsed
record.
Player results¶
The result field depicts the ranking of the players and their final value.
This result is extracted from the transcripts last line.
If the transcript does not represent a full game with a game over identifier,
e.g. an ongoing game, this field will be empty.
Final state¶
The final state depicts the player and company state columns as a full, dense snapshot of the game state at its conclusion. It is structured into players and companies, as shown below.
{
"final_state": {
"players": {
},
"companies": {
}
}
}
Example for a final player state in an 1830 game:
{
"name": "player1",
"cash": 3304.0,
"privates": {
},
"value": 6735.0,
"shares": {
"B&M": 6,
"B&O": 6,
"C&O": 1,
"CPR": 0,
"ERIE": 4,
"NYC": 1,
"NYNH": 0,
"PRR": 1
},
"priority_deal": false
}
Example for the PRR company state in an 1830 game:
{
"name": "PRR",
"cash": 40.0,
"privates": {},
"trains": {
"2": 0,
"3": 0,
"4": 0,
"5": 0,
"6": 0,
"D": 1
},
"ipo": 0,
"market": 0,
"president": "player3",
"share_price": 67.0
}
Verification¶
The verification compares the final value of each player reported in the
transcript and the one calculated during the game state processing.
The verification result will be depicted in the success field.
Differences will be written to the diffs field.
Unprocessed lines¶
For debugging purposes, unprocessed lines, i.e. lines that were not matched to a step during parsing, will be written to the metadata as well.
Parse result¶
The parse result depicts the success of the raw transcript parsing. If no errors
occurred, it will be set to SUCCESS. Otherwise, the received error will be
written, i.e., No players found.
Parsing a transcript¶
After installation, single transcripts can be parsed by calling the poetry
script trx from the command line.
Run the following command to see command line options:
trx --help
Run full verification¶
The script automatically runs a full verification of the final game state based on a ground truth file.
The file must be located in the transcript directory and must be named
<game>_<id>_truth.json.
Its structure is similar to the one depicted in Final state.
Except that its structure omits the key final_state and player names are not
anonymized but the real player names.
Such an example is shown here: 1830_201210_truth.json
Supported Games¶
The following games are supported:
Games soon to be supported: