Deleting from hashes

Hi all!
Following on from my previous question

I need some help with deleting cards from a hash. Heres what I have

#!/usr/bin/env ruby
Card = Struct.new :name, :type, :atk, :defn, :level
$deck = [
Card[“Celtic Guardian”, :monster, 1400, 1200,4],
Card[“Dark Magician”, :monster, 2500, 2100,7],
]

def draw
draw = rand(1)
puts “you drew the number #{draw}”
puts “you drew the card #{$deck[draw].name}”
end
draw

So what I need help with is deleting the card I just drew and stopping
it from being drawn again. Also I’ve heard it’s bad to use global
variable but is it ok to have just one?

Thank you in advance. Regards Joshua

On Jan 20, 2011, at 16:56 , Josh R. wrote:

]
[…]
So what I need help with is deleting the card I just drew and stopping
it from being drawn again.

First off, that’s an array, not a hash.

Second, it sounds like you could use some ‘ri’ love. Try this in your
terminal:

ri Array

You should see all the methods available on Array. From there it is
pretty easy to guess what you want as ruby methods are intelligently
named.

Also I’ve heard it’s bad to use global
variable but is it ok to have just one?

Meh. For learning the language they’re fine.

On Fri, Jan 21, 2011 at 1:56 AM, Josh R. [email protected] wrote:

def draw
draw = rand(1)

rand(1) won’t work as intended, since you never get 1 as result. You
would need at least rand(2) but even better use

draw = rand($deck.size)

otherwise the drawing won’t work reliably once $deck has changed.

Kind regards

robert

Thank you all, now for the issue of that being an array. I made a
mistake in which code to copy and paste. This is the hash

card1 = {:name => “Celtic guardian”, :type => “monster”, :atk => 1400,
:def => 1200, :level => 4}
card2 = {:name => “Dark Magician”, :type => “monster”, :atk => 2500,
:def => 2100, :level => 7}
$deck = [card1,card2]
def draw
draw = rand($deck.size)
puts “you drew the card #{$deck[draw][:name]}”
$deck.delete(draw)
end
draw

This is what I think it should look like.

What do you all think regarding using arrays or hashes in my card game?
Any thoughts would be appreciated.

Regards

Joshua

On Fri, Jan 21, 2011 at 10:44 AM, Josh R. [email protected] wrote:

puts “you drew the card #{$deck[draw].name}”
$deck.delete(draw)
end
draw

Still, $deck is an Array and you want to delete from $deck and not
from any of the Hashes in the Array!

This is what I think it should look like.

Please rethink.

10:55:44 ~$ ri19 Array#delete Array#delete_at
Array#delete

(from ruby core)

ary.delete(obj) → obj or nil
ary.delete(obj) { block } → obj or nil


Deletes items from self that are equal to obj. If any items are
found, returns obj. If the item is not found, returns nil. If
the optional code block is given, returns the result of block if the
item is not found. (To remove nil elements and get an informative
return value, use #compact!)

a = [ “a”, “b”, “b”, “b”, “c” ]
a.delete(“b”) #=> “b”
a #=> [“a”, “c”]
a.delete(“z”) #=> nil
a.delete(“z”) { “not found” } #=> “not found”

Array#delete_at

(from ruby core)

ary.delete_at(index) → obj or nil


Deletes the element at the specified index, returning that element, or
nil if the index is out of range. See also Array#slice!.

a = %w( ant bat cat dog )
a.delete_at(2) #=> “cat”
a #=> [“ant”, “bat”, “dog”]
a.delete_at(99) #=> nil

10:56:05 ~$

What do you all think regarding using arrays or hashes in my card game?
Any thoughts would be appreciated.

No idea as I don’t know what your game is about and how it is supposed
to be played.

Kind regards

robert

I now have it working, this is what it looks like

card1 = {:name => “Celtic guardian”, :type => “monster”, :atk => 1400,
:def => 1200, :level => 4}
card2 = {:name => “Dark Magician”, :type => “monster”, :atk => 2500,
:def => 2100, :level => 7}
card3 = {:name => “Spike Seadra”, :type => “monster”, :atk => 1600, :def
=> 1300, :level => 5}
$deck = [card1,card2,card3]
def draw
draw = rand($deck.size)
puts draw
puts “you drew the card #{$deck[draw][:name]}”
$deck.delete($deck[draw])
end
3.times do
draw
x = $deck.empty?
if x == true
puts “Game over!”
end
end

Thank you both for answering my beginner questions. I hope I will be
able to help people on this forum one day.

Kind regards

Joshua

On Fri, Jan 21, 2011 at 11:16 AM, Josh R. [email protected] wrote:

draw = rand($deck.size)
puts draw
puts “you drew the card #{$deck[draw][:name]}”
$deck.delete($deck[draw])

I’d rather use Array#delete_at because it is more efficient. Your
solution needs to traverse the whole Array to find the elements to
remove. Yes, in fact it may remove multiple elements!
Array#delete_at just removes a single position.

Btw, you can make the code even simpler and more efficient by doing:

def draw
draw = rand($deck.size)
puts draw
card = $deck.delete_at(draw)
puts “you drew the card #{card[:name]}”
end

This avoids one Array access.

end
3.times do
draw
x = $deck.empty?
if x == true
puts “Game over!”
end
end

Comparing x with true is a bad idea because there are multiple values
for true in Ruby. Generally comparing boolean values or expressions
with boolean constants to get a boolean value is a bad idea because

a) it is superfluous (we do have a boolean value already)
b) it leads to subtle errors which are hard to detect in all languages
which have more than one value representing either boolean state true
and false.

In your case you can simplify to

if $deck.empty?
puts “Game over!”
end

or even

puts “Game over!” if $deck.empty?

Thank you both for answering my beginner questions.

You’re welcome.

I hope I will be
able to help people on this forum one day.

Certainly!

Kind regards

robert

On Jan 21, 2011, at 02:53 , Robert K. wrote:

I’d rather use Array#delete_at because it is more efficient.

Maybe it is just me… but when they’re still using training wheels I
tend to bias my advice towards correctness and form… not speed or
efficiency.

On Fri, Jan 21, 2011 at 12:12 PM, Ryan D. [email protected]
wrote:

On Jan 21, 2011, at 02:53 , Robert K. wrote:

I’d rather use Array#delete_at because it is more efficient.

Maybe it is just me… but when they’re still using training wheels I tend to
bias my advice towards correctness and form… not speed or efficiency.

Well, as I pointed out (maybe not clear enough) it’s also more correct
because it will only remove the exact element at the draw position.
Array#delete potentially removes more (probably not in this particular
case but generally).

Cheers

robert