npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@poker-apprentice/hand-history-parser

v6.6.0

Published

Parse hand histories from online poker sites

Downloads

31

Readme

Hand History Parser

Parse hand histories from online poker sites in JavaScript & TypeScript.

Installation

Add @poker-apprentice/hand-history-parser as a dependency.

  • yarn:
    yarn add @poker-apprentice/hand-history-parser
  • npm:
    npm install @poker-apprentice/hand-history-parser --save

Usage

parseHand

This promise-based function can be used to parse hand histories from any support poker site. To use it, simply pass the contents of an individual hand history along with the filename.

// Assumes `hand` is a string containing the hand history file contents & `filename`
// is a string containing the hand history filename.
const handHistory = parseHand({ hand, filename })
  .then((handHistory) => console.log(handHistory))
  .catch((err) => console.error(err));

If preferred, an async/await implementation can be used instead.

// Assumes `hand` is a string containing the hand history file contents & `filename`
// is a string containing the hand history filename.
try {
  const handHistory = await parseHand({ hand, filename });
  console.log(handHistory);
} catch (err) {
  console.error(err);
}

The value returned is represented as a HandHistory type object. For example:

{
  "info": {
    "bettingStructure": "no limit",
    "blinds": ["0.1", "0.25"],
    "currency": "USD",
    "handNumber": "4290322948",
    "isFastFold": false,
    "tableNumber": "26728545",
    "site": "bovada",
    "tableSize": 6,
    "timestamp": new Date("2022-05-26T14:16:24.000Z"),
    "variant": "holdem",
  },
  "players": [
    {
      "chipStack": "25",
      "isAnonymous": false,
      "isHero": true,
      "name": "Big Blind",
      "position": "BB",
      "seatNumber": 1,
    },
    {
      "chipStack": "24.4",
      "isAnonymous": true,
      "isHero": false,
      "name": "UTG",
      "position": "UTG",
      "seatNumber": 2,
    },
    {
      "chipStack": "7.5",
      "isAnonymous": true,
      "isHero": false,
      "name": "UTG+1",
      "position": "UTG+1",
      "seatNumber": 3,
    },
    {
      "chipStack": "33.77",
      "isAnonymous": true,
      "isHero": false,
      "name": "UTG+2",
      "position": "UTG+2",
      "seatNumber": 4,
    },
    {
      "chipStack": "26.87",
      "isAnonymous": true,
      "isHero": false,
      "name": "Dealer",
      "position": "BTN",
      "seatNumber": 5,
    },
    {
      "chipStack": "23.3",
      "isAnonymous": true,
      "isHero": false,
      "name": "Small Blind",
      "position": "SB",
      "seatNumber": 6,
    },
  ],
  "actions": [
    {
      "type": "post",
      "postType": "blind",
      "amount": "0.1",
      "playerName": "Small Blind",
    },
    {
      "type": "post",
      "postType": "blind",
      "amount": "0.25",
      "playerName": "Big Blind",
    },
    {
      "type": "deal-hand",
      "cards": ["Th", "Qh"],
      "playerName": "Big Blind",
    },
    {
      "type": "deal-hand",
      "cards": ["9s", "Ks"],
      "playerName": "UTG",
    },
    {
      "type": "deal-hand",
      "cards": ["6h", "Ad"],
      "playerName": "UTG+1",
    },
    {
      "type": "deal-hand",
      "cards": ["Jd", "2s"],
      "playerName": "UTG+2",
    },
    {
      "type": "deal-hand",
      "cards": ["Tc", "8d"],
      "playerName": "Dealer",
    },
    {
      "type": "deal-hand",
      "cards": ["3d", "8c"],
      "playerName": "Small Blind",
    },
    {
      "type": "call",
      "amount": "0.25",
      "isAllIn": false,
      "playerName": "UTG",
    },
    {
      "type": "call",
      "amount": "0.25",
      "isAllIn": false,
      "playerName": "UTG+1",
    },
    {
      "type": "fold",
      "playerName": "UTG+2",
    },
    {
      "type": "fold",
      "playerName": "Dealer",
    },
    {
      "type": "fold",
      "playerName": "Small Blind",
    },
    {
      "type": "check",
      "playerName": "Big Blind",
    },
    {
      "type": "deal-board",
      "cards": ["Qs", "Ts", "4s"],
      "street": "flop",
    },
    {
      "type": "bet",
      "amount": "0.5",
      "isAllIn": false,
      "playerName": "Big Blind",
    },
    {
      "type": "call",
      "amount": "0.5",
      "isAllIn": false,
      "playerName": "UTG",
    },
    {
      "type": "fold",
      "playerName": "UTG+1",
    },
    {
      "type": "deal-board",
      "cards": ["Jc"],
      "street": "turn",
    },
    {
      "type": "bet",
      "amount": "1",
      "isAllIn": false,
      "playerName": "Big Blind",
    },
    {
      "type": "call",
      "amount": "1",
      "isAllIn": false,
      "playerName": "UTG",
    },
    {
      "type": "deal-board",
      "cards": ["5d"],
      "street": "river",
    },
    {
      "type": "check",
      "playerName": "Big Blind",
    },
    {
      "type": "bet",
      "amount": "2.75",
      "isAllIn": false,
      "playerName": "UTG",
    },
    {
      "type": "call",
      "amount": "2.75",
      "isAllIn": false,
      "playerName": "Big Blind",
    },
    {
      "type": "showdown",
      "handStrength": 5,
      "playerName": "UTG",
    },
    {
      "type": "showdown",
      "handStrength": 2,
      "playerName": "Big Blind",
    },
    {
      "type": "award-pot",
      "amount": "8.89",
      "isSidePot": false,
      "playerName": "UTG",
    },
  ],
}

parseSite

This function can be used to determine the support poker site on which a hand was played. To use it, simply pass the contents of an individual hand history.

// assumes `hand` is a string containing the hand history file contents
const site = parseSite(hand);
console.log(site);

The value returned is represented as a Site string union type.

Supported Poker Sites/Networks

This package currently supports the following poker sites & networks:

| Site | Network | Cash Games | Tournaments | Hold'em | Omaha | Omaha-8 | Stud | Currencies | | -------- | -------- | :--------: | :---------: | :-----: | :-----: | :-----: | :--: | ---------- | | Bodog | Ignition | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | USD | | Bovada | Ignition | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | USD | | Ignition | Ignition | ✅ | ✅ | ✅ | ✅ | ✅ | N/A | USD |

The parser is built in a way that it is relatively straightforward to extend with new poker sites. The main thing that is missing for this to happen is a combination of sample hand histories to implement against & time.

If you are a developer that is interested in contributing, see the contributing section below.

If you are an online poker player that has hand histories that can be used as a reference, please email them to the author.

Contributing

If you'd like to implement a new poker site, fix a bug, improve the documentation, or anything else to better this library, pull requests are welcomed!

The architecture is as straightforward as possible, with the most complex part involving an understanding of the ANTLR language processor. The approach is as follows:

  1. Clone the repository:
    git clone [email protected]:poker-apprentice/hand-history-parser.git
  2. Install dependencies:
    yarn install
  3. Add a .g4 grammar file under grammar/[PokerNetwork].g4. It is recommended that this file be parsed by different types of lines that appear within the file. These lines can typically be broken down into one of: game metadata, player metadata, & player actions. These three types of information comprise the data that must be returned by a new hand history parser.
  4. Build all ANTLR grammar files:
    yarn build:grammar
  5. Add a visitor for your poker site under networks/[pokernetwork]/[PokerNetwork]HandHistoryVisitor.ts. The visitor is responsible for returning a value representing the current node that is being parsed bym ANTLR. Ideally each line being parsed can return an object representing one of the three types of metadata outlined above. However, it may be necessary to utilize a custom return type that may or may not wrap the shared Action, Player, and GameInfo types depending on the poker site's hand history structure.
  6. Add a parser for your poker site under networks/[pokernetwork]/parseHand.ts. This function is intended to delegate to the Visitor class implemented above, massaging the return value into a HandHistory object as a return value.
  7. Add an if-condition for your poker site within parseSite.ts.
  8. Include tests for common & uncommon parsing scenarios that demonstrate the parseHand and parseSite functions are working as intended. Common & uncommon scenarios include for the parseHand function include:
    • Multiple variants (e.g.: Hold'em, Omaha, Omaha-8, etc.),
    • Multiple betting structures (i.e.: limit, no-limit, pot-limit, spread-limit, cap-limit),
    • Multiple currencies,
    • Cash & tournament games,
    • Chopped pots & side pots,
    • Antes & bounties, and
    • Player disconnections & timeouts.

If you are interested in contributing, but you are stuck or lost at any point in your efforts, please reach out for help!