Solved – How to predict the results of a simple card game

gamesprobabilityr

I want to predict the results of a simple card game, to judge on average, how long a game will last.

My 'simple' game is;

  • Cards are dealt from a randomised
    deck to n players (typically 2-4)
  • Each player gets five cards
  • The top
    card from the deck is turned over
  • Each player takes it in turns to
    either place a card of the same face
    value (i.e 1-10, J, Q, K, A), the
    same suit (i.e Hearts, Diamonds,
    Spades, Clubs) or any suit of magic
    card (a jack)
  • If the player can place
    a card they do, otherwise they must
    take a card from the deck
  • Play
    continues in turn until all but one
    player has no cards left

I'm guessing that I could write code to play a mythical game and report the result, then run that code thousands of times.

Has anyone done this ? Can they suggest code that does a similar job (my favoured language is R, but anything would do) ? Is there a better way ?

Best Answer

The easiest way is just to simulate the game lots of times. The R code below simulates a single game.

nplayers = 4
#Create an empty data frame to keep track
#of card number, suit and if it's magic
empty.hand = data.frame(number = numeric(52),
  suit = numeric(52),
  magic  = numeric(52))

#A list of players who are in the game
players =list()
for(i in 1:nplayers)
  players[[i]] = empty.hand

#Simulate shuffling the deck
deck = empty.hand
deck$number = rep(1:13, 4)
deck$suit = as.character(rep(c("H", "C", "S", "D"), each=13))
deck$magic = rep(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), each=4)
deck = deck[sample(1:52, 52),]

#Deal out five cards per person
for(i in 1:length(players)){
  r = (5*i-4):(5*i)
  players[[i]][r,] = deck[r,]
}

#Play the game
i = 5*length(players)+1
current = deck[i,]
while(i < 53){
  for(j in 1:length(players)){
    playersdeck = players[[j]]
    #Need to test for magic and suit also - left as an exercise!
    if(is.element(current$number, playersdeck$number)){
      #Update current card
      current = playersdeck[match(current$number,
        playersdeck$number),]
      #Remove card from players deck
      playersdeck[match(current$number, playersdeck$number),] = c(0,
                   0, 0)
    } else {
      #Add card to players deck
      playersdeck[i,] = deck[i,]
      i = i + 1
    }
    players[[j]] = playersdeck
    #Has someone won or have we run out of card
    if(sum(playersdeck$number) == 0 | i > 52){
      i = 53
      break
    }
  }
}

#How many cards are left for each player
for(i in 1:length(players))
{
  cat(sum(players[[i]]$number !=0), "\n") 
}

Some comments

  1. You will need to add a couple of lines for magic cards and suits, but data structure is already there. I presume you didn't want a complete solution? ;)
  2. To estimate the average game length, just place the above code in a function and call lots of times.
  3. Rather than dynamically increasing a vector when a player gets a card, I find it easier just to create a sparse data frame that is more than sufficient. In this case, each player has a data frame with 52 rows, which they will never fill (unless it's a 1 player game).
  4. There is a small element of strategy with this game. What should you do if you can play more than one card. For example, if 7H comes up, and you have in your hand 7S, 8H and the JC. All three of these cards are "playable".