Reputation: 901
I'm looking for some advice on dynamic variables. Particularly if I'm making the best use of instance_variable_set
or if there is a better way I should be looking at. Thanks in advance for any advice. Now for the code.
I'm creating a Blackjack game. And I have two value_creator
methods that look like this:
class Blackjack
def dealers_card_value_creator
@card_value = @hit_dealer
case
when @card_value.match(/\d+/)
@card_value = @card_value.match(/\d+/)[0].to_i
when @card_value.match(/Ace/)
if @dealers_hand >= 11
@card_value = 1
else
@card_value = 11
end
when @card_value.match(/Jack|Queen|King/)
@card_value = 10
else
puts "there was an error. please try again."
end
@hit_dealer = @card_value
@dealers_hand = @dealers_hand + @hit_dealer
if @dealers_hand > 21 then puts "Dealer went over 21. You won $#{@bet}. Nice!"
deal end
end
def players_card_value_creator
@card_value = @hit_player
case
when @card_value.match(/\d+/)
@card_value = @card_value.match(/\d+/)[0].to_i
when @card_value.match(/Ace/)
if @players_hand >= 11
@card_value = 1
else
@card_value = 11
end
when @card_value.match(/Jack|Queen|King/)
@card_value = 10
else
puts "there was an error. please try again."
end
@hit_player = @card_value
@players_hand = @players_hand + @hit_player
if @players_hand > 21 then puts "You went over 21. You lost $#{@bet}. Try again."
deal end
end
end
as you can see, they are basically the same. So I created this method to be used by both Dealers and Players.
def value_creator(string)
hit = "@#{string}" #returns either @player or @dealer
instance_variable_set(hit, "#{@hit_card}")
@card_value = hit
case
when @card_value.match(/\d+/)
@card_value = @card_value.match(/\d+/)[0].to_i
when @card_value.match(/Ace/)
if "@#{string}"_hand >= 11
@card_value = 1
else
@card_value = 11
end
when @card_value.match(/Jack/)
@card_value = 10
when @card_value.match(/Queen/)
@card_value = 10
when @card_value.match(/King/)
@card_value = 10
else
puts "there was an error. please try again."
end
"@#{string}" = @card_value
"@#{string}"_hand = "@#{string}"_hand + "@#{string}"
end
def hit_dealer
@hit_card = @shuffled_deck.pop
value_creator("dealer")
end
def hit_player
@hit_card = @shuffled_deck.pop
value_creator("player")
end
But when I try to call the value of "@#{string}"
with hit_player
it returns @player
, not the value it was assigned.
Lots of code, but I hope it helps to give a better understanding of what I'm trying to do and will help better direct advice. Again, thanks in advance.
Upvotes: 1
Views: 187
Reputation: 27845
The comment in
hit = "@#{string}" #returns either @player or @dealer
is not correct.
The result is not @player
or @dealer
, it is the String '@player'
or '@dealer'
.
You may do something like:
def value_creator( variant )
case variant
when :player
hit = @player
when :dealer
hit = @dealer
else
raise ArgumentError
end
#....
end
def hit_dealer
@hit_card = @shuffled_deck.pop
value_creator(:dealer)
end
def hit_player
@hit_card = @shuffled_deck.pop
value_creator(:player)
end
Alternative: Use instance_variable_get
to get the value.
hit = instance_variable_get("@#{string}")
Two other possibilities:
hit = eval("@#{string}")
(I don't like it - eval is evil).
And with send
.
You have to define two accessors first:
attr_reader :player
attr_reader :dealer
Then you can use:
def value_creator( string )
hit = send( string )
Upvotes: 1