(function() { // Return the greatest element of an array. function max(arr) { var maximum = arr[0]; for (var i in arr) { if (arr[i] > maximum) maximum = arr[i]; } return maximum; } // Return true if all elements in arr are true, false otherwise. function all(arr) { for (var i in arr) { if (!arr[i]) return false; } return true; } function sum(arr) { var n = 0; for (var i in arr) { n += arr[i]; } return n; } // Return all combinations of the elements in arr function powerset(arr) { var set = []; for (var i = 0, pow = Math.pow(2, arr.length); i < pow; ++i) { var subset = []; for (var j = 0; j < arr.length; ++j) { if (1< -1) && (suits.indexOf(this.suit) > -1); }; Cribbage.Card.prototype.toString = function() { return ""; } // Count points from all individual methods Cribbage.Hand.prototype.count = function() { return this.countPairs() + this.countFifteens() + this.countJack() + this.countFlush() + this.countStraight(); }; // 2 points for every pair (same rank) Cribbage.Hand.prototype.countPairs = function() { var pset = powerset(this.cards); var n = 0; for (var i in pset) { var set = pset[i]; if (set.length == 2 && set[0].rank == set[1].rank) n += 2 } return n; }; // 2 points for all combinations that add up to 15 Cribbage.Hand.prototype.countFifteens = function() { var pset = powerset(this.cards); var n = 0; for (var i in pset) { var set = pset[i]; if (sum(set.map(function(card) { return card.value })) == 15) n += 2; } return n }; // 1 point if a jack in your hand has the same suit as the starter card. Cribbage.Hand.prototype.countJack = function() { for (i in this.hand) { if (this.hand[i].rank == 'jack' && this.hand[i].suit == this.starterCard.suit) return 1; } return 0; }; // 1 point per card in a flush. All the cards in the hand need to be of the same suit. // If the hand is a crib, the starter card must also have the same suit. Cribbage.Hand.prototype.countFlush = function() { function _countFlush(cards) { var suits = cards.map(function(card) { return card.suit == cards[0].suit; }); if (all(suits)) return cards.length; else return 0; } if (this.isCrib) { return _countFlush(this.cards); } else { return max([_countFlush(this.hand), _countFlush(this.cards)]); } }; // 1 point per card in a straight. Only straights of 3 cards and more are considered // and the longest straights are the ones counted (i.e.: if you have a straight Ace, // Two, Three, Four, this counts for four points) Cribbage.Hand.prototype.countStraight = function() { function _isStraight(arr) { var arr2 = arr.sort() for (var i = 0, length = arr2.length; i < length; ++i) { if (arr2[i] - i != arr2[0]) return false; } return true; } function _keepLongest(arr) { var longest = max(arr.map(function (x) { return x.length; })); if (longest < 3) return [[]]; return arr.filter(function(x) { return x.length == longest; }); } var pset = powerset(this.cards.map(function(card) { return card.pos; })); var straights = pset.filter(_isStraight); straights = _keepLongest(straights); var n = 0; for (var i = 0, length = straights.length; i < length; ++i) { n += straights[i].length; } return n; } // If $C and $H already exist, we back them up under the // names $_C and $_H. if (window.$C) window.$_C = window.$C; if (window.$H) window.$_H = window.$H; // Utility function to make creating a card more succinct. // e.g.: $C('AS') == new Cribbage.Card('ace', 'spade') window.$C = function(desc) { var rank = { 'A': 'ace', '2': 'two', '3': 'three', '4': 'four', '5': 'five', '6': 'six', '7': 'seven', '8': 'eight', '9': 'nine', 'T': 'ten', 'J': 'jack', 'Q': 'queen', 'K': 'king' }[desc[0]]; var suit = { 'C': 'clubs', 'D': 'diamond', 'H': 'heart', 'S': 'spade' }[desc[1]]; var card = new Cribbage.Card(rank, suit); return card.isValid() ? card : null; }; // Utility function to make creating a hand more succinct. // e.g.: $H([$C('AS')], $C('JC')) == new Cribbage.Hand([$C('AS')], $C('JC')) window.$H = function(hand, starterCard, isCrib) { return new Cribbage.Hand(hand, starterCard, isCrib); }; })();