Scott Montford
Scott Montford

Reputation: 165

How to randomly select a card from a deck of cards and not select it again?

I am trying to build a game based on random card selection. The player draws a card, once the card has been drawn the card will not be drawn again.

I've tried to make it work but I'm getting an error on my website saying "Uncaught TypeError: currentCard.filter is not a function"

Here is my code:

    cards = [
    'clubs-ace',
    'clubs-2',
    'clubs-3',
    'clubs-4',
    'clubs-5',
    'clubs-6',
    'clubs-7',
    'clubs-8',
    'clubs-9',
    'clubs-10',
    'clubs-jack',
    'clubs-queen',
    'clubs-king',
    'diamonds-ace',
    'diamonds-2',
    'diamonds-3',
    'diamonds-4',
    'diamonds-5',
    'diamonds-6',
    'diamonds-7',
    'diamonds-8',
    'diamonds-9',
    'diamonds-10',
    'diamonds-jack',
    'diamonds-queen',
    'diamonds-king',
    'hearts-ace',
    'hearts-2',
    'hearts-3',
    'hearts-4',
    'hearts-5',
    'hearts-6',
    'hearts-7',
    'hearts-8',
    'hearts-9',
    'hearts-10',
    'hearts-jack',
    'hearts-queen',
    'hearts-king',
    'spades-ace',
    'spades-2',
    'spades-3',
    'spades-4',
    'spades-5',
    'spades-6',
    'spades-7',
    'spades-8',
    'spades-9',
    'spades-10',
    'spades-jack',
    'spades-queen',
    'spades-king'
];

var currentCard = "";
var kingsCup = 0;

function drawCard() {
    var randomNumber = Math.floor(Math.random() * (currentCard.length));
    currentCard = currentCard.filter((e, i) => i !== randomNumber);
    console.log(currentCard.length);

    switch(currentCard[randomNumber]) {
        case 1:
           document.getElementById("cards").src="assets/js/games/cards/clubs-ace.png";
        break;
        case 2:
            document.getElementById("cards").src="assets/js/games/cards/clubs-2.png";
        break;
        case 3:
            document.getElementById("cards").src="assets/js/games/cards/clubs-3.png";
        break;
        case 4:
            document.getElementById("cards").src="assets/js/games/cards/clubs-4.png";
        break;
        case 5:
            document.getElementById("cards").src="assets/js/games/cards/clubs-5.png";
        break;
        case 6:
            document.getElementById("cards").src="assets/js/games/cards/clubs-6.png";
        break;
        case 7:
            document.getElementById("cards").src="assets/js/games/cards/clubs-7.png";
        break;
        case 8:
            document.getElementById("cards").src="assets/js/games/cards/clubs-8.png";
        break;
        case 9:
            document.getElementById("cards").src="assets/js/games/cards/clubs-9.png";
        break;
    }
}

I'm a beginner at JS and the code could probably be written in a neater and more efficient way, so please excuse the long, messy code.

What am I doing wrong?

Upvotes: 1

Views: 2280

Answers (3)

Mosia Thabo
Mosia Thabo

Reputation: 4267

You might want to do something like this... Keep two lists handy that handles the cards. The first list stores the entire cards and the second one stores the currentCards list. So every time you draw a card from the main list cards, it is added to the currentCards and removed from the main cards, so you will never repeat the same card. The randomNumber will be updated as the list of cards list gets smaller as well.

var drawnCardsDisplay = document.getElementById('drawnCards');
var cards = [
    'clubs-ace',
    'clubs-2',
    'clubs-3',
    'clubs-4',
    'clubs-5',
    'clubs-6',
    'clubs-7',
    'clubs-8',
    'clubs-9',
    'clubs-10',
    'clubs-jack',
    'clubs-queen',
    'clubs-king',
    'diamonds-ace',
    'diamonds-2',
    'diamonds-3',
    'diamonds-4',
    'diamonds-5',
    'diamonds-6',
    'diamonds-7',
    'diamonds-8',
    'diamonds-9',
    'diamonds-10',
    'diamonds-jack',
    'diamonds-queen',
    'diamonds-king',
    'hearts-ace',
    'hearts-2',
    'hearts-3',
    'hearts-4',
    'hearts-5',
    'hearts-6',
    'hearts-7',
    'hearts-8',
    'hearts-9',
    'hearts-10',
    'hearts-jack',
    'hearts-queen',
    'hearts-king',
    'spades-ace',
    'spades-2',
    'spades-3',
    'spades-4',
    'spades-5',
    'spades-6',
    'spades-7',
    'spades-8',
    'spades-9',
    'spades-10',
    'spades-jack',
    'spades-queen',
    'spades-king'
];

var currentCards = [];

function drawCard() {
    // ue cards here instead of currentCards
    var randomNumber = Math.floor(Math.random() * (cards.length - 1));
    
    currentCards.push(
      // Run an immediately self executing function expression
      (function(){
        // store the elected card temorarily
        var tempSelectedCard = cards[randomNumber];
        // Remove that card from the main cards
        cards = getUnDrawnCards(randomNumber);
        // return the selected card and store it inside the currentCards array
        return tempSelectedCard;
      })()
    );
    // After Drawing the card, display it.
    showDrawnCards(currentCards);
}

function getUnDrawnCards(cardPositionToBeRemoved) // returns card[]
{
  if(cardPositionToBeRemoved)
  {
    // create a temporary array storage
    var tempNewCards = [];
    
    // Loop through the cards
    cards.forEach(function(card, index)
    {
      // if the card to be removed does matches the current card position
      if(index !== cardPositionToBeRemoved)
      {
        // Add it to the tempArrayList
        tempNewCards.push(cards[index]);
      }
      // At tis poist the matched index will not be part of the cards anymore
    });
    
    // Return tempNewCards
    return tempNewCards;
  }
  return [];
}

function showDrawnCards(drawnCardsArray)
{
  if(drawnCardsArray.length > 0)
  {
    drawnCardsDisplay.innerHTML = '';
    drawnCardsArray.map(function(card)
    {
      var drawn_card = document.createElement('span');
      drawn_card.innerHTML = card;
      drawnCardsDisplay.appendChild(drawn_card);
    });
  }
}
span{
  display: inline-block;
  width: 120px;
  line-height: 40px;
  text-align: center;
  border: thin solid #dbdbdb;
  margin: 5px;
}
button{
margin-top: 15px;
}
<div id="drawnCards"></div>
<button onClick="drawCard()">Click to Draw</button>

Upvotes: 0

bruno.ribeiro
bruno.ribeiro

Reputation: 19

i believe this should work.

const selectableCards = [
    'clubs-ace',
    'clubs-2',
    'clubs-3',
    'clubs-4',
    'clubs-5',
    'clubs-6',
    'clubs-7',
    'clubs-8',
    'clubs-9',
    'clubs-10',
    'clubs-jack',
    'clubs-queen',
    'clubs-king',
    'diamonds-ace',
    'diamonds-2',
    'diamonds-3',
    'diamonds-4',
    'diamonds-5',
    'diamonds-6',
    'diamonds-7',
    'diamonds-8',
    'diamonds-9',
    'diamonds-10',
    'diamonds-jack',
    'diamonds-queen',
    'diamonds-king',
    'hearts-ace',
    'hearts-2',
    'hearts-3',
    'hearts-4',
    'hearts-5',
    'hearts-6',
    'hearts-7',
    'hearts-8',
    'hearts-9',
    'hearts-10',
    'hearts-jack',
    'hearts-queen',
    'hearts-king',
    'spades-ace',
    'spades-2',
    'spades-3',
    'spades-4',
    'spades-5',
    'spades-6',
    'spades-7',
    'spades-8',
    'spades-9',
    'spades-10',
    'spades-jack',
    'spades-queen',
    'spades-king'
]

const currentCard = {}
const cardsAlreadySelected = []
const kingsCup = 0

const drawCard = () => {
  const randomNumber = Math.floor(Math.random() * (selectableCards.length))
  const currentCard = selectableCards.splice(randomNumber, 1)
  console.log(currentCard.length)
  document.getElementById("cards").src = `assets/js/games/cards/${currentCard}.png`
}

Upvotes: 0

machineghost
machineghost

Reputation: 35812

Specifically responding to:

I'm a beginner at JS and the code could probably be written in a neater and more efficient way, so please excuse the long, messy code.

As a general rule, you want to try and separate your data and logic, but your code mixes both.

Consider instead something like:

const cardsById = {
    1: 'clubs-ace'
    2: 'clubs-2'
    // ...
};


document.getElementById("cards").src =
  'assets/js/games/cards/' + cardsById[randomNumber]+ '.png';

That way you have your data (cardsById) with just the unique data parts (the image names and IDs), and the logic is separate.

As for not picking the same card twice, one option would be to remove each card as you pick it using slice as @Crayon Violent suggested in the comments (although I'd recommend splice, with a "p", instead for that).

Another would be to add each card's ID to a second alreadyPicked array, and then check that array when you generate a random ID; if it's one you already picked, re-pick. Which style is better depends on your specific code.

Upvotes: 2

Related Questions