Skip to content

Commit

Permalink
refactored pullRandom to use Array.prototype.pullRandom which complie…
Browse files Browse the repository at this point in the history
…s with behavior of pop() and shift()
  • Loading branch information
dskoda1 committed Sep 22, 2016
1 parent 6d2da2b commit 71828be
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 112 deletions.
68 changes: 16 additions & 52 deletions src/Deck.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ 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
Expand Down Expand Up @@ -122,6 +129,15 @@ class Deck {
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);
}


_pull(arrMethod, n) {
if (n === undefined) {
n = 1;
Expand Down Expand Up @@ -157,58 +173,6 @@ class Deck {
}


// 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) {
if (n !== undefined && n !== 1) {
// Make sure more than 0
if (n < 1) {
throw Error(g_BAD_AMOUNT);
}
// Make sure enough cards left
else if (n > this.remainingSize()) {
throw Error(g_OUT_OF_CARDS);
}

// get n unique random numbers
let randoms = [];
while (randoms.length < n) {
let random = _.random(0, this.remainingSize() - 1);
if (_.indexOf(randoms, random) === -1) {
randoms.push(random);
}
}

// Now get the cards
let cards = [];
for (let i = 0; i < n; ++i) {
// Pop a card from active
let random = randoms[i];
let card = this.activeCards[random - i];
// Push it on inactive
this.inactiveCards.push(card);
// Push it on ret
cards.push(card);
this.activeCards.splice(random - i, 1);
}
return cards;
}
else {
// Make sure at least one card left
if (this.remainingSize() < 1) {
throw Error(g_OUT_OF_CARDS);
}
// Get the card
let random = _.random(0, this.remainingSize() - 1);
let card = this.activeCards[random];
this.inactiveCards.push(card);
this.activeCards.splice(random, 1);
return card;
}
}

// Shuffle all the active cards, deferring to lodash shuffle
// https://lodash.com/docs/4.15.0#shuffle
shuffle() {
Expand Down
116 changes: 56 additions & 60 deletions test/Deck-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,61 +230,25 @@ describe('Deck', () => {
});
});

//////////////////////////////////////////////////////////////////////////
describe('Deck.shuffle()', () => {
let original_shuffle;
before(() => {
// Cache the og shuffle
original_shuffle = _.shuffle;
// Set it to be reverse
_.shuffle = (a) => _.reverse(a);

});

after(() => {
// Reset it
_.shuffle = original_shuffle;
});
it('Will shuffle all the cards in the deck', () => {
// We expect the cards to simply be reversed now
let deck = new Deck();
let cards = deck.getRemaining();
cards = _.map(cards, (card) => {
return new Card({
'suit': card.getSuit(),
'rank': card.getRank()
});
});

deck.shuffle();
// Now reverse the original cards
cards = _.reverse(cards);
// Will be the same
assert(_.isEqual(cards, deck.getRemaining()));

});
});

//////////////////////////////////////////////////////////////////////////
describe.skip('Deck.pullRandom()', () => {
let original_random;
describe('Deck.pullRandom()', () => {
//let original_random;
before(() => {
// Cache the og shuffle
original_random = _.random;
//original_random = _.random;
// Set it to be reverse
// TODO:
// Fix the ranodm behavior, this is locking
// up in the while loop
_.random = (low, high) => 0;
//_.random = (low, high) => 0;

});

after(() => {
// Reset it
_.shuffle = original_random();
//_.shuffle = original_random();
});


describe('Validation of n', () => {
it('Will throw Deck.BAD_AMOUNT if less than one is passed', () => {
let deck = new Deck();
Expand All @@ -295,11 +259,8 @@ describe('Deck', () => {
let deck = new Deck();
expect(() => deck.pullRandom(53)).to.throw(Deck.OUT_OF_CARDS);
});

it('Will default to 1 if nothing is passed', () => {
let deck = new Deck();


for (let i = 0; i < 52; ++i) {
let card = deck.pullRandom(1);
assert.instanceOf(card, Card);
Expand All @@ -308,23 +269,36 @@ describe('Deck', () => {
expect(deck.remainingSize()).to.equal(0);
expect(deck.pulledSize()).to.equal(52);
});

it ('Will throw Deck.OUT_OF_CARDS when out of cards and defaulting to 1', () => {
let deck = new Deck();
deck.pullRandom(52);
expect(() => deck.pullRandom()).to.throw(Deck.OUT_OF_CARDS);
});
});
describe('Return value', () => {
it ('Will return a Card type when 1 requested or defaulted', () => {
it('Will return n cards from the randomly in the deck, and remove them', () => {
let deck = new Deck();
let cards = deck.pullRandom(5);
expect(cards.length).to.equal(5);
expect(deck.remainingSize()).to.equal(52 - 5);
expect(deck.pulledSize()).to.equal(5);
assert(_.isEqual(cards, deck.getPulled()));


for (let i = 0; i < 52; ++i) {
_.forEach(cards, (card) => {
assert.instanceOf(card, Card);
});
});
it ('Will return a single Card type when defaulting or 1 requested', () => {
let deck = new Deck();
const halfDeck = deck.remainingSize() / 2;
for (let i = 0; i < halfDeck; ++i) {
let card = deck.pullRandom();
assert.instanceOf(card, Card);
}

for (let i = 0; i < halfDeck; ++i) {
let card = deck.pullRandom(1);
assert.instanceOf(card, Card);
}
});
it ('Will return an array of Card types when more than 1 requested ', () => {
let deck = new Deck();
Expand All @@ -335,20 +309,42 @@ describe('Deck', () => {
assert.instanceOf(card, Card);
});
});
});
})
//////////////////////////////////////////////////////////////////////////
describe('Deck.shuffle()', () => {
let original_shuffle;
before(() => {
// Cache the og shuffle
original_shuffle = _.shuffle;
// Set it to be reverse
_.shuffle = (a) => _.reverse(a);

it('Will return n cards from the top of the deck, and remove them', () => {
let deck = new Deck();
let cards = deck.pullRandom(5);
expect(cards.length).to.equal(5);
expect(deck.remainingSize()).to.equal(52 - 5);
expect(deck.pulledSize()).to.equal(5);
assert(_.isEqual(cards, deck.getPulled()));

_.forEach(cards, (card) => {
assert.instanceOf(card, Card);
});

after(() => {
// Reset it
_.shuffle = original_shuffle;
});
it('Will shuffle all the cards in the deck', () => {
// We expect the cards to simply be reversed now
let deck = new Deck();
let cards = deck.getRemaining();
cards = _.map(cards, (card) => {
return new Card({
'suit': card.getSuit(),
'rank': card.getRank()
});
});

deck.shuffle();
// Now reverse the original cards
cards = _.reverse(cards);
// Will be the same
assert(_.isEqual(cards, deck.getRemaining()));

});
})
});

});

0 comments on commit 71828be

Please sign in to comment.