ACBLgamedump Software

ACBLgamedump is a free (open source) software written by Matthew Kidd that directly reads an ACBLscore binary game file into a Perl data structure or an equivalent JSON data structure. Contracts, results, and opening leads can also be integrated from Bridgemate, BridgePad, and BridgeScorer electronic scoring systems. ACBLgamedump is intended as a utility for other programs.

⇓ Download Now

Introduction

Parsing ACBLscore text based reports can be tedious. The problem is made worse by a multiplicity of report formats, variations in the report formats that arise rarely (e.g. an Adjustment column when a pair is penalized), and the lack of ACBLscore command line options to generate whichever reports your software is setup to parse. For systematic processing of ACBLscore data, directly reading the ACBLscore binary game files is highly preferable. But until recently, this was approach was also problematic because the binary game file format was not documented. Recently game file format reverse engineering has advanced far enough to make this approach robust.

ACBLgamedump decodes the ACBLscore objects and properties that are most useful for report generation and data analysis. The program removes layers of indirection that are only useful to the internal working of ACBLscore; for example the indirection to support editing pair numbers or movements (ACBLscore EDMOV command). It also skips internal details that speed up ACBLscore report generation, for example the linked list traversal of masterpoint winners.

Starting with version 1.0.2, contracts, results, and opening leads from the Bridgemate, BridgePad, and BridgeScorer electronic scoring systems can also be incorporated into the output structure or JSON.

Using the program

The actual decoding is done in a Perl package, ACBLgamedecode.pm. If you are programming in Perl, you can use this package as shown in the following code snippet.

# Find ACBLgamedecode package in the same folder as Perl code. use FindBin; use lib $FindBin::Bin; use ACBLgamedecode; # Decode a file ($err == 0 indicates success). my ($err, $gm) = ACBLgamedecode::decode('140912.ACA'); # Look at something: ACBL player number of second player in E-W pair 3 # in section B of the first event (Perl uses zero-based arrays). print $gm->{'event'}[0]{'section'}{'B'}{'entry'}{'3E'}{'player'}[1]{'pnum'}, "\n"; # See everything. use Data::Dumper; print Dumper($gm); # Include contracts, results, and opening leads from an electronic scoring file. ($err, my $bws) = ACBLgamedecode::readBWSfiles('140912A.BWS'); ($err, $gm) = ACBLgamedecode::decode('140912.ACA', undef, $bws); # Include the binary db_key field in the output. my $opt = {'binaryvalues' => 1}; ($err, $gm) = ACBLgamedecode::decode('140912.ACA', $opt, $bws);

ACBLgamedecode.pm is a Perl package but it is not “installed” as a package is when installed using PPM or CPAN. This means it will not automatically be on the Perl library search path. The first two program lines above tell Perl to search the directory that your Perl program is running from, using the FindBin package that is usually included with Perl installations. This way you can keep ACBLgamedecode.pm in the same directory as your Perl programs.

If you are not programming in Perl, run ACBLgamedump.pl to generate equivalent JSON output which can then be processed by JavaScript or any other language.

perl ACBLgamedump.pl 140912.ACA -o 140912A.json

Multiple files can be processed at once:

perl ACBLgamedump.pl 140826.ACM 140912.ACA 141017.ACE | some_other_program

In the second example the output is piped to another program.

Since multiple files can be processed at once, the JSON data structure has an extra outer array layer, where each element corresponds to the parsed result for one game file.

The JSON output is stripped of white space to minimize the output size, unless the -pp (“pretty print”) switch is specified. The JSON Lite Add-On for Firefox by Lauri Rooden will display JSON in a pretty printed tree where branches can be selectively viewed or hidden. Similar add-ons exist for other browsers.

Including electronic scoring results

Contracts, results, and opening leads may be incorporated into the output by specifying the Bridgemate, BridgePad, or BridgeScore electronic scoring (.bws) file using the -b switch. For example:

perl ACBLgamedump.pl 140912.ACA -b 140912A.BWS -o 140912A.json

If you are not sure which BWS file contains the results for a given game file, you may repeat the -b switch to have the program search multiple files. This is helpful for regionals where there are many events and the BWS files often have non-obvious names.

BWS files are searched by section letter. If a game files has section A in it and two of the BWS files contain results for section A, the data from the last BWS file containing section A will be used. This means it is inadvisable to toss all your BWS files into the mix. A future version of ACBLgamedump.pl may implement smarter matching by date and session.

On Windows, Perl uses ODBC to read the electronic scoring file. The ODBC driver needed can only be accessed from 32-bit Perl. If the -b switch is used with 64-bit Perl, the program will exit with an error message. On Unix / Linux and Mac OS, the open source mdbtools package is used to read the electronic scoring file. The exact way to install this package on Unix or Linux depends on your operating system. On Ubuntu (Debian) use one of the following commands or use the Synaptic package manager.

apt-get install mdbtools (if running as root)
sudo apt-get install mdbtools (if you are allowed to install packages)

For Max OS X, the easiest thing to do is to download this supplemental zip file of the mdbtools executables and their library dependencies. Copy mdb-export, mdb-schema, and mdb-tables from the zip archive to /usr/local/bin and copy the libmdb.1.dylib, libglib-2.0.0.dylib, and libintl.8.dylib dynamic libraries to /usr/local/lib. These directories may not exist. If not, create them as follows by starting a BASH shell using the Terminal app and entering the following commands:

sudo mkdir /usr/local
sudo chmod 775 /usr/local
sudo chgrp admin /usr/local
mkdir /usr/local/bin
mkdir /usr/local/lib

You will need to enter your account password the first time you use sudo.

Installing the JSON::PP package

JSON::PP has been a Perl core module since Perl 5.14 so it should be included with standard Perl distributions. But see below if you need to install it.

If you are using the ActiveState Perl distribution on Windows, the JSON wrapper package should already be included. But if not, you can install it from the Windows command line using the Perl Package Manager (PPM) as follows:

ppm install JSON

The JSON package is a wrapper that chooses either JSON::XS, the C/C++ performance enhanced package if available, or the JSON::PP (Pure Perl) package if it is not.

Modern Macs ship with Perl installed. The shipped Perl distribution includes the JSON::PP package but not the JSON wrapper package. ACBLgamedump 1.0.1 and later use JSON:PP to avoid problems.

On Unix or Linux use CPAN if it is necessary to install the JSON::PP package:

cpan -i JSON::PP

Notes on the output structure

The output structure is fairly self-explanatory in conjunction with ACBLscore Game Files Decoded documentation. However, in some places brevity is chosen over pedantic readability.

  1. Board results

    The result on each board is given as an array instead of a hash. The elements are:

    Round #, Table #, N-S Pair #, N-S Raw Score, N-S Score, E-W Pair #, E-W Raw Score, E-W Score, Contract Level, Contract Denomination, Declarer, Contract Result, Opening Lead

    A raw score is something like -620. The score is matchpoints or IMPs depending on the scoring type in event[].event_scoring. N-S Raw Score and E-W Raw Score are normally opposite and N-S score and E-W score normally sum to either the matchpoint top or zero (for IMP Pairs) but rare split scores from a director ruling can change this. Scores can also be one of the following strings: “Ave-”, “Ave”, “Ave+”, “Late Play”, “Not Played”. Scores from foul groups are indicated with the suffix F# where # (1-7) is the foul group number; for example -140F1 means a raw score of -140 for foul group 1. In the era of dealing machines, fouled scores are rare and it is even rarer for more than one foul group to be used. Nonetheless it is still possible for players to foul a board by exchanging card between hands before returning them to the tray or for a board to be change mid-session if a player recognizes it from a previous session.

    The fields in blue are only included if electronic scoring information has been included. Contract Level is 1-7 or PASS. Contract Denomination is C, D, H, S, or N. Declarer is N, E, S, or W. The Contract Result is relative to the Contract Level; for example 1 means one overtrick and -2 means down two. The opening lead has the format suit-rank, e.g. D3 for the ♦3, or is an empty string if the opening lead was not recorded. If the contract was passed out the Contract Denomination, Declarer, and Contract Result fields will be empty strings and the Opening Lead will be undef.

    For Board-a-Match (BAM) events, the fields listed as N-S Pair # and E-W Pair # above are instead the team numbers.

    For Individual events (check event[].event_type), there are separate results for each seat. The elements are:

    Round #, Table #, North #, North Raw Score, North Score, East #, East Raw Score, East Score, South #, South Raw Score, South Score, West #, West Raw Score, West Score, Contract Level, Contract Denomination, Declarer, Contract Result, Opening Lead

  2. Entries

    An entry refers to a tournament entry, either an individual, pair, or team depending on the event type (check event[].event_type). For a Mitchell movement, entries are indexed by number and direction (N → North-South, E → East-West), e.g. 3E. For a Howell movement, entries are indexed by a number. Check section{}.is_howell.

    For board results (see #1), pair numbers are numeric. Postfix the pair number with N or E for Mitchell movements to get the index of the pair entries.

  3. Award subfields are an array of arrays.

    Masterpoint awards are assigned at both the entry level and player level, i.e. entry{}.award and entry{}.player.award. This is to accommodate team play where players on five or six man teams can end up with differing awards depending on how many and which matches they play in. The award field supports multi-session events via the fields previous, current, and total.

    Masterpoint awards can be a combination of up to three pigmentation types where the pigmentations are Black (B), Silver (S), Red (R), Gold (G), and Platinum (P). Accordingly, the outer array will be 0-3 elements depending on the number of pigmentation type. Each inner array, contains the following fields:

    Masterpoints, Pigmentation Letter, Award Reason, Award Reason Code

    The Award Reason Code is the ACBLscore internal representation of the Award Reason. For example, a code of 12 always means a section ranking (1) in the second strat (2). Usually this will translate to an Award Reason of “SB”; however strats designations can vary, for example AX or DEF concurrent with a separately flighted ABC event. See event[].strat[].letter for the letter (or even sometimes a digit) used for each strat of an event.

    Putting this altogether, here are examples of referencing the total masterpoint award and pigmentation type for the first pigmentation.

    $pair = $gm->{'event'}[0]{'section'}{'B'}{'entry'}{'3E'}; $mp = $pair->{'award'}{'total'}[0][0]; $pg = $pair->{'award'}{'total'}[0][1];

    For handicapped events that are ranked both with and without the handicap, the award for the ranking with the handicap is stored in the first position and the award for the ranking without the handicap is stored in the second position. If a pair only receives an award without the handicap, the masterpoint award for the first position will be zero. For handicapped events, the masterpoint pigmentation type will be the same in each position unlike the normal case above where the pigmentation type is different for each position. If a pair receives an award both with and without the handicap, their total award is the sum of the two masterpoint awards as indicated in these fields. For example, consider a pair that third after the handicap is applied and ranks 1st without the handicap, where the awards are 0.18 MP and 0.53 MP. The pair receives the better of these awards, 0.53 MP. However internally, the awards are stored as 0.18 MP and 0.35 MP respectively, as though the award without the handicap were an inferior pigmentation even though the pigmentation is the same.

  4. Award field is not included if an entry received no award.

    When no masterpoint are awarded in any of the previous, current, and total categories, the award field will not be included. In Perl, attempts to reference the missing fields, will return undef, for example player[].award[].total[0][0] will return undef for the masterpoints and this will be interpreted as 0 in a numeric context which is usually what one wants, though a warning will be generated if Perl is invoked with the -w (warnings) switch. Other languages may not be as tolerant. It may be necessary to check for the existence of the award member once the JSON code has been loaded as an object in a particular language.

  5. Combining and Ranking sections together

    For scoring, sections within an event may be combined together, producing a higher top. Sections that are combined together may also be ranked together. Ranking Together means the section awards are across all N-S sections and all E-W sections respectively instead of within individual sections. The field event[].combining_and_ranking is an array of arrays indicating how the sections are combined and ranked together. For example:

    [ [ ["J"], ["K"] ], [ ["L", "M"] ], [ ["Q"] ] ]

    In this five section example, sections J and K are combined but ranked separately, sections L and M are combined and ranked together, and section Q is separate.

  6. Datetime format

    Timestamps are encoded using the ISO 8601 format, e.g. 2014-08-29T14:05:17. Note that a time zone designator is not included because ACBL game files do not include time zone information.

  7. Important fields

    Many fields are decoded (or derived). For accurate parsing pay careful attention to the ones listed below.

    FieldExplanation
    event.type_id
    event.type
    Use either. type_id is ACBLscore’s internal value. Allowed values are 0 → Pairs, 1 → Teams, 2 → Individual, 3 → Home Style Pairs, 4 → BAM, 5 → Series Winner.
    event.scoring_id
    event.scoring
    Use either. scoring_id is ACBLscore’s internal value. Allowed values are 0 → Matchpoints, 1 → IMPs with computed datum, 2 → Average IMPs, 3 → Total IMPs, 4 → Instant Matchpoints, 5 → BAM Teams, 6 → Win/Loss, 7 → Victory Points, 8 → Knockout, 10 → Series Winners, 16 → BAM Matchpoints, 18 → Compact KO.
    event.rating_id
    event.rating
    Use either. rating_id is ACBLscore’s internal value. Sample values: 0 → No Masterpoints, 1 → Club Masterpoints, 2 → Club Championship. See Event Rating Enum for the full list.
    event.tournament_flag 1 → tournament, 0 → club game
    event.session_num Session number
    event.nsessions Total number of sessions
    event.final_session_flag Derived from previous two fields. If zero, the masterpoint awards shown are not final. Do not tally these awards in computing masterpoint totals.
    event.handicap_type_id
    event.handicap_type
    event.handicap_scoring
    If the event is handicapped, the ACBLscore internal value handicap_type_id will be non-zero. In this case the event.handicap_type_id (“Percentage”, “Matchpoints”, “Boards”) and handicap_scoring (“single-ranking” or “double-ranking”) will be decoded.
    event.tournament
    event.club
    Have first field for tournaments, second for club games
    event.city
    event.director
    Have first field for tournaments, second for club games
    section.board_top Top on a board for Matchpoint scoring (probably set to 100 for Instant Matchpoints). Not included for team games.
    section.nboards Total number of boards in play. A pair may not play all the boards. For example a 10 table Mitchell will use 30 boards where each pair plays 27 (9 rounds × 3 boards / round).
    section.is_howell Indicates whether movement is a Howell movement. This affects how entries are indexed.
    section.nteams Number of teams (only included for team games).

Limiting Output

When using ACBLgamedump.pl, the amount of data dumped may be limited by the -sc (section level only), -nb (no board dump), and -ne (no entry dump) switches. When ACBLgamedecode.pm is used directly, a second $opt parameter can be passed to ACBLgamedecode::decode where setting $opt->{'sectionsonly'}, $opt->{'noboards'}, and $opt->{'noentries'} to a non-zero value respectively is equivalent to the previous switches.

Other options

The -pp (“pretty print”) switch causes the output JSON to include white space and new lines for easy human interpretation. The -bv (“binary values”) causes the output to include fields which have a binary value, currently only the db_key field of the player structure. When ACBLgamedecode.pm is used directly, these -bv option invoked by setting $opt->{'binaryonly'} to a non-zero value; the -pp option is not applicable at level of ACBLgamedump.pm.

Version history

Older versions of ACBLgamedump can be downloaded by clicking on the download arrow next to the version. The latest version is also always available from the Download Now button at the top of the page as well as here.

ACBLgamedump version history
VersionDateMajor Changes
⇓ 1.0.711-Apr-2018
  • Fixed failure to return any pair information for IMP Pairs events due to a kludge that was used to detect phantom pairs and the non-existent companion pair to a rover pair (reported by Philippe Lamoise). Code should now handle phantom and rover pairs correctly.
  • Fixed incorrect reporting of negative IMP results on each board for IMP Pairs events due to incorrectly interpreting an int32 as unsigned, leading to results such as 42949688.96 (reported by Philippe Lamoise).
  • Account for possible second and third phantom players in individual events.
  • Added roverdir to the section structure. This will be either ‘N-S’ or ‘E-W’ to indicate the direction that the rover pair sits in a Rover Mitchell movement; otherwise it will be an empty string.
  • Filled in missing event ratings though ‘Alzheimer Fund’ by searching for the strings in wScore.exe (requested by Rick Garvin).
  • Correctly interpret ACBL Rank Letters for events run after the start of 2016 when the Ruby (1500 MP) and Sapphire (3500 MP) ranks were added.
⇓ 1.0.605-Dec-2015
  • Fixed regression in version 1.0.5 that prevented board results from ever appearing.
  • Knockout team match results are now only reported for actual matches. Previously, matchups against team 0 were reported for the rounds after a team was knocked out.
⇓ 1.0.502-Nov-2015
  • Fixed bug that caused erroneous decoding of non-existent board results (NULL pointer) and a possible hang when ACBLscore is only used to award matchpoints but not used to score the results, a rare case (reported by Philippe Lamoise).
⇓ 1.0.408-Oct-2015
  • Fixed bug where board numbers could be offset by 256 (i.e. 257, 258, … instead of 1, 2, …) when travelers were used for scoring as opposed to pickup slips or electronic scoring (reported separately by Rick Garvin and Philippe Lamoise).
  • Fixed bug that could cause one valid board result to be dropped each time a Not Played or Schedule Late Play result was encountered (reported separately by Rick Garvin and Tom Moore).
  • Fixed bug that resulted in improper decoding of multi-line memos.
  • Fixed bug that prevented reporting of GNT qual for a Flt C team that doesn’t rank (reported by Rick Garvin).
  • Fixed bug that prevented reporting of masterpoints and quals for the non-handicapped ranking of a double-ranked handicap event when the pair did not received masterpoints or qualify in the handicapped ranking (reported by Rick Garvin).
  • Fixed bug that caused Perl warnings to be generated if a Mitchell movement had a bump pair (fix suggested by Rick Garvin).
  • Code now decodes board results from foul groups.
  • Added next_section, next_table, and next_dir fields to entry structure for non-final session of multi-session events. If a pair (or individual) pulls out, next_section is set to “Resigned” (requested by Philipp Lamoise).
  • Added computed fields has_overall_scores and has_quals to the section structure (requested by Philippe Lamoise).
⇓ 1.0.312-Mar-2015
  • Now properly decode Home Style Pairs events (two table events where each pair forms a team with each of the other pairs for three rounds). Previously, the code attempted to dereference non-existent board pointers which could exhaust memory.
  • Fixed decoding of day and seconds fields in datetime fields. High bit was improperly masked such that day was always ≤15 and seconds was always ≤31 (reported by Rick Garvin).
  • Fixed swap of Section (S) and Overall (O) in award output (reported by David Kopper).
  • Added rating_id and rating fields to event structure.
  • Added LM_eligibility field to strat structure. Reports ‘LM Only’, ‘NLM Only’, or ‘No Restriction’.
⇓ 1.0.206-Feb-2015
  • Added ability to incorporate contract, result, and lead card from Bridgemate, BridgePad, and BridgeScore BWS files.
  • Fixed bug that could generate nonsense output when there was a phantom pair (code attempted to decode the phantom pair, dereferencing invalid pointers).
  • Fixed bug that caused is_bam field to be 0 even for BAM games.
  • Board-a-Match (BAM) decoded events now include results for each board.
  • Datetime fields, e.g. the game file creation timestamp, are now decoded (applies to game file, events, and sections).
  • Memos (game file, event, and section) and Notes (only applies to game file) are now decoded.
  • New fields for game file: ACBLscore_min_compatible_version, ACBLscore_version; events: consolation_flag, continuous_pairs_flag, senior_event_flag, mp_award_revision_num; sections: is_scored
  • Entry structure now only includes players for actual number of players on the team (typically 4) instead of for all 6 potential players.
  • Suppress fields which have binary data (db_key) unless new -bv switch is specified.
⇓ 1.0.112-Nov-2014
  • Replaced JSON wrapper package with specific JSON::PP (Pure Perl) package so that program works with version of Perl shipped with Mac OS X without installing any packages.
⇓ 1.0.005-Nov-2014 Original release.

Files included in the software distribution

The current program archive contains the files listed in the table below.

ACBLgamedump file list
FilenamePurpose
ACBLgamedump.plPerl program
ACBLgamedecode.pmPerl package

Command Line Help

Command line arguments inside [ ] are optional.

  Usage: $bname fname [fname...] [-b bfname [...]] [-o ofname]

  fname  : ACBLscore game filename
  bfname : BWS filename (electronic scoring file)  
  ofname : Output filename (default is STDOUT)
    
  Options
    -sc : Dump to section level only
    -nb : Don't dump board
    -ne : Don't dump entries (individual, pairs, teams)
    
    -bv : Include binary values (db_key parameter)
    -pp : Pretty print JSON output      
    -vr : Display version number
    
  Partially decodes one or more ACBLscore game files, outputting
  result as JSON. Can also integrate contracts, results, and opening
  leads from Bridgemate, BridgePad, and BridgeScorer systems.
  
  Online documentation is located at:
  http://lajollabridge.com/Software/ACBLgamedump/ACBLgamedump-About.htm
  
  See http://lajollabridge.com/Articles/ACBLscoreGameFilesDecoded.htm
  for details of ACBLscore game file format.