Apps Home
|
My Uploads
|
Create an App
Raven's Games
Author:
raven_hart
Description
Source Code
Launch App
Current Users
Created by:
Raven_Hart
App Images
/* Name: Games With Raven Author: aoibheann_raven Last Modified: 2019 February 24 */ /// // Globals /// var General = { broadcasterName: cb.room_slug, roomSubject: "", }; /// // Message Event System /// var MessageType = { MSG: 1, TIP: 2, POSTTIP: 3, PREPANEL: 4, DRAWPANEL: 5, }; var MessageCenter = { listeners: [], process: function(type, payload) { for (var i=0; i<MessageCenter.listeners.length; i++) { if (MessageCenter.listeners[i].type == type) { if (type == MessageType.MSG) { payload = MessageCenter.listeners[i].process(payload); } else { MessageCenter.listeners[i].process(payload); } } } if (type == MessageType.MSG) { return payload; } else if (type == MessageType.TIP) { MessageCenter.process(MessageType.POSTTIP, payload); } }, subscribe: function(type, listener) { MessageCenter.listeners.push({'type':type,'process':listener}); }, } cb.onTip(function(tip) { MessageCenter.process(MessageType.TIP, tip); }); cb.onMessage(function (msg) { msg = MessageCenter.process(MessageType.MSG, msg); return msg; }); /// // General Chat Commands /// MessageCenter.subscribe(MessageType.MSG, function(msg) { if (msg.user==cb.room_slug && msg.m.substring(0, 1) === "/") { msg["X-Spam"] = true; if (msg.m.substring(1, 8) == "setname") { var args = msg.m.substring(9); var argsArr = args.split(" "); General.broadcasterName = argsArr[0]; } else if (msg.m.substring(1, 9) === "setprize") { var args = msg.m.substring(10); var argsArr = args.split(" "); PokerGame.overridePrize = argsArr[0]; } else if (msg.m.substring(1, 8) == "testtip") { var args = msg.m.substring(9); var argsArr = args.split(" "); var tip = { to_user: cb.room_slug, amount: argsArr[1], message: "", from_user: argsArr[0], from_user_in_fanclub: false, from_user_has_tokens: false, from_user_is_mod: false, from_user_gender: argsArr[2], from_user_tipped_recently: true, } if(!fakeusers.includes(argsArr[0])) fakeusers.push(argsArr[0]); MessageCenter.process(MessageType.TIP, tip); } else if (msg.m.substring(1, 10) === "startgame") { var args = msg.m.substring(11); var argsArr = args.split(" "); if (argsArr[0] == "poker") { PokerGame.start(); } } else if (msg.m.substring(1, 8) === "addgoal") { var args = msg.m.substring(9); var argsArr = args.split(" "); Tips.goals.push({'goalText':argsArr[0],'goalAmount':argsArr[1]}); } else if (msg.m.substring(1, 8) === "logdump") { cb.sendNotice(PokerGame, cb.room_slug); cb.sendNotice(Tips, cb.room_slug); cb.sendNotice(Tippers, cb.room_slug); cb.sendNotice(TotalHighTipper, cb.room_slug); cb.sendNotice(HighestTipTipper, cb.room_slug); cb.sendNotice(LastTipper, cb.room_slug); cb.sendNotice(Tips.getCurrentTotal(), cb.room_slug); } else if (msg.m.substring(1, 7) === "update" && TotalHighTipper.name != "") { chatNotice("--Welcome to " + General.broadcasterName + "'s Room--\n" + "Big thanks to " + TotalHighTipper.name + ", who has tipped " + TotalHighTipper.amount + " tokens tonight!\n" + "Also, thank you " + HighestTipTipper.name + " for giving me " + HighestTipTipper.amount + " tokens in a single tip!\n" + "And thank you to everyone who has tipped. You're all amazing <3", "", "#4CFDFD", "#FE4CB1"); } } return msg; }); var fakeusers = []; function chatNotice(msg, to_user, background='#477148', foreground='#FFFFFF', weight='bold', to_group) { if (to_user != undefined && to_user != "") { background = '#FFEE9B'; foreground = '#000000'; } if (fakeusers.includes(to_user)) { cb.sendNotice((to_user + ": " + msg), cb.room_slug, background, foreground, weight, to_group); } else { cb.sendNotice((msg), to_user, background, foreground, weight, to_group); } } /// // General Tip Tracking /// var Tips = { total: 0, goals: [], previousGoals: 0, getCurrentTotal: function () { return Tips.total-Tips.previousGoals; }, init: function() { MessageCenter.subscribe(MessageType.TIP, function(tip) { Tips.total += Number(tip.amount); }); }, }; Tips.init(); var Tippers = { init: function() { MessageCenter.subscribe(MessageType.TIP, function(tip) { if (Tippers[tip.from_user] === undefined) { Tippers[tip.from_user] = Number(tip.amount); } else { Tippers[tip.from_user] += Number(tip.amount); } }); }, }; Tippers.init(); var TotalHighTipper = { name: '', amount: 0, init: function() { MessageCenter.subscribe(MessageType.POSTTIP, function(tip) { if (Tippers[tip.from_user] > TotalHighTipper.amount) { TotalHighTipper.name = tip.from_user; TotalHighTipper.amount = Tippers[tip.from_user]; } }); }, }; TotalHighTipper.init(); var HighestTipTipper = { name: '', amount: 0, init: function() { MessageCenter.subscribe(MessageType.TIP, function(tip) { if(tip.amount > HighestTipTipper.amount) { HighestTipTipper.name = tip.from_user; HighestTipTipper.amount = Number(tip.amount); } }); }, }; HighestTipTipper.init(); var LastTipper = { name: '', amount: 0, init: function() { MessageCenter.subscribe(MessageType.TIP, function(tip) { LastTipper.name = tip.from_user; LastTipper.amount = Number(tip.amount); }); }, }; LastTipper.init(); /// // Poker // Card Back Vector Design by Vecteezy.com /// const blankCard = "8bc2ba96-e2dc-4759-903c-ab0ebe650671"; var Deck = { cards: ["As", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s", "Ts", "Js", "Qs", "Ks", "Ah", "2h", "3h", "4h", "5h", "6h", "7h", "8h", "9h", "Th", "Jh", "Qh", "Kh", "Ad", "2d", "3d", "4d", "5d", "6d", "7d", "8d", "9d", "Td", "Jd", "Qd", "Kd", "Ac", "2c", "3c", "4c", "5c", "6c", "7c", "8c", "9c", "Tc", "Jc", "Qc", "Kc",], joker: "0r", boardCards: [], discardPile: [], playersHands: {}, shuffle: function() { Deck.cards.push(...Deck.discardPile); Deck.discardPile = []; for (var i=Deck.cards.length-1; i>0; i--) { var j = Math.floor(Math.random() * (i+1)); var k = Deck.cards[j]; Deck.cards[j] = Deck.cards[i]; Deck.cards[i] = k; } }, deal: function(player, howMany) { if (Deck.playersHands[player] === undefined) { Deck.playersHands[player] = []; } for (var i=0; i<howMany; i++) { Deck.playersHands[player].push(Deck.cards.pop()); if (Deck.cards.length == 0) { Deck.shuffle; } } chatNotice("Your Hand: " + Deck.humanReadable(Deck.playersHands[player]) + "\nYou can see your hand at any time by typing '/myhand' without the quotes.", player); }, discardHand: function(player) { Deck.discardPile.push(...Deck.playersHands[player]); delete Deck.playersHands[player]; }, dealBoard: function(howMany) { var dealt = [] for (var i=0; i<howMany; i++) { dealt.push(Deck.cards.pop()); if (Deck.cards.length == 0) { Deck.shuffle; } } Deck.boardCards.push(...dealt); return dealt; }, humanReadable: function(hand) { cb.log(hand); var text = ""; for (var i=0; i<hand.length; i++) { if (i>0) text+=", " text += hand[i].charAt(0) + " of "; if ( hand[i].charAt(1) == 'c') text += "Clubs"; if ( hand[i].charAt(1) == 's') text += "Spades"; if ( hand[i].charAt(1) == 'd') text += "Diamonds"; if ( hand[i].charAt(1) == 'h') text += "Hearts"; } text = text.replace(new RegExp("T", 'g'), "Ten"); text = text.replace(new RegExp("J", 'g'), "Jack"); text = text.replace(new RegExp("Q", 'g'), "Queen"); text = text.replace(new RegExp("K", 'g'), "King"); text = text.replace(new RegExp("A", 'g'), "Ace"); text = text.replace(new RegExp("1", 'g'), "One"); text = text.replace(new RegExp("2", 'g'), "Two"); text = text.replace(new RegExp("3", 'g'), "Three"); text = text.replace(new RegExp("4", 'g'), "Four"); text = text.replace(new RegExp("5", 'g'), "Five"); text = text.replace(new RegExp("6", 'g'), "Six"); text = text.replace(new RegExp("7", 'g'), "Seven"); text = text.replace(new RegExp("8", 'g'), "Eight"); text = text.replace(new RegExp("9", 'g'), "Nine"); return text; }, reset: function() { for (let player of PokerGame.players) { Deck.discardHand(player); } Deck.cards.push(...Deck.discardPile); Deck.cards.push(...Deck.boardCards); Deck.discardPile = []; Deck.boardCards = []; }, handValue: function(player) { var combinedHand = Deck.playersHands[player].concat(Deck.boardCards); return Hand.solve(combinedHand, "standard"); }, addJokers: function () { Deck.cards.push(joker); Deck.cards.push(joker); }, } var PokerStages = { BUYIN: 1, FIRSTBETS: 2, SECONDBETS: 3, THIRDBETS: 4, FINALBETS: 5, } var PokerGame = { players: [], playersTips: {}, currentPlayer: 0, gameStage: PokerStages.BUYIN, timer: -1, ante: 11, currentBet: 12, gameStarting: false, lastCall: false, waitTimes: [4, 2], overridePrize: "", prizeText: function() { if (PokerGame.overridePrize != "") { return overridePrize; } return "The winner get's to control " + General.broadcasterName + "'s Lovense Hush for 1 minute."; }, start: function() { MessageCenter.subscribe(MessageType.TIP, function(tip) { if (PokerGame.playersTips[tip.from_user]==undefined && !(tip.amount == PokerGame.ante && PokerGame.gameStage == PokerStages.BUYIN)) { return; } else if (PokerGame.playersTips[tip.from_user]==undefined) { PokerGame.players.push(tip.from_user); PokerGame.playersTips[tip.from_user] = Number(tip.amount); Deck.deal(tip.from_user, 2); if (!PokerGame.gameStarting && PokerGame.players.length > 1) { PokerGame.gameStarting = true; chatNotice("Betting will begin in " + PokerGame.waitTimes[0] + " minutes."); PokerGame.timer = cb.setTimeout(PokerGame.progress, ((PokerGame.waitTimes[0] * 60000) - 60000)); } } else if (tip.from_user == PokerGame.players[PokerGame.currentPlayer]) { PokerGame.playersTips[tip.from_user] += Number(tip.amount); if (PokerGame.playersTips[tip.from_user] == PokerGame.currentBet) { chatNotice(tip.from_user + " has called."); PokerGame.advancePlayer(false); } else if (PokerGame.playersTips[tip.from_user] > PokerGame.currentBet) { PokerGame.currentBet = Number(PokerGame.playersTips[tip.from_user]); chatNotice(tip.from_user + " has raised."); PokerGame.advancePlayer(false); } } }); MessageCenter.subscribe(MessageType.MSG, function(msg) { if (PokerGame.playersTips[msg.user] == undefined && msg.user!=cb.room_slug) { return; } if (msg.user==cb.room_slug && msg.m.substring(0, 1) === "/") { msg["X-Spam"] = true; if (msg.m.substring(1, 7) == "update") { var round; switch(PokerGame.gameStage) { case PokerStages.BUYIN: round = "Buy In: Tip " + PokerGame.ante + " tokens to join the game."; break; case PokerStages.FIRSTBETS: round = "First Round of Betting.\n" + "Current bet: " + PokerGame.currentBet + " Tokens"; break; case PokerStages.SECONDBETS: round = "Second Round of Betting.\n" + "Current bet: " + PokerGame.currentBet + " Tokens"; break; case PokerStages.THIRDBETS: round = "Third Round of Betting.\n" + "Current bet: " + PokerGame.currentBet + " Tokens"; break; case PokerStages.FINALBETS: round = "Final Round of Betting.\n" + "Current bet: " + PokerGame.currentBet + " Tokens"; break; } var board = ""; if (Deck.boardCards > 0) { board = "\nThe Current Board: " + Deck.humanReadable(Deck.boardCards) } chatNotice("--" + General.broadcasterName + "'s Poker Game--\n" + "Current Players: " + PokerGame.players.length + "\n" + "Round: " + round + board); } } else if (msg.m.substring(0, 1) === "/") { msg["X-Spam"] = true; if (msg.m.substring(1, 7) == "myhand") { chatNotice("Your Hand: " + Deck.humanReadable(Deck.playersHands[msg.user]) + "\nThe Board: " + Deck.humanReadable(Deck.boardCards), msg.user); } } return msg; }); Deck.shuffle(); chatNotice("****" + General.broadcasterName + " has started a game of Texas Hold'em****\n" + "Tip " + PokerGame.ante + " tokens before the first round of betting to join.\n" + PokerGame.prizeText()); }, progress: function() { if (PokerGame.gameStage == PokerStages.BUYIN && !PokerGame.lastCall) { PokerGame.lastCall = true; chatNotice("Last chance to join the game.\n" + "Betting will begin in 1 minute."); PokerGame.timer = cb.setTimeout(PokerGame.progress, 60000); } else if (PokerGame.gameStage == PokerStages.BUYIN) { PokerGame.lastCall = false; PokerGame.gameStage++; chatNotice(PokerGame.players[PokerGame.currentPlayer] + " is now betting."); chatNotice("Tip " + (PokerGame.currentBet - PokerGame.playersTips[PokerGame.players[PokerGame.currentPlayer]]) + " token(s) to call. Tip a larger amount to raise.\n" + "Type '/fold' without the quotes to fold the hand.", PokerGame.players[PokerGame.currentPlayer]); cb.cancelTimeout(PokerGame.timer); PokerGame.timer = cb.setTimeout(PokerGame.progress, ((PokerGame.waitTimes[1] * 60000) - 60000)); } if (PokerGame.gameStage >= PokerStages.FIRSTBETS && !PokerGame.lastCall) { PokerGame.lastCall = true; chatNotice("In less than 1 minute you will automatically fold.\n" + "Tip " + (PokerGame.currentBet - PokerGame.playersTips[PokerGame.players[PokerGame.currentPlayer]]) + " token(s) to call. Tip a larger amount to raise.", PokerGame.players[PokerGame.currentPlayer]); cb.cancelTimeout(PokerGame.timer); PokerGame.timer = cb.setTimeout(PokerGame.progress, 60000); } else if (PokerGame.gameStage >= PokerGame.FIRSTBETS && PokerGame.lastCall) { var foldingPlayer = PokerGame.players[PokerGame.currentPlayer]; Deck.discardHand(foldingPlayer); PokerGame.players.splice(PokerGame.currentPlayer, 1); delete PokerGame.playersTips[foldingPlayer]; chatNotice(foldingPlayer + " automatically folded."); PokerGame.advancePlayer(true); } }, advancePlayer: function(previousFold) { cb.cancelTimeout(PokerGame.timer); if (!previousFold) { PokerGame.currentPlayer++; } if(PokerGame.currentPlayer >= PokerGame.players.length) { PokerGame.currentPlayer = 0; } if (PokerGame.roundEnd()) { PokerGame.currentPlayer = 0; PokerGame.currentBet++; switch(PokerGame.gameStage) { case PokerStages.FIRSTBETS: Deck.dealBoard(3); chatNotice("The first round of betting has ended.\n" + "The Flop: " + Deck.humanReadable(Deck.boardCards) + "\n" + "The second round of betting has begun."); PokerGame.gameStage++; break; case PokerStages.SECONDBETS: var turn = Deck.dealBoard(1); chatNotice("The second round of betting has ended.\n" + "The Turn: " + Deck.humanReadable(turn) + "\nCurrent Board: " + Deck.humanReadable(Deck.boardCards) + "\n" + "The third round of betting has begun."); PokerGame.gameStage++; break; case PokerStages.THIRDBETS: var river = Deck.dealBoard(1); chatNotice("The third round of betting has ended.\n" + "The River: " + Deck.humanReadable(river) + "\nCurrent Board: " + Deck.humanReadable(Deck.boardCards) + "\n" + "The finale round of betting has begun."); PokerGame.gameStage++; break; case PokerStages.FINALBETS: chatNotice("The final round of betting has ended.\n\n" + "---THE SHOWDOWN---"); PokerGame.lastCall = false; PokerGame.showdown(); return; } } PokerGame.lastCall = false; chatNotice(PokerGame.players[PokerGame.currentPlayer] + " is now betting."); chatNotice("Tip " + (PokerGame.currentBet - PokerGame.playersTips[PokerGame.players[PokerGame.currentPlayer]]) + " token(s) to call. Tip a larger amount to raise.\nType '/fold' without the quotes to fold the hand.", PokerGame.players[PokerGame.currentPlayer]); PokerGame.timer = cb.setTimeout(PokerGame.progress, ((PokerGame.waitTimes[1] * 60000) - 60000)); }, roundEnd: function() { for (var i=0; i<PokerGame.players.length; i++) { if (PokerGame.playersTips[PokerGame.players[i]] < PokerGame.currentBet) { return false; } } return true; }, showdown: function() { var hands = []; var winners = []; for (let player of PokerGame.players) { var hand = Deck.handValue(player); hands.push({"player": player, "hand": hand,}); winners.push(hand); } for (let player of hands) { chatNotice(player.player + " has a " + player.hand.descr + ".\n" + Deck.humanReadable(Deck.playersHands[player.player])); } winners = Hand.winners(winners); for (let player of hands) { if (winners.includes(player.hand)) { chatNotice(player.player + " won."); } } if (winners.length > 1) { chatNotice("Oh, gosh! " + winners.length + " winners!\n" + "All winners get the advertised prize.", "", "#4CFDFD", "#FE4CB1"); } Deck.reset(); PokerGame.gameStarting = false; PokerGame.players = []; PokerGame.playersTips = {}; PokerGame.currentPlayer = 0; PokerGame.gameStage = PokerStages.BUYIN; PokerGame.timer = -1; PokerGame.ante = 11; PokerGame.currentBet = 12; PokerGame.lastCall = false; Deck.shuffle(); chatNotice(General.broadcasterName + " has started a new game of Texas Hold'em, " + "the ante is " + PokerGame.ante + ".\n" + PokerGame.prizeText()); }, } /// // Helper Functions /// function arrayRemove(arr, value) { return arr.filter(function(ele){ return ele != value; }); } /// // Third party code /// /** * pokersolver v2.1.2 * Copyright (c) 2016, James Simpson of GoldFire Studios * http://goldfirestudios.com * * License: https://github.com/goldfire/pokersolver/blob/master/LICENSE.md */ // NOTE: The 'joker' will be denoted with a value of 'O' and any suit. var values = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']; /** * Base Card class that defines a single card. */ class Card { constructor(str) { this.value = str.substr(0, 1); this.suit = str.substr(1, 1).toLowerCase(); this.rank = values.indexOf(this.value); this.wildValue = str.substr(0, 1); } toString() { return this.wildValue.replace('T', '10') + this.suit; } static sort(a, b) { if (a.rank > b.rank) { return -1; } else if (a.rank < b.rank) { return 1; } else { return 0; } } } /** * Base Hand class that handles comparisons of full hands. */ class Hand { constructor(cards, name, game, canDisqualify) { this.cardPool = []; this.cards = []; this.suits = {}; this.values = []; this.wilds = []; this.name = name; this.game = game; this.sfLength = 0; this.alwaysQualifies = true; // Qualification rules apply for dealer's hand. // Also applies for single player games, like video poker. if (canDisqualify && this.game.lowestQualified) { this.alwaysQualifies = false; } // Get rank based on game. var handRank = this.game.handValues.length; for (var i=0; i<this.game.handValues.length; i++) { if (this.game.handValues[i] === this.constructor) { break; } } this.rank = handRank - i; // Set up the pool of cards. this.cardPool = cards.map(function(c) { return (typeof c === 'string') ? new Card(c) : c; }); // Fix the card ranks for wild cards, and sort. for (var i=0; i<this.cardPool.length; i++) { card = this.cardPool[i]; if (card.value === this.game.wildValue) { card.rank = -1; } } this.cardPool = this.cardPool.sort(Card.sort); // Create the arrays of suits and values. var obj, obj1, key, key1, card; for (var i=0; i<this.cardPool.length; i++) { // Make sure this value already exists in the object. card = this.cardPool[i]; // We do something special if this is a wild card. if (card.rank === -1) { this.wilds.push(card); } else { (obj = this.suits)[key = card.suit] || (obj[key] = []); (obj1 = this.values)[key1 = card.rank] || (obj1[key1] = []); // Add the value to the array for that type in the object. this.suits[card.suit].push(card); this.values[card.rank].push(card); } } this.values.reverse(); this.isPossible = this.solve(); } /** * Compare current hand with another to determine which is the winner. * @param {Hand} a Hand to compare to. * @return {Number} */ compare(a) { if (this.rank < a.rank) { return 1; } else if (this.rank > a.rank) { return -1; } var result = 0; for (var i=0; i<=4; i++) { if (this.cards[i] && a.cards[i] && this.cards[i].rank < a.cards[i].rank) { result = 1; break; } else if (this.cards[i] && a.cards[i] && this.cards[i].rank > a.cards[i].rank) { result = -1; break; } } return result; } /** * Determine whether a hand loses to another. * @param {Hand} hand Hand to compare to. * @return {Boolean} */ loseTo(hand) { return (this.compare(hand) > 0); } /** * Determine the number of cards in a hand of a rank. * @param {Number} val Index of this.values. * @return {Number} Number of cards having the rank, including wild cards. */ getNumCardsByRank(val) { var cards = this.values[val]; var checkCardsLength = (cards) ? cards.length : 0; for (var i=0; i<this.wilds.length; i++) { if (this.wilds[i].rank > -1) { continue; } else if (cards) { if (this.game.wildStatus === 1 || cards[0].rank === values.length - 1) { checkCardsLength += 1; } } else if (this.game.wildStatus === 1 || val === values.length - 1) { checkCardsLength += 1; } } return checkCardsLength; } /** * Determine the cards in a suit for a flush. * @param {String} suit Key for this.suits. * @param {Boolean} setRanks Whether to set the ranks for the wild cards. * @return {Array} Cards having the suit, including wild cards. */ getCardsForFlush(suit, setRanks) { var cards = (this.suits[suit] || []).sort(Card.sort); for (var i=0; i<this.wilds.length; i++) { var wild = this.wilds[i]; if (setRanks) { var j=0; while (j<values.length && j<cards.length) { if (cards[j].rank === values.length-1-j) { j += 1; } else { break; } } wild.rank = values.length-1-j; wild.wildValue = values[wild.rank]; } cards.push(wild); cards = cards.sort(Card.sort); } return cards; } /** * Resets the rank and wild values of the wild cards. */ resetWildCards() { for (var i=0; i<this.wilds.length; i++) { this.wilds[i].rank = -1; this.wilds[i].wildValue = this.wilds[i].value; } } /** * Highest card comparison. * @return {Array} Highest cards */ nextHighest() { var picks; var excluding = []; excluding = excluding.concat(this.cards); picks = this.cardPool.filter(function(card) { if (excluding.indexOf(card) < 0) { return true; } }); // Account for remaining wild card when it must be ace. if (this.game.wildStatus === 0) { for (var i=0; i<picks.length; i++) { var card = picks[i]; if (card.rank === -1) { card.wildValue = 'A'; card.rank = values.length - 1; } } picks = picks.sort(Card.sort); } return picks; } /** * Return list of contained cards in human readable format. * @return {String} */ toString() { var cards = this.cards.map(function(c) { return c.toString(); }); return cards.join(', '); } /** * Return array of contained cards. * @return {Array} */ toArray() { var cards = this.cards.map(function(c) { return c.toString(); }); return cards; } /** * Determine if qualifying hand. * @return {Boolean} */ qualifiesHigh() { if (!this.game.lowestQualified || this.alwaysQualifies) { return true; } return (this.compare(Hand.solve(this.game.lowestQualified, this.game)) <= 0); } /** * Find highest ranked hands and remove any that don't qualify or lose to another hand. * @param {Array} hands Hands to evaluate. * @return {Array} Winning hands. */ static winners(hands) { hands = hands.filter(function(h) { return h.qualifiesHigh(); }); var highestRank = Math.max.apply(Math, hands.map(function(h) { return h.rank; })); hands = hands.filter(function(h) { return h.rank === highestRank; }); hands = hands.filter(function(h) { var lose = false; for (var i=0; i<hands.length; i++) { lose = h.loseTo(hands[i]); if (lose) { break; } } return !lose; }); return hands; } /** * Build and return the best hand. * @param {Array} cards Array of cards (['Ad', '3c', 'Th', ...]). * @param {String} game Game being played. * @param {Boolean} canDisqualify Check for a qualified hand. * @return {Hand} Best hand. */ static solve(cards, game, canDisqualify) { game = game || 'standard'; game = (typeof game === 'string') ? new Game(game) : game; cards = cards || ['']; var hands = game.handValues; var result = null; for (var i=0; i<hands.length; i++) { result = new hands[i](cards, game, canDisqualify); if (result.isPossible) { break; } } return result; } /** * Separate cards based on if they are wild cards. * @param {Array} cards Array of cards (['Ad', '3c', 'Th', ...]). * @param {Game} game Game being played. * @return {Array} [wilds, nonWilds] Wild and non-Wild Cards. */ static stripWilds(cards, game) { var card, wilds, nonWilds; cards = cards || ['']; wilds = []; nonWilds = []; for (var i=0; i<cards.length; i++) { card = cards[i]; if (card.rank === -1) { wilds.push(cards[i]); } else { nonWilds.push(cards[i]); } } return [wilds, nonWilds]; } } class StraightFlush extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Straight Flush', game, canDisqualify); } solve() { var cards; this.resetWildCards(); var possibleStraight = null; var nonCards = []; for (var suit in this.suits) { cards = this.getCardsForFlush(suit, false); if (cards && cards.length >= this.game.sfQualify) { possibleStraight = cards; break; } } if (possibleStraight) { for (var suit in this.suits) { if (possibleStraight[0].suit !== suit) { nonCards = nonCards.concat(this.suits[suit] || []); nonCards = Hand.stripWilds(nonCards, this.game)[1]; } } var straight = new Straight(possibleStraight, this.game); if (straight.isPossible) { this.cards = straight.cards; this.cards = this.cards.concat(nonCards); this.sfLength = straight.sfLength; } } if (this.cards[0] && this.cards[0].rank === 13) { this.descr = 'Royal Flush'; } else if (this.cards.length >= this.game.sfQualify) { this.descr = this.name + ', ' + this.cards[0].toString().slice(0, -1) + suit + ' High'; } return this.cards.length >= this.game.sfQualify; } } class RoyalFlush extends StraightFlush { constructor(cards, game, canDisqualify) { super(cards, game, canDisqualify); } solve() { this.resetWildCards(); var result = super.solve(); return result && this.descr === 'Royal Flush'; } } class NaturalRoyalFlush extends RoyalFlush { constructor(cards, game, canDisqualify) { super(cards, game, canDisqualify); } solve() { var i = 0; this.resetWildCards(); var result = super.solve(); if (result && this.cards) { for (i=0; i<this.game.sfQualify && i<this.cards.length; i++) { if (this.cards[i].value === this.game.wildValue) { result = false; this.descr = 'Wild Royal Flush'; break; } } if (i === this.game.sfQualify) { this.descr = 'Royal Flush'; } } return result; } } class WildRoyalFlush extends RoyalFlush { constructor(cards, game, canDisqualify) { super(cards, game, canDisqualify); } solve() { var i = 0; this.resetWildCards(); var result = super.solve(); if (result && this.cards) { for (i=0; i<this.game.sfQualify && i<this.cards.length; i++) { if (this.cards[i].value === this.game.wildValue) { this.descr = 'Wild Royal Flush'; break; } } if (i === this.game.sfQualify) { result = false; this.descr = 'Royal Flush'; } } return result; } } class FiveOfAKind extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Five of a Kind', game, canDisqualify); } solve() { this.resetWildCards(); for (var i=0; i<this.values.length; i++) { if (this.getNumCardsByRank(i) === 5) { this.cards = this.values[i] || []; for (var j=0; j<this.wilds.length && this.cards.length<5; j++) { var wild = this.wilds[j]; if (this.cards) { wild.rank = this.cards[0].rank; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-5)); break; } } if (this.cards.length >= 5) { this.descr = this.name + ', ' + this.cards[0].toString().slice(0, -1) + '\'s'; } return this.cards.length >= 5; } } class FourOfAKindPairPlus extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Four of a Kind with Pair or Better', game, canDisqualify); } solve() { var cards; this.resetWildCards(); for (var i=0; i<this.values.length; i++) { if (this.getNumCardsByRank(i) === 4) { this.cards = this.values[i] || []; for (var j=0; j<this.wilds.length && this.cards.length<4; j++) { var wild = this.wilds[j]; if (this.cards) { wild.rank = this.cards[0].rank; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } break; } } if (this.cards.length === 4) { for (i=0; i<this.values.length; i++) { cards = this.values[i]; if (cards && this.cards[0].wildValue === cards[0].wildValue) { continue; } if (this.getNumCardsByRank(i) >= 2) { this.cards = this.cards.concat(cards || []); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-6)); break; } } } if (this.cards.length >= 6) { var type = this.cards[0].toString().slice(0, -1) + '\'s over ' + this.cards[4].toString().slice(0, -1) + '\'s'; this.descr = this.name + ', ' + type; } return this.cards.length >= 6; } } class FourOfAKind extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Four of a Kind', game, canDisqualify); } solve() { this.resetWildCards(); for (var i=0; i<this.values.length; i++) { if (this.getNumCardsByRank(i) === 4) { this.cards = this.values[i] || []; for (var j=0; j<this.wilds.length && this.cards.length<4; j++) { var wild = this.wilds[j]; if (this.cards) { wild.rank = this.cards[0].rank; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-4)); break; } } if (this.cards.length >= 4) { if (this.game.noKickers) { this.cards.length = 4; } this.descr = this.name + ', ' + this.cards[0].toString().slice(0, -1) + '\'s'; } return this.cards.length >= 4; } } class FourWilds extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Four Wild Cards', game, canDisqualify); } solve() { if (this.wilds.length === 4) { this.cards = this.wilds; this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-4)); } if (this.cards.length >= 4) { if (this.game.noKickers) { this.cards.length = 4; } this.descr = this.name; } return this.cards.length >= 4; } } class ThreeOfAKindTwoPair extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Three of a Kind with Two Pair', game, canDisqualify); } solve() { var cards; this.resetWildCards(); for (var i=0; i<this.values.length; i++) { if (this.getNumCardsByRank(i) === 3) { this.cards = this.values[i] || []; for (var j=0; j<this.wilds.length && this.cards.length<3; j++) { var wild = this.wilds[j]; if (this.cards) { wild.rank = this.cards[0].rank; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } break; } } if (this.cards.length === 3) { for (var i=0; i<this.values.length; i++) { var cards = this.values[i]; if (cards && this.cards[0].wildValue === cards[0].wildValue) { continue; } if (this.cards.length > 5 && this.getNumCardsByRank(i) === 2) { this.cards = this.cards.concat(cards || []); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-4)); break; } else if (this.getNumCardsByRank(i) === 2) { this.cards = this.cards.concat(cards); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } } } } if (this.cards.length >= 7) { var type = this.cards[0].toString().slice(0, -1) + '\'s over ' + this.cards[3].toString().slice(0, -1) + '\'s & ' + this.cards[5].value + '\'s'; this.descr = this.name + ', ' + type; } return this.cards.length >= 7; } } class FullHouse extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Full House', game, canDisqualify); } solve() { var cards; this.resetWildCards(); for (var i=0; i<this.values.length; i++) { if (this.getNumCardsByRank(i) === 3) { this.cards = this.values[i] || []; for (var j=0; j<this.wilds.length && this.cards.length<3; j++) { var wild = this.wilds[j]; if (this.cards) { wild.rank = this.cards[0].rank; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } break; } } if (this.cards.length === 3) { for (i=0; i<this.values.length; i++) { cards = this.values[i]; if (cards && this.cards[0].wildValue === cards[0].wildValue) { continue; } if (this.getNumCardsByRank(i) >= 2) { this.cards = this.cards.concat(cards || []); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-5)); break; } } } if (this.cards.length >= 5) { var type = this.cards[0].toString().slice(0, -1) + '\'s over ' + this.cards[3].toString().slice(0, -1) + '\'s'; this.descr = this.name + ', ' + type; } return this.cards.length >= 5; } } class Flush extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Flush', game, canDisqualify); } solve() { this.sfLength = 0; this.resetWildCards(); for (var suit in this.suits) { var cards = this.getCardsForFlush(suit, true); if (cards.length >= this.game.sfQualify) { this.cards = cards; break; } } if (this.cards.length >= this.game.sfQualify) { this.descr = this.name + ', ' + this.cards[0].toString().slice(0, -1) + suit + ' High'; this.sfLength = this.cards.length; if (this.cards.length < this.game.cardsInHand) { this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-this.cards.length)); } } return this.cards.length >= this.game.sfQualify; } } class Straight extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Straight', game, canDisqualify); } solve() { var card, checkCards; this.resetWildCards(); // There are still some games that count the wheel as second highest. // These games do not have enough cards/wilds to make AKQJT and 5432A both possible. if (this.game.wheelStatus === 1) { this.cards = this.getWheel(); if (this.cards.length) { var wildCount = 0; for (var i=0; i<this.cards.length; i++) { card = this.cards[i]; if (card.value === this.game.wildValue) { wildCount += 1; } if (card.rank === 0) { card.rank = values.indexOf('A'); card.wildValue = 'A'; if (card.value === '1') { card.value = 'A'; } } } this.cards = this.cards.sort(Card.sort); for (; wildCount<this.wilds.length && this.cards.length < this.game.cardsInHand; wildCount++) { card = this.wilds[wildCount]; card.rank = values.indexOf('A'); card.wildValue = 'A'; this.cards.push(card); } this.descr = this.name + ', Wheel'; this.sfLength = this.sfQualify; if (this.cards[0].value === 'A') { this.cards = this.cards.concat(this.nextHighest().slice(1, this.game.cardsInHand-this.cards.length+1)); } else { this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-this.cards.length)); } return true; } this.resetWildCards(); } this.cards = this.getGaps(); // Now add the wild cards, if any, and set the appropriate ranks for (var i=0; i<this.wilds.length; i++) { card = this.wilds[i]; checkCards = this.getGaps(this.cards.length); if (this.cards.length === checkCards.length) { // This is an "open-ended" straight, the high rank is the highest possible rank. if (this.cards[0].rank < (values.length - 1)) { card.rank = this.cards[0].rank + 1; card.wildValue = values[card.rank]; this.cards.push(card); } else { card.rank = this.cards[this.cards.length - 1].rank - 1; card.wildValue = values[card.rank]; this.cards.push(card); } } else { // This is an "inside" straight, the high card doesn't change. for (var j=1; j<this.cards.length; j++) { if (this.cards[j-1].rank - this.cards[j].rank > 1) { card.rank = this.cards[j-1].rank - 1; card.wildValue = values[card.rank]; this.cards.push(card); break; } } } this.cards = this.cards.sort(Card.sort); } if (this.cards.length >= this.game.sfQualify) { this.descr = this.name + ', ' + this.cards[0].toString().slice(0, -1) + ' High'; this.cards = this.cards.slice(0, this.game.cardsInHand); this.sfLength = this.cards.length; if (this.cards.length < this.game.cardsInHand) { if (this.cards[this.sfLength-1].rank === 0) { this.cards = this.cards.concat(this.nextHighest().slice(1, this.game.cardsInHand-this.cards.length+1)); } else { this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-this.cards.length)); } } } return this.cards.length >= this.game.sfQualify; } /** * Get the number of gaps in the straight. * @return {Array} Highest potential straight with fewest number of gaps. */ getGaps(checkHandLength) { var wildCards, cardsToCheck, i, card, gapCards, cardsList, gapCount, prevCard, diff; var stripReturn = Hand.stripWilds(this.cardPool, this.game); wildCards = stripReturn[0]; cardsToCheck = stripReturn[1]; for (i=0; i<cardsToCheck.length; i++) { card = cardsToCheck[i]; if (card.wildValue === 'A') { cardsToCheck.push(new Card('1' + card.suit)); } } cardsToCheck = cardsToCheck.sort(Card.sort); if (checkHandLength) { i = cardsToCheck[0].rank + 1; } else { checkHandLength = this.game.sfQualify; i = values.length; } gapCards = []; for (; i>0; i--) { cardsList = []; gapCount = 0; for (var j=0; j<cardsToCheck.length; j++) { card = cardsToCheck[j]; if (card.rank > i) { continue; } prevCard = cardsList[cardsList.length - 1]; diff = (prevCard) ? prevCard.rank - card.rank : i - card.rank; if (diff === null) { cardsList.push(card); } else if (checkHandLength < (gapCount + diff + cardsList.length)) { break; } else if (diff > 0) { cardsList.push(card); gapCount += (diff - 1); } } if (cardsList.length > gapCards.length) { gapCards = cardsList.slice(); } if (this.game.sfQualify - gapCards.length <= wildCards.length) { break; } } return gapCards; } getWheel() { var wildCards, cardsToCheck, i, card, wheelCards, wildCount, cardFound; var stripReturn = Hand.stripWilds(this.cardPool, this.game); wildCards = stripReturn[0]; cardsToCheck = stripReturn[1]; for (i=0; i<cardsToCheck.length; i++) { card = cardsToCheck[i]; if (card.wildValue === 'A') { cardsToCheck.push(new Card('1' + card.suit)); } } cardsToCheck = cardsToCheck.sort(Card.sort); wheelCards = []; wildCount = 0; for (i = this.game.sfQualify-1; i>=0; i--) { cardFound = false; for (var j=0; j<cardsToCheck.length; j++) { card = cardsToCheck[j]; if (card.rank > i) { continue; } if (card.rank < i) { break; } wheelCards.push(card); cardFound = true; break; } if (!cardFound) { if (wildCount < wildCards.length) { wildCards[wildCount].rank = i; wildCards[wildCount].wildValue = values[i]; wheelCards.push(wildCards[wildCount]); wildCount += 1; } else { return []; } } } return wheelCards; } } class TwoThreeOfAKind extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Two Three Of a Kind', game, canDisqualify); } solve() { this.resetWildCards(); for (var i=0; i<this.values.length; i++) { var cards = this.values[i]; if (this.cards.length > 0 && this.getNumCardsByRank(i) === 3) { this.cards = this.cards.concat(cards || []); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-6)); break; } else if (this.getNumCardsByRank(i) === 3) { this.cards = this.cards.concat(cards); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } } } if (this.cards.length >= 6) { var type = this.cards[0].toString().slice(0, -1) + '\'s & ' + this.cards[3].toString().slice(0, -1) + '\'s'; this.descr = this.name + ', ' + type; } return this.cards.length >= 6; } } class ThreeOfAKind extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Three of a Kind', game, canDisqualify); } solve() { this.resetWildCards(); for (var i=0; i<this.values.length; i++) { if (this.getNumCardsByRank(i) === 3) { this.cards = this.values[i] || []; for (var j=0; j<this.wilds.length && this.cards.length<3; j++) { var wild = this.wilds[j]; if (this.cards) { wild.rank = this.cards[0].rank; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-3)); break; } } if (this.cards.length >= 3) { if (this.game.noKickers) { this.cards.length = 3; } this.descr = this.name + ', ' + this.cards[0].toString().slice(0, -1) + '\'s'; } return this.cards.length >= 3; } } class ThreePair extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Three Pair', game, canDisqualify); } solve() { this.resetWildCards(); for (var i=0; i<this.values.length; i++) { var cards = this.values[i]; if (this.cards.length > 2 && this.getNumCardsByRank(i) === 2) { this.cards = this.cards.concat(cards || []); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-6)); break; } else if (this.cards.length > 0 && this.getNumCardsByRank(i) === 2) { this.cards = this.cards.concat(cards || []); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } } else if (this.getNumCardsByRank(i) === 2) { this.cards = this.cards.concat(cards); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } } } if (this.cards.length >= 6) { var type = this.cards[0].toString().slice(0, -1) + '\'s & ' + this.cards[2].toString().slice(0, -1) + '\'s & ' + this.cards[4].toString().slice(0, -1) + '\'s'; this.descr = this.name + ', ' + type; } return this.cards.length >= 6; } } class TwoPair extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Two Pair', game, canDisqualify); } solve() { this.resetWildCards(); for (var i=0; i<this.values.length; i++) { var cards = this.values[i]; if (this.cards.length > 0 && this.getNumCardsByRank(i) === 2) { this.cards = this.cards.concat(cards || []); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-4)); break; } else if (this.getNumCardsByRank(i) === 2) { this.cards = this.cards.concat(cards); for (var j=0; j<this.wilds.length; j++) { var wild = this.wilds[j]; if (wild.rank !== -1) { continue; } if (cards) { wild.rank = cards[0].rank; } else if (this.cards[0].rank === values.length - 1 && this.game.wildStatus === 1) { wild.rank = values.length - 2; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } } } if (this.cards.length >= 4) { if (this.game.noKickers) { this.cards.length = 4; } var type = this.cards[0].toString().slice(0, -1) + '\'s & ' + this.cards[2].toString().slice(0, -1) + '\'s'; this.descr = this.name + ', ' + type; } return this.cards.length >= 4; } } class OnePair extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'Pair', game, canDisqualify); } solve() { this.resetWildCards(); for (var i=0; i<this.values.length; i++) { if (this.getNumCardsByRank(i) === 2) { this.cards = this.cards.concat(this.values[i] || []); for (var j=0; j<this.wilds.length && this.cards.length<2; j++) { var wild = this.wilds[j]; if (this.cards) { wild.rank = this.cards[0].rank; } else { wild.rank = values.length - 1; } wild.wildValue = values[wild.rank]; this.cards.push(wild); } this.cards = this.cards.concat(this.nextHighest().slice(0, this.game.cardsInHand-2)); break; } } if (this.cards.length >= 2) { if (this.game.noKickers) { this.cards.length = 2; } this.descr = this.name + ', ' + this.cards[0].toString().slice(0, -1) + '\'s'; } return this.cards.length >= 2; } } class HighCard extends Hand { constructor(cards, game, canDisqualify) { super(cards, 'High Card', game, canDisqualify); } solve() { this.cards = this.cardPool.slice(0, this.game.cardsInHand); for (var i=0; i<this.cards.length; i++) { var card = this.cards[i]; if (this.cards[i].value === this.game.wildValue) { this.cards[i].wildValue = 'A'; this.cards[i].rank = values.indexOf('A'); } } if (this.game.noKickers) { this.cards.length = 1; } this.cards = this.cards.sort(Card.sort); this.descr = this.cards[0].toString().slice(0, -1) + ' High'; return true; } } var gameRules = { 'standard': { 'cardsInHand': 5, 'handValues': [StraightFlush, FourOfAKind, FullHouse, Flush, Straight, ThreeOfAKind, TwoPair, OnePair, HighCard], 'wildValue': null, 'wildStatus': 1, 'wheelStatus': 0, 'sfQualify': 5, 'lowestQualified': null, "noKickers": false }, 'jacksbetter': { 'cardsInHand': 5, 'handValues': [StraightFlush, FourOfAKind, FullHouse, Flush, Straight, ThreeOfAKind, TwoPair, OnePair, HighCard], 'wildValue': null, 'wildStatus': 1, 'wheelStatus': 0, 'sfQualify': 5, 'lowestQualified': ['Jc', 'Jd', '4h', '3s', '2c'], "noKickers": true }, 'joker': { 'cardsInHand': 5, 'handValues': [NaturalRoyalFlush, FiveOfAKind, WildRoyalFlush, StraightFlush, FourOfAKind, FullHouse, Flush, Straight, ThreeOfAKind, TwoPair, HighCard], 'wildValue': 'O', 'wildStatus': 1, 'wheelStatus': 0, 'sfQualify': 5, 'lowestQualified': ['4c', '3d', '3h', '2s', '2c'], "noKickers": true }, 'deuceswild': { 'cardsInHand': 5, 'handValues': [NaturalRoyalFlush, FourWilds, WildRoyalFlush, FiveOfAKind, StraightFlush, FourOfAKind, FullHouse, Flush, Straight, ThreeOfAKind, HighCard], 'wildValue': '2', 'wildStatus': 1, 'wheelStatus': 0, 'sfQualify': 5, 'lowestQualified': ['5c', '4d', '3h', '3s', '3c'], "noKickers": true }, 'threecard': { 'cardsInHand': 3, 'handValues': [StraightFlush, ThreeOfAKind, Straight, Flush, OnePair, HighCard], 'wildValue': null, 'wildStatus': 1, 'wheelStatus': 0, 'sfQualify': 3, 'lowestQualified': ['Qh', '3s', '2c'], "noKickers": false }, 'fourcard': { 'cardsInHand': 4, 'handValues': [FourOfAKind, StraightFlush, ThreeOfAKind, Flush, Straight, TwoPair, OnePair, HighCard], 'wildValue': null, 'wildStatus': 1, 'wheelStatus': 0, 'sfQualify': 4, 'lowestQualified': null, "noKickers": true }, 'fourcardbonus': { 'cardsInHand': 4, 'handValues': [FourOfAKind, StraightFlush, ThreeOfAKind, Flush, Straight, TwoPair, OnePair, HighCard], 'wildValue': null, 'wildStatus': 1, 'wheelStatus': 0, 'sfQualify': 4, 'lowestQualified': ['Ac', 'Ad', '3h', '2s'], "noKickers": true }, 'paigowpokerfull': { 'cardsInHand': 7, 'handValues': [FiveOfAKind, FourOfAKindPairPlus, StraightFlush, Flush, Straight, FourOfAKind, TwoThreeOfAKind, ThreeOfAKindTwoPair, FullHouse, ThreeOfAKind, ThreePair, TwoPair, OnePair, HighCard], 'wildValue': 'O', 'wildStatus': 0, 'wheelStatus': 1, 'sfQualify': 5, 'lowestQualified': null }, 'paigowpokeralt': { 'cardsInHand': 7, 'handValues': [FourOfAKind, FullHouse, ThreeOfAKind, ThreePair, TwoPair, OnePair, HighCard], 'wildValue': 'O', 'wildStatus': 0, 'wheelStatus': 1, 'sfQualify': 5, 'lowestQualified': null }, 'paigowpokersf6': { 'cardsInHand': 7, 'handValues': [StraightFlush, Flush, Straight], 'wildValue': 'O', 'wildStatus': 0, 'wheelStatus': 1, 'sfQualify': 6, 'lowestQualified': null }, 'paigowpokersf7': { 'cardsInHand': 7, 'handValues': [StraightFlush, Flush, Straight], 'wildValue': 'O', 'wildStatus': 0, 'wheelStatus': 1, 'sfQualify': 7, 'lowestQualified': null }, 'paigowpokerhi': { 'cardsInHand': 5, 'handValues': [FiveOfAKind, StraightFlush, FourOfAKind, FullHouse, Flush, Straight, ThreeOfAKind, TwoPair, OnePair, HighCard], 'wildValue': 'O', 'wildStatus': 0, 'wheelStatus': 1, 'sfQualify': 5, 'lowestQualified': null }, 'paigowpokerlo': { 'cardsInHand': 2, 'handValues': [OnePair, HighCard], 'wildValue': 'O', 'wildStatus': 0, 'wheelStatus': 1, 'sfQualify': 5, 'lowestQualified': null } }; /** * Base Game class that defines the rules of the game. */ class Game { constructor(descr) { this.descr = descr; this.cardsInHand = 0; this.handValues = []; this.wildValue = null; this.wildStatus = 0; this.wheelStatus = 0; this.sfQualify = 5; this.lowestQualified = null; this.noKickers = null; // Set values based on the game rules. if (!this.descr || !gameRules[this.descr]) { this.descr = 'standard'; } this.cardsInHand = gameRules[this.descr]['cardsInHand']; this.handValues = gameRules[this.descr]['handValues']; this.wildValue = gameRules[this.descr]['wildValue']; this.wildStatus = gameRules[this.descr]['wildStatus']; this.wheelStatus = gameRules[this.descr]['wheelStatus']; this.sfQualify = gameRules[this.descr]['sfQualify']; this.lowestQualified = gameRules[this.descr]['lowestQualified']; this.noKickers = gameRules[this.descr]['noKickers']; } } function exportToGlobal(global) { global.Card = Card; global.Hand = Hand; global.Game = Game; global.RoyalFlush = RoyalFlush; global.NaturalRoyalFlush = NaturalRoyalFlush; global.WildRoyalFlush = WildRoyalFlush; global.FiveOfAKind = FiveOfAKind; global.StraightFlush = StraightFlush; global.FourOfAKindPairPlus = FourOfAKindPairPlus; global.FourOfAKind = FourOfAKind; global.FourWilds = FourWilds; global.TwoThreeOfAKind = TwoThreeOfAKind; global.ThreeOfAKindTwoPair = ThreeOfAKindTwoPair; global.FullHouse = FullHouse; global.Flush = Flush; global.Straight = Straight; global.ThreeOfAKind = ThreeOfAKind; global.ThreePair = ThreePair; global.TwoPair = TwoPair; global.OnePair = OnePair; global.HighCard = HighCard; global.PaiGowPokerHelper = PaiGowPokerHelper; } // Export the classes for node.js use. if (typeof exports !== 'undefined') { exportToGlobal(exports); } // Add the classes to the window for browser use. if (typeof window !== 'undefined') { exportToGlobal(window); }
© Copyright Chaturbate 2011- 2025. All Rights Reserved.