[
  {
    "path": ".gitignore",
    "content": "node_modules\nnpm-debug.log"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - 0.8\nenv: NODE_ENV=travis\nbefore_install:\n  - npm config set loglevel warn\n"
  },
  {
    "path": "lib/3CardConverter.js",
    "content": "//converts 3 card to lowest equivalent 5 card hand\nmodule.exports = {\n  CARDVALS: ['2', '3', '4', '5', '6', '7', '8', '9', 't', 'j', 'q', 'k', 'a'],\n  CARDS: {\n    \"2c\": 1,\n    \"2d\": 2,\n    \"2h\": 3,\n    \"2s\": 4,\n    \"3c\": 5,\n    \"3d\": 6,\n    \"3h\": 7,\n    \"3s\": 8,\n    \"4c\": 9,\n    \"4d\": 10,\n    \"4h\": 11,\n    \"4s\": 12,\n    \"5c\": 13,\n    \"5d\": 14,\n    \"5h\": 15,\n    \"5s\": 16,\n    \"6c\": 17,\n    \"6d\": 18,\n    \"6h\": 19,\n    \"6s\": 20,\n    \"7c\": 21,\n    \"7d\": 22,\n    \"7h\": 23,\n    \"7s\": 24,\n    \"8c\": 25,\n    \"8d\": 26,\n    \"8h\": 27,\n    \"8s\": 28,\n    \"9c\": 29,\n    \"9d\": 30,\n    \"9h\": 31,\n    \"9s\": 32,\n    \"tc\": 33,\n    \"td\": 34,\n    \"th\": 35,\n    \"ts\": 36,\n    \"jc\": 37,\n    \"jd\": 38,\n    \"jh\": 39,\n    \"js\": 40,\n    \"qc\": 41,\n    \"qd\": 42,\n    \"qh\": 43,\n    \"qs\": 44,\n    \"kc\": 45,\n    \"kd\": 46,\n    \"kh\": 47,\n    \"ks\": 48,\n    \"ac\": 49,\n    \"ad\": 50,\n    \"ah\": 51,\n    \"as\": 52\n  },\n  makesStraight: function(cardsUsed, rank) {\n    //add ace to bottom as well\n    var newCards = [cardsUsed[12]].concat(cardsUsed);\n    //add in new card (pushed up one by ace)\n    newCards[rank+1] = 2;\n    //determine if there are 5 cards in a row\n    return 5 === newCards.reduce(function(prev, next) {\n      if (prev === 5) {\n        return 5;\n      } else {\n        return next ? prev + 1 : 0;\n      }\n    });\n  },\n\n  fillHand: function(cards) {\n\n  \tvar cardsUsed = [0,0,0,0,0,0,0,0,0,0,0,0,0];\n\n  \t//convert each card to vals 0-12, strip suit\n  \tcards.forEach(function(card) {\n  \t\tvar i = Math.floor((this.CARDS[card.toLowerCase()]-1)/4);\n  \t\tcardsUsed[i] = 1;\n  \t}, this);\n\n  \tvar toFill = 2; //need to fill 2 cards\n\n    //fill in <toFill> cards to complete 5 card hand\n  \tfor (var i = 0; i < 13; i++) {\n  \t  if (toFill == 0) break; //done filling\n      //prevent adding a card to finish a straight\n      if (cardsUsed[i] == 0 && !this.makesStraight(cardsUsed,i)) {\n        cardsUsed[i] = 2;\n        toFill--;\n      }\n  \t}\n\n    //fill dummy cards for lowest possible hand\n    var suit = ['s', 'd'];\n    for (var i = 0; i <= 13; i++) {\n      if (cardsUsed[i] == 2) {\n        var card = this.CARDVALS[i] + suit[0];\n        suit.splice(0, 1);\n        cards.push(card);\n      }\n    }\n    return cards;\n  }\n};"
  },
  {
    "path": "lib/PokerEvaluator.js",
    "content": "var fs = require(\"fs\");\nvar path = require(\"path\");\nvar ThreeCardConverter = require(\"./3CardConverter\");\n\nmodule.exports = {\n  HANDTYPES: [\n    \"invalid hand\",\n    \"high card\",\n    \"one pair\",\n    \"two pairs\",\n    \"three of a kind\",\n    \"straight\",\n    \"flush\",\n    \"full house\",\n    \"four of a kind\",\n    \"straight flush\"\n  ],\n\n  CARDS: {\n    \"2c\": 1,\n    \"2d\": 2,\n    \"2h\": 3,\n    \"2s\": 4,\n    \"3c\": 5,\n    \"3d\": 6,\n    \"3h\": 7,\n    \"3s\": 8,\n    \"4c\": 9,\n    \"4d\": 10,\n    \"4h\": 11,\n    \"4s\": 12,\n    \"5c\": 13,\n    \"5d\": 14,\n    \"5h\": 15,\n    \"5s\": 16,\n    \"6c\": 17,\n    \"6d\": 18,\n    \"6h\": 19,\n    \"6s\": 20,\n    \"7c\": 21,\n    \"7d\": 22,\n    \"7h\": 23,\n    \"7s\": 24,\n    \"8c\": 25,\n    \"8d\": 26,\n    \"8h\": 27,\n    \"8s\": 28,\n    \"9c\": 29,\n    \"9d\": 30,\n    \"9h\": 31,\n    \"9s\": 32,\n    \"tc\": 33,\n    \"td\": 34,\n    \"th\": 35,\n    \"ts\": 36,\n    \"jc\": 37,\n    \"jd\": 38,\n    \"jh\": 39,\n    \"js\": 40,\n    \"qc\": 41,\n    \"qd\": 42,\n    \"qh\": 43,\n    \"qs\": 44,\n    \"kc\": 45,\n    \"kd\": 46,\n    \"kh\": 47,\n    \"ks\": 48,\n    \"ac\": 49,\n    \"ad\": 50,\n    \"ah\": 51,\n    \"as\": 52\n  },\n\n  evalHand: function(cards) {\n    if (!this.ranks) {\n      throw new Error(\"HandRanks.dat not loaded\");\n    }\n\n    if (cards.length != 7 && cards.length != 6 && cards.length != 5 && cards.length != 3) {\n      throw new Error(\"Hand must be 3, 5, 6, or 7 cards, but got \" + cards.length);\n    }\n\n    //if 3 card hand, fill in to make 5 card\n    if (cards.length == 3) {\n      cards = ThreeCardConverter.fillHand(cards);\n    }\n\n    //if passing in string formatted hand, convert first\n    if (typeof cards[0] == \"string\") {\n      cards = cards.map(function(card) {\n        return this.CARDS[card.toLowerCase()];\n      }.bind(this));\n    }\n\n    return this.eval(cards);\n  },\n\n  eval: function(cards) {\n    var p = 53;\n    for (var i = 0; i < cards.length; i++) {\n      p = this.evalCard(p + cards[i]);\n    }\n\n    if (cards.length == 5 || cards.length == 6) {\n      p = this.evalCard(p)\n    }\n\n    return {\n      handType: p >> 12,\n      handRank: p & 0x00000fff,\n      value: p,\n      handName: this.HANDTYPES[p >> 12]\n    }\n  },\n\n  evalCard: function(card) {\n    return this.ranks.readUInt32LE(card * 4);\n  }\n}\n\nvar ranksFile = path.join(__dirname, '../data/HandRanks.dat');\nmodule.exports.ranks = fs.readFileSync(ranksFile);\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"poker-evaluator\",\n  \"version\": \"0.3.2\",\n  \"description\": \"A library to evaluate 3, 5 or 7 card poker hands\",\n  \"homepage\": \"http://github.com/chenosaurus/poker-evaluator\",\n  \"keywords\": [\"poker\", \"games\"],\n  \"author\": \"David Chen <chenosaurus@gmail.com>\",\n  \"contributors\": [\n    {\n      \"name\": \"Andreas Brekken\",\n      \"email\": \"a@abrkn.com\"\n    }\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/chenosaurus/poker-evaluator.git\"\n  },\n  \"dependencies\": {},\n  \"scripts\": {\n    \"test\": \"jest && node test/speedtest.js\"\n  },\n  \"devDependencies\": {\n    \"jest\": \"^20.0.4\"\n  },\n  \"main\": \"./lib/PokerEvaluator.js\",\n  \"engines\": {\n    \"node\": \">= 0.6.0\"\n  }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "# Poker Hand Evaluator\n\nPoker hand evaluator using the Two Plus Two alogorithm and lookup table.\nThe lookup table HandRanks.dat is included in the module.\n\nIt is capable of evaluating 7, 6, 5, and 3 card hands.  The highest hand possible in a 3 card hand is 3 of a kind, straights & flushes do not apply to 3 cards.\n\nHands can be evaluated by comparing the handType then the handRank to determine the better hand.\n\nThis can evaluate about 22MM hands per second on a quad-core 2.7GHz Macbook Pro.  Run the speedtest.js file under /test to try it.\n\n## to install:\n\nnpm install poker-evaluator\n\n## Usage:\n\n```js\nvar PokerEvaluator = require(\"poker-evaluator\");\n\nPokerEvaluator.evalHand([\"As\", \"Ks\", \"Qs\", \"Js\", \"Ts\", \"3c\", \"5h\"]);\n\n//{ handType: 9,\n//  handRank: 10,\n//  value: 36874,\n//  handName: 'straight flush' }\n\nPokerEvaluator.evalHand([\"As\", \"Ac\", \"Ad\", \"5d\", \"5s\"]);\n\n//{ handType: 7,\n//  handRank: 148,\n//  value: 28820,\n//  handName: 'full house' }\n\nPokerEvaluator.evalHand([\"As\", \"Ac\", \"Qs\"]);\n\n//{ handType: 2,\n//  handRank: 2761,\n//  value: 10953,\n//  handName: 'one pair' }\n\n```\n"
  },
  {
    "path": "test/poker-evaluator.spec.js",
    "content": "const PokerEvaluator = require('../lib/PokerEvaluator');\n\ndescribe('evalHand', function() {\n  describe('should throw', function() {\n    it('if 4 cards', function() {\n      expect(function() {\n        PokerEvaluator.evalHand(['As', 'Ac', 'Ad', '5s']);\n      }).toThrow();\n    });\n    it('if 8 cards', function() {\n      expect(function() {\n        PokerEvaluator.evalHand([\n          'As',\n          'Ac',\n          'Ad',\n          '5s',\n          'Ad',\n          'Ah',\n          '5c',\n          '5s'\n        ]);\n      }).toThrow();\n    });\n  });\n  it('5 cards, full house', function() {\n    expect(PokerEvaluator.evalHand(['As', 'Ac', 'Ad', '5d', '5s'])).toEqual({\n      handType: 7,\n      handRank: 148,\n      value: 28820,\n      handName: 'full house'\n    });\n  });\n  it('3 cards, one pair', function() {\n    expect(PokerEvaluator.evalHand(['As', 'Ac', 'Qs'])).toEqual({\n      handType: 2,\n      handRank: 2761,\n      value: 10953,\n      handName: 'one pair'\n    });\n  });\n  it('7 cards, straight flush', function() {\n    expect(\n      PokerEvaluator.evalHand(['As', 'Ks', 'Qs', 'Js', 'Ts', '3c', '5h'])\n    ).toEqual({\n      handType: 9,\n      handRank: 10,\n      value: 36874,\n      handName: 'straight flush'\n    });\n  });\n});\n"
  },
  {
    "path": "test/speedtest.js",
    "content": "var evaluator = require(\"..\");\nvar path = require(\"path\");\nvar assert = require(\"assert\");\n\nfunction enumerateAllHands() {\n  var u0, u1, u2, u3, u4, u5;\n  var c0, c1, c2, c3, c4, c5, c6;\n  var handTypeSum = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n  var count = 0;\n\n  console.log(\"Enumerating and evaluating all 133,784,560 possible 7-card poker hands...\\n\");\n\n  var startTime = Date.now();\n\n  for (c0 = 1; c0 < 47; c0++) {\n    u0 = evaluator.evalCard(53+c0);\n    for (c1 = c0+1; c1 < 48; c1++) {\n      u1 = evaluator.evalCard(u0+c1);\n      for (c2 = c1+1; c2 < 49; c2++) {\n        u2 = evaluator.evalCard(u1+c2);\n        for (c3 = c2+1; c3 < 50; c3++) {\n          u3 = evaluator.evalCard(u2+c3);\n          for (c4 = c3+1; c4 < 51; c4++) {\n            u4 = evaluator.evalCard(u3+c4);\n            for (c5 = c4+1; c5 < 52; c5++) {\n              u5 = evaluator.evalCard(u4+c5);\n              for (c6 = c5+1; c6 < 53; c6++) {\n\n                handTypeSum[evaluator.evalCard(u5+c6) >> 12]++;\n                count++;\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n\n  var endTime = Date.now();\n\n  console.log(\"BAD:              %d\\n\", handTypeSum[0]);\n  console.log(\"High Card:        %d\\n\", handTypeSum[1]);\n  console.log(\"One Pair:         %d\\n\", handTypeSum[2]);\n  console.log(\"Two Pair:         %d\\n\", handTypeSum[3]);\n  console.log(\"Trips:            %d\\n\", handTypeSum[4]);\n  console.log(\"Straight:         %d\\n\", handTypeSum[5]);\n  console.log(\"Flush:            %d\\n\", handTypeSum[6]);\n  console.log(\"Full House:       %d\\n\", handTypeSum[7]);\n  console.log(\"Quads:            %d\\n\", handTypeSum[8]);\n  console.log(\"Straight Flush:   %d\\n\", handTypeSum[9]);\n\n  // Perform sanity checks.. make sure numbers are where they should be\n  var testCount = 0;\n  for (var index = 0; index < 10; index++)\n    testCount += handTypeSum[index];\n  assert(testCount === count);\n  assert(count === 133784560);\n  assert(handTypeSum[0] === 0);\n\n  console.log(\"\\nEnumerated \" + count + \" hands in \" + (endTime - startTime) + \" milliseconds!\\n\");\n}\n\nassert.equal(evaluator.CARDS['as'], 52);\nassert.equal(evaluator.HANDTYPES.length, 10);\nassert.deepEqual(evaluator.eval([1, 2, 3, 4, 5]), {\n  handType: 8,\n  handName: 'four of a kind',\n  value: 32769,\n  handRank: 1\n});\n\nenumerateAllHands();\n"
  }
]