Skip to content

Instantly share code, notes, and snippets.

@naphthalene
Created May 27, 2015 19:59
Show Gist options
  • Save naphthalene/ce634677863dbfc8f249 to your computer and use it in GitHub Desktop.
Save naphthalene/ce634677863dbfc8f249 to your computer and use it in GitHub Desktop.
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