Created
May 27, 2015 19:59
-
-
Save naphthalene/ce634677863dbfc8f249 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, | |
hasProp = {}.hasOwnProperty; | |
var SUITS = ["H", "D", "S", "C"]; | |
var CARDS = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]; | |
var RANKS = ["HC", "1P", "2P", "3K", "ST", "FL", "FH", "4K", "SF", "RF"]; | |
var HighCard = (function() { | |
function HighCard(hand1) { | |
this.hand = hand1; | |
this.rank = "HC"; | |
} | |
HighCard.prototype.intcmp = function(a, b) { | |
if (a > b) { | |
return 1; | |
} else if (a < b) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}; | |
HighCard.prototype.zipcmp = function(a, b) { | |
var reduceFun, t; | |
t = this; | |
if (a.length !== b.length) { | |
if (a.length > b.length) { | |
return 1; | |
} else { | |
return -1; | |
} | |
} else { | |
reduceFun = function(p, e, i, _) { | |
if (p !== 0) { | |
return p; | |
} else { | |
return t.intcmp(e, b[i]); | |
} | |
}; | |
return a.reduce(reduceFun, 0); | |
} | |
}; | |
HighCard.prototype.rankcmp = function(other) { | |
var r1i, r2i; | |
if (other === null) { | |
return 1; | |
} | |
r1i = RANKS.indexOf(this.rank); | |
r2i = RANKS.indexOf(other.rank); | |
if (r1i > r2i) { | |
return 1; | |
} else { | |
if (r1i < r2i) { | |
return -1; | |
} else { | |
console.log("Same rank: " + this.rank + ", using tiebreaker..."); | |
return this.tiebreaker(other); | |
} | |
} | |
}; | |
HighCard.prototype.val = function(c) { | |
return ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"].indexOf(c.slice(0, -1)); | |
}; | |
HighCard.prototype.tiebreaker = function(other) { | |
var cmp, mapf, myHC, oHC, reducef, t; | |
t = this; | |
reducef = function(p, c, i, a) { | |
if (c > p) { | |
return c; | |
} else { | |
return p; | |
} | |
}; | |
mapf = function(c) { | |
return t.val(c); | |
}; | |
myHC = this.hand.map(mapf).reduce(reducef, -1); | |
oHC = other.hand.map(mapf).reduce(reducef, -1); | |
cmp = this.intcmp(myHC, oHC); | |
if (cmp === 0) { | |
console.log("High cards are the same: " + myHC); | |
return this.zipcmp(this.hand.map(mapf), other.hand.map(mapf)); | |
} else { | |
return cmp; | |
} | |
}; | |
return HighCard; | |
})(); | |
var OnePair = (function(superClass) { | |
extend(OnePair, superClass); | |
function OnePair(hand1, counts1, i1) { | |
this.hand = hand1; | |
this.counts = counts1; | |
this.i = i1; | |
this.rank = "1P"; | |
} | |
OnePair.prototype.tiebreaker = function(other) { | |
var myCrank, otherCrank, reduceFun; | |
myCrank = this.counts[this.i][0]; | |
otherCrank = other.counts[other.i][0]; | |
if (myCrank === otherCrank) { | |
reduceFun = function(ignore) { | |
return function(p, c, i, a) { | |
var newp; | |
if (i === ignore) { | |
return p; | |
} else { | |
newp = p; | |
newp = newp.concat([c[0]]); | |
return newp; | |
} | |
}; | |
}; | |
return this.zipcmp(this.counts.reduce(reduceFun(this.i), []), other.counts.reduce(reduceFun(other.i), [])); | |
} else { | |
if (myCrank > otherCrank) { | |
return 1; | |
} else { | |
return -1; | |
} | |
} | |
}; | |
return OnePair; | |
})(HighCard); | |
var TwoPair = (function(superClass) { | |
extend(TwoPair, superClass); | |
function TwoPair(hand1, counts1, ia) { | |
this.hand = hand1; | |
this.counts = counts1; | |
this.rank = "2P"; | |
this.i = ia[0], this.j = ia[1]; | |
} | |
TwoPair.prototype.tiebreaker = function(other) { | |
var doublesCmp, myKickerVal, mys, oKickerVal, os, reduceFun, sortIJ, t; | |
t = this; | |
sortIJ = function(i, j, c) { | |
return [i, j].map(function(e) { | |
return [e, c[e][0]]; | |
}).sort(function(a, b) { | |
return b[1] - a[1]; | |
}); | |
}; | |
mys = sortIJ(this.i, this.j, this.counts); | |
os = sortIJ(other.i, other.j, other.counts); | |
reduceFun = function(prev, curr, h, a) { | |
if (prev !== 0) { | |
return prev; | |
} else { | |
return t.intcmp(curr[1], os[h][1]); | |
} | |
}; | |
doublesCmp = mys.reduce(reduceFun, 0); | |
if (doublesCmp === 0) { | |
console.log("Two pair is the same, reviewing kicker"); | |
myKickerVal = this.counts[3 - this.i - this.j][0]; | |
oKickerVal = other.counts[3 - other.i - other.j][0]; | |
return this.intcmp(myKickerVal, oKickerVal); | |
} else { | |
return doublesCmp; | |
} | |
}; | |
return TwoPair; | |
})(HighCard); | |
var ThreeOfAKind = (function(superClass) { | |
extend(ThreeOfAKind, superClass); | |
function ThreeOfAKind(hand1, counts1, ti1) { | |
this.hand = hand1; | |
this.counts = counts1; | |
this.ti = ti1; | |
this.rank = "3K"; | |
} | |
ThreeOfAKind.prototype.tiebreaker = function(other) { | |
var cmp, srf; | |
cmp = this.intcmp(this.counts[this.ti][0], other.counts[other.ti][0]); | |
if (cmp !== 0) { | |
cmp; | |
} else { | |
srf = function(ti) { | |
return function(p, c, i, e) { | |
var newp; | |
if (i === ti) { | |
return p; | |
} else { | |
newp = p; | |
newp = newp.concat([c[0]]); | |
return newp; | |
} | |
}; | |
}; | |
} | |
return this.zipcmp(this.counts.reduce(srf(this.ti), []), other.counts.reduce(srf(other.ti), [])); | |
}; | |
return ThreeOfAKind; | |
})(HighCard); | |
var Straight = (function(superClass) { | |
extend(Straight, superClass); | |
function Straight(hand1, sh) { | |
this.hand = hand1; | |
this.sh = sh; | |
this.rank = "ST"; | |
} | |
Straight.prototype.tiebreaker = function(other) { | |
return this.intcmp(this.sh, other.sh); | |
}; | |
return Straight; | |
})(HighCard); | |
var Flush = (function(superClass) { | |
extend(Flush, superClass); | |
function Flush(hand1) { | |
this.hand = hand1; | |
this.rank = "FL"; | |
} | |
Flush.prototype.tiebreaker = function(other) { | |
var h, oh; | |
h = this.hand; | |
h.reverse(); | |
oh = other.hand; | |
oh.reverse(); | |
return this.zipcmp(h, oh); | |
}; | |
return Flush; | |
})(HighCard); | |
var FullHouse = (function(superClass) { | |
extend(FullHouse, superClass); | |
function FullHouse(hand1, counts1, fhi) { | |
this.hand = hand1; | |
this.counts = counts1; | |
this.fhi = fhi; | |
this.rank = "FH"; | |
} | |
FullHouse.prototype.tiebreaker = function(other) { | |
var cmp; | |
cmp = this.intcmp(this.counts[this.fhi][0], other.counts[other.fhi][0]); | |
if (cmp !== 0) { | |
return cmp; | |
} else { | |
return this.intcmp(this.counts[1 - this.fhi][0], other.counts[1 - other.fhi][0]); | |
} | |
}; | |
return FullHouse; | |
})(HighCard); | |
var FourOfAKind = (function(superClass) { | |
extend(FourOfAKind, superClass); | |
function FourOfAKind(hand1, counts1, fki) { | |
this.hand = hand1; | |
this.counts = counts1; | |
this.fki = fki; | |
this.rank = "4K"; | |
} | |
FourOfAKind.prototype.tiebreaker = function(other) { | |
var cmp; | |
cmp = this.intcmp(this.counts[this.fki][0], other.counts[other.fki][0]); | |
if (cmp !== 0) { | |
return cmp; | |
} else { | |
return this.intcmp(this.counts[1 - this.fki][0], other.counts[1 - other.fki][0]); | |
} | |
}; | |
return FourOfAKind; | |
})(HighCard); | |
var StraightFlush = (function(superClass) { | |
extend(StraightFlush, superClass); | |
function StraightFlush(hand1, sh) { | |
this.hand = hand1; | |
this.sh = sh; | |
this.rank = "SF"; | |
} | |
return StraightFlush; | |
})(Straight); | |
var RoyalFlush = (function(superClass) { | |
extend(RoyalFlush, superClass); | |
function RoyalFlush(hand1) { | |
this.hand = hand1; | |
this.rank = "RF"; | |
} | |
RoyalFlush.prototype.tiebreaker = function(other) { | |
return 0; | |
}; | |
return RoyalFlush; | |
})(HighCard); | |
var combinations = function(arr, k) { | |
var len, reduceFun, t; | |
len = arr.length; | |
if (k > len) { | |
return []; | |
} else if (!k) { | |
return [[]]; | |
} else if (k === len) { | |
return [arr]; | |
} else { | |
reduceFun = function(acc, val, i) { | |
return acc.concat(combinations(arr.slice(i + 1), k - 1).map( | |
function(comb) { | |
return [val].concat(comb); | |
})); | |
}; | |
return arr.reduce(reduceFun, []); | |
} | |
}; | |
var sortHand = function(hand) { | |
var sortFun; | |
sortFun = function(a, b) { | |
if (a.slice(0, -1) === b.slice(0, -1)) { | |
return 0; | |
} else { | |
return CARDS.indexOf(a.slice(0, -1)) > CARDS.indexOf(b.slice(0, -1)); | |
} | |
}; | |
return hand.sort(sortFun); | |
}; | |
var computeWinner = function(players, cc) { | |
var evalRank, suit, val; | |
val = function(c) { | |
return CARDS.indexOf(c.slice(0, -1)); | |
}; | |
suit = function(c) { | |
return c.slice(-1)[0]; | |
}; | |
evalRank = function(bestPlayer, player, i, a) { | |
var bh, bhcmp, combProcess, e, ls; | |
e = player.hand; | |
e = e.concat(cc.flop); | |
e.push(cc.turn); | |
e.push(cc.river); | |
e = sortHand(e); | |
console.log("Player " + players[i].name + " has this sorted hand: " + e); | |
console.log("Current best players are: " + bestPlayer.ls); | |
console.log("Current best hand is: " + bestPlayer.hand); | |
combProcess = function(bestHand, ce, ci, ca) { | |
var FH, checkStraight, cmp, counts, flush, hrank, onePair, quad, quadOrFH, ref, royalFlush, straight, strtVal, trips, tripsOrTwoPair, twoPair, twoPairFinder; | |
try { | |
counts = dupCounts(ce.map(function(e) { | |
return val(e); | |
})); | |
flush = ce.every(function(cae, cai, caa) { | |
return !cai || suit(cae) === suit(caa[0]); | |
}); | |
checkStraight = function(sp, sc, si, sa) { | |
var cmp, ref, special, valcomp; | |
valcomp = function(x, y) { | |
var specialAce; | |
specialAce = x === 12 && si === 4 && !val(sa[0]); | |
return [specialAce || x === y + 1, specialAce]; | |
}; | |
ref = valcomp(val(sc), sp[1]), cmp = ref[0], special = ref[1]; | |
return [!si || (sp[0] && cmp), special ? 3 : val(sc)]; | |
}; | |
ref = ce.reduce(checkStraight, [true, -1]), straight = ref[0], strtVal = ref[1]; | |
royalFlush = flush && straight && strtVal === 12; | |
quadOrFH = counts.length === 2; | |
quad = quadOrFH ? [0, 1].map(function(i) { | |
return counts[i][1] === 4; | |
}).indexOf(true) : false; | |
FH = quadOrFH ? [0, 1].map(function(i) { | |
return counts[i][1] === 3; | |
}).indexOf(true) : false; | |
tripsOrTwoPair = counts.length === 3; | |
trips = tripsOrTwoPair ? [0, 1, 2].map(function(i) { | |
return counts[i][1] === 3; | |
}).indexOf(true) : false; | |
twoPairFinder = function(acc, ia) { | |
var twop; | |
twop = counts[ia[0]][1] === 2 && counts[ia[1]][1] === 2; | |
if (acc[0]) { | |
return acc; | |
} else if (twop) { | |
return [true, ia]; | |
} else { | |
return acc; | |
} | |
}; | |
twoPair = tripsOrTwoPair ? combinations([0, 1, 2], 2).reduce(twoPairFinder, [false, null]) : false; | |
onePair = counts.length === 4 ? [0, 1].map(function(i) { | |
return counts[i][1] === 2; | |
}).indexOf(true) : false; | |
hrank = royalFlush ? new RoyalFlush(ce) : straight && flush ? new StraightFlush(ce, strtVal) : quad !== false && quad !== -1 ? new FourOfAKind(ce, counts, quad) : FH !== false && FH !== -1 ? new FullHouse(ce, counts, FH) : flush ? new Flush(ce) : straight ? new Straight(ce) : trips !== false && trips !== -1 ? new ThreeOfAKind(ce, counts, trips) : twoPair !== false && twoPair[0] ? new TwoPair(ce, counts, twoPair[1]) : onePair !== false && onePair !== -1 ? new OnePair(ce, counts, onePair) : new HighCard(ce); | |
cmp = hrank.rankcmp(bestHand); | |
if (cmp > 0) { | |
console.log("new best: " + hrank.rank + ": "+hrank.hand); | |
return hrank; | |
} else { | |
return bestHand; | |
} | |
return ret; | |
} catch (_error) { | |
e = _error; | |
return console.error(e.stack); | |
} | |
}; | |
bh = combinations(e, 5).reduce(combProcess, null); | |
bhcmp = bh.rankcmp(bestPlayer.best); | |
console.log("Best rank for player " + player.name + ": " | |
+ bh.rank + "(" + bh.hand + ")"); | |
if (bhcmp === 0) { | |
console.log("Player has matched " + bestPlayer); | |
ls = bestPlayer.ls; | |
ls.push(i); | |
return { | |
best: bestPlayer.best, | |
ls: ls | |
}; | |
} else if (bhcmp > 1) { | |
return { | |
best: bh, | |
ls: [i] | |
}; | |
} else { | |
return bestPlayer; | |
} | |
}; | |
return players.reduce(evalRank, { | |
best: null, | |
ls: [] | |
}); | |
}; | |
var dupCounts = function(arr) { | |
var appendDup; | |
appendDup = function(p, c, i, a) { | |
var newp; | |
if (p[0] !== c) { | |
newp = p[2]; | |
if (p[0] !== null) { | |
newp = newp.concat([[p[0], p[1]]]); | |
} | |
if (i === a.length - 1) { | |
newp = newp.concat([[c, 1]]); | |
} | |
return [c, 1, newp]; | |
} else { | |
if (i === a.length - 1) { | |
newp = p[2]; | |
newp = newp.concat([[p[0], ++p[1]]]); | |
return [p[0], p[1], newp]; | |
} else { | |
return [p[0], ++p[1], p[2]]; | |
} | |
} | |
}; | |
return arr.reduce(appendDup, [null, 0, []])[2]; | |
}; | |
var scenario1 = | |
{ | |
players: [ | |
{ | |
name: "aaron", | |
hand: ["5D", "6D"] | |
}, | |
{ | |
name: "blart", | |
hand: ["JC", "QS"] | |
}, | |
{ | |
name: "caren", | |
hand: ["JD", "AS"] | |
} | |
], | |
cc: { | |
flop: ["2H", "2D", "4D"], | |
turn: "10H", river: "QC" | |
} | |
}; | |
var processScenario = function(scen) { | |
console.log("Scenario: " + JSON.stringify(scen)); | |
var winners = computeWinner(scen.players, scen.cc); | |
console.log("Winners: " + JSON.stringify(winners)); | |
}; | |
[scenario1].map(processScenario); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment