Programming Fundamentals - Lab 5 - Solution
EXERCISE
Build a deck of cards. Given the arrays of card data, use a loop to write out the cards to the screen.
Sample output:
2 of Clubs
2 of Diamonds
2 of Hearts
2 of Spades
3 of Clubs
This lab includes 4 arrays (1 for each suit) of ranks.
clubs = [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]
diamonds = [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]
hearts = [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]
spades = [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]
To display the "cards", we can loop through each array and output the rank with its suit. Let's start by just looping through the clubs. We can use either an incrementing index to find each element of the array by position. Or, we can use the for ___ in ___
loop which does that for us. Let's go with the latter.
for ____ in clubs
# do something
end
Sometimes it's nice just to start with the loop structure. We get to make up a variable that will represent each element in the array as we iterate through it. We could call it zebra
or x
or anyting else, but we'll use something descriptive like rank
. And on each iteration of the loop, we'll display a string with the rank in it and a placeholder for the suit.
for rank in clubs
puts "#{rank} of Clubs"
end
Great. Now, we just repeat for each other suit:
for rank in clubs
puts "#{rank} of Clubs"
end
for rank in diamonds
puts "#{rank} of Diamonds"
end
for rank in hearts
puts "#{rank} of Hearts"
end
for rank in spades
puts "#{rank} of Spades"
end
This will output all 52 cards organized by suit, just as instructed. Problem solved.
However, there's some duplication in this code that could be improved upon. Instead of 4 loops, since the data in each array is the same, we can loop through it once and display the rank for each suit:
for rank in clubs
puts "#{rank} of Clubs"
puts "#{rank} of Diamonds"
puts "#{rank} of Hearts"
puts "#{rank} of Spades"
end
We'd probably want to rename the clubs
array to something more generic, like ranks
. And that will bring us to the first challenge.
Challenge #1
Challenge #1
The arrays are identical for each suit and can be simplified by using a ranks array as seen below. Try to complete the exercise again by combining these arrays.
This challenge includes 2 arrays with ranks and suits that we'll use:
ranks = [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]
suits = ["Clubs", "Diamonds", "Hearts", "Spades"]
Looking at the previous solution, you can see that we're outputing the rank 4 times, once for each suit: puts "#{rank} of Clubs"
(then "Diamonds", then "Hearts", then "Spades"). Instead of repeating that code 4 times, we can combine the rank with each suit using the suits
array.
For example, when rank
is 2, we want to combine it with "Clubs", then "Diamonds", then "Hearts", then "Spades". To go through each of those elements in the suits array, it makes sense to use another loop:
for rank in ranks
for ___ in suits
puts "#{rank} of ___"
end
end
Once again, we need to name a variable for the suits loop. We can name it anything, but suit
is a nice descriptive variable. You may notice a pattern that often the array name is pluralized and then we use the singular of it for the loop. That's a good pattern to remember!
Now that we have a variable name for the suits loop, we can replace the placeholder in our string with the suit.
for rank in ranks
for suit in suits
puts "#{rank} of #{suit}"
end
end
Our code now loops through the ranks and, for each rank, it then loops through the suits and combines that rank with each suit. The combination of rank and suit is a "card". Once the suits loop is complete for the rank, the code moves on to the next rank and repeats until all the ranks have been combined with all the suits.
Challenge #2
Deal a poker hand. Shuffle the deck and "deal" (i.e. display) a 5 card hand (i.e. 5 cards from the deck).
You will want to look at the documentation for Arrays: https://ruby-doc.org/core-2.7.0/Array.html
For the challenge, we don't just want to see all the combinations of ranks and suits, but we want to store them as cards in a new array that we can then shuffle and deal a hand from. So instead of just using puts
, we'll add each "card" to a new array. First let's create that array:
deck = []
To start, the deck array is empty. We'll fill it as we build each code in our loop code.
for rank in ranks
for suit in suits
card = "#{rank} of #{suit}"
deck.push(card)
end
end
puts deck
Here, instead of just using puts
with the card, we're "pushing" (i.e. adding it) to the end of the deck. So "2 of Clubs" becomes the first element in the deck
array. Then "2 of Diamonds" becomes the second element. And "2 of Hearts", and then "2 of Spades", and "3 of Clubs", etc, until we have all the cards (combinations of ranks and suits) in the deck array.
The deck is currently in perfect order, so we want to shuffle it to get a random order. If we look back to the ruby Array documentation, we'll find a method .shuffle
(here) which appears to do exactly what we want - randomize the order.
shuffled_deck = deck.shuffle
puts shuffled_deck
Now we want to get a 5-card hand from the shuffled deck. We could just do this:
hand = [
shuffled_deck[0],
shuffled_deck[1],
shuffled_deck[2],
shuffled_deck[3],
shuffled_deck[4]
]
But hopefully you're starting to guess that there are more efficient ways to perform common tasks. In this case, looking again at the documentation shows the use of the square brackes ([]
) to read n elements from the array starting at any position (here). We use a starting index and the number of elements like this:
hand = shuffled_deck[0,5]
puts hand
This will read 5 elements from the shuffled_deck
array beginning at index 0.
And the final step is to display the cards in the hand. Again we could hardcode each index, but a loop seems appropriate here. That way, if the size of the hand ever changes (e.g. 7-code poker), the loop will still just work.
for card in hand
puts card
end
All the code together:
ranks = [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]
suits = ["Clubs", "Diamonds", "Hearts", "Spades"]
deck = []
for rank in ranks
for suit in suits
card = "#{rank} of #{suit}"
deck.push(card)
end
end
shuffled_deck = deck.shuffle
hand = shuffled_deck[0,5]
for card in hand
puts card
end