For a Memory game, I'm trying to randomly populate a 2D array with letters.
The grid is size
× size
and each letter occurs twice.
This is my code so far. I don't understand why it is giving an error
alpha = ("A".."Z").to_a
letters_range = alpha[0...size*size/2]
chosen_letters = (letters_range letters_range).shuffle
(0...size).each do |row|
(0...size).each do |col|
letter = chosen_letters.select
@grid[row][col] = Card.new(letter)
letter_idx = chosen_letters.index(letter)
chosen_letters.delete_at(letter_idx) #error line
end
end
CodePudding user response:
chosen_letters
is an array containing single-character strings.
When running letter = chosen_letters.select
, you may assume that Array#select
returns a random element. However, when not passing it a block, it returns an Enumerator
. As such, your letter
variable does not contain an element from the chosen_letter
array and thus, an index for this object can not be found, resulting in letter_idx
to be nil
.
To fix this, you may want to use a more appropriate statement to fetch an element, e.g. Array#pop
to return and remove the last element from the array.
CodePudding user response:
Since chosen_letters
is already shuffled, you don't have to pick a random element. Instead you can just pop
the last or shift
the first element off the array which makes your loop a lot simpler:
(0...size).each do |row|
(0...size).each do |col|
letter = chosen_letters.shift
@grid[row][col] = Card.new(letter)
end
end
It might be a little cleaner to start with an array of cards, e.g. by creating a pair of two cards for each letter:
cards = letters_range.flat_map { |letter| [Card.new(letter), Card.new(letter)] }
cards.shuffle!
You can then assign the cards to the grid via:
(0...size).each do |row|
(0...size).each do |col|
@grid[row][col] = cards.shift
end
end
or you could build the @grid
right out of the array via each_slice
:
@grid = cards.each_slice(size).to_a