UNPKG

card-decks

Version:

A module to simulate one to n decks of cards.

257 lines (211 loc) 7.41 kB
'use strict'; let _ = require('lodash'); let Card = require('./Card'); Array.prototype.removeRandom = function() { // Pick random element let random = _.random(0, this.length - 1); // Splice returns array, only splicing 1 so return first and only ele return this.splice(random, 1)[0]; }; class Deck { // This class provides an interface for creating and accessing // playing cards in a deck. It can be used to simulate one to // n card decks and defaults to just a single if not told // otherwise in the constructor. ////////////////////////////////////////////////////////////////////// constructor(init) { if (init && init.numDecks) { this.numDecks = init.numDecks; } else { this.numDecks = 1; } // Create the deck now this.createDeck(); } // Helper function for setting the cards in this deck createDeck() { this.activeCards = []; this.inactiveCards = []; _.forEach(Card.Combinations, (combo) => { for (let i = 0; i < this.numDecks; ++i) { this.activeCards.push(new Card(combo)); } }); } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Return the array of cards that are still active // PRIVATE?? getRemaining() { return this.activeCards; } // Return the array of cards that have been pulled already // PRIVATE?? getPulled() { return this.inactiveCards; } ////////////////////////////////////////////////////////////////////// // SIZE METHODS ////////////////////////////////////////////////////// // The total number of cards left in this deck totalSize() { return this.activeCards.length + this.inactiveCards.length; } // The number of remaining cards remainingSize() { return this.activeCards.length; } // The number of cards that have been pulled pulledSize() { return this.inactiveCards.length; } // The number of decks this deck is comprised of decks() { return this.numDecks; } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Return the number of occurences of this card left in the active pile has(combo) { // Will throw Card.badCombo if invalid combo Card.validateCombo(combo); // Return the number of occurences return _.filter(this.activeCards, (card) => { return (card.suit == combo.suit && card.rank == combo.rank); }) .length; } hasBeenPulled(combo) { // Will throw Card.badCombo if invalid combo Card.validateCombo(combo); // Return the number of occurences return _.filter(this.inactiveCards, (card) => { return (card.suit == combo.suit && card.rank == combo.rank); }) .length; } // Return the top card without removing it. // Throws Deck.OUT_OF_CARDS if no more cards remain peekTop() { const remainingSize = this.remainingSize(); if (remainingSize > 0) { return this.activeCards[remainingSize - 1]; } else { throw Error(g_OUT_OF_CARDS); } } // Return the bottom card without removing it. // Throws Deck.OUT_OF_CARDS if no more cards remain peekBottom() { const remainingSize = this.remainingSize(); if (remainingSize > 0) { return this.activeCards[0]; } else { throw Error(g_OUT_OF_CARDS); } } // Return the top n cards and remove them. Default to 1 card // if not passed anything. // Throws Deck.BAD_AMOUNT if specified 'n' is less than 1. // Throws Deck.OUT_OF_CARDS if specified 'n' more than remaining. pullTop(n) { return this._pull(Array.prototype.pop, n); } // Return the bottom n cards and remove them. Default to 1 card // if not passed anything. // Throws Deck.BAD_AMOUNT if specified 'n' is less than 1. // Throws Deck.OUT_OF_CARDS if specified 'n' more than remaining. pullBottom(n) { return this._pull(Array.prototype.shift, n); } // Return n random cards and remove them. Default to 1 card // if not passed anything. // Throws Deck.BAD_AMOUNT if specified 'n' is less than 1. // Throws Deck.OUT_OF_CARDS if specified 'n' more than remaining. pullRandom(n) { return this._pull(Array.prototype.removeRandom, n); } // Internal method: called with an Array.prototype method, // and a number of cards to remove. _pull(arrMethod, n) { if (n === undefined) { n = 1; } if (n < 1) { throw Error(g_BAD_AMOUNT); } if (n > this.remainingSize()) { throw Error(g_OUT_OF_CARDS); } if (typeof arrMethod !== 'function') { throw Error('Programmer error- only calling this method internally'); } // Now get the cards let cards = []; for (let i = 0; i < n; ++i) { // retrieve a card from active let card = arrMethod.call(this.activeCards); // Push it on inactive this.inactiveCards.push(card); // Push it on ret cards.push(card); } if (cards.length === 1) { return cards[0]; } else { return cards; } } // Shuffle all the active cards, deferring to lodash shuffle // https://lodash.com/docs/4.15.0#shuffle shuffle() { this.activeCards = _.shuffle(this.activeCards); } replaceTop(cards) { this._replace(Array.prototype.push, cards); } _replace(arrMethod, cards) { if (cards == undefined || cards == null) { // Make sure pulled + remaining == to if (this.pulledSize() + this.remainingSize() != this.numDecks * Deck.CardsPerDeck) { throw Error(g_TAMPERED_WITH); } for (let i = 0; i < this.pulledSize(); ++i) { arrMethod.call(this.activeCards, this.inactiveCards[i]); } this.inactiveCards = []; } } _remove(arrMethod, arr, i) { } // STATIC METHODS static get BAD_AMOUNT() { return g_BAD_AMOUNT; } static get OUT_OF_CARDS() { return g_OUT_OF_CARDS; } static get TAMPERED_WITH() { return g_TAMPERED_WITH; } static get CardsPerDeck() { return g_CardsPerDeck; } } module.exports = Deck; const g_BAD_AMOUNT = { type: 'BAD_AMOUNT', error: 'Invalid amount of cards requested. Must be at least 1.' }; const g_OUT_OF_CARDS = { type: 'OUT_OF_CARDS', error: 'No more cards are available to pull. Replace cards to continue.' }; const g_TAMPERED_WITH = { type: 'OUT_OF_CARDS', error: 'No more cards are available to pull. Replace cards to continue.' }; const g_CardsPerDeck = 52;