Deleting from hashes

J

Josh Rowe

Hi all!
Following on from my previous question
http://www.rubyforum.com/topic/912567#new
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
 
R

Ryan Davis

Hi all!
Following on from my previous question
http://www.rubyforum.com/topic/912567#new
I need some help with deleting cards from a hash. Heres what I have
=20
#!/usr/bin/env ruby
Card =3D Struct.new :name, :type, :atk, :defn, :level
$deck =3D [
Card["Celtic Guardian", :monster, 1400, 1200,4],
Card["Dark Magician", :monster, 2500, 2100,7],
]
[...]
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. =46rom 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.=
 
R

Robert Klemme

Following on from my previous question
http://www.rubyforum.com/topic/912567#new
I need some help with deleting cards from a hash. Heres what I have

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

def draw
=A0draw =3D 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 =3D rand($deck.size)

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

Kind regards

robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
J

Josh Rowe

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
 
R

Robert Klemme

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 =3D {:name =3D> "Celtic guardian", :type =3D> "monster", :atk =3D> = 1400,
:def =3D> 1200, :level =3D> 4}
card2 =3D {:name =3D> "Dark Magician", :type =3D> "monster", :atk =3D> 25= 00,
:def =3D> 2100, :level =3D> 7}
$deck =3D [card1,card2]
def draw
=A0draw =3D rand($deck.size)
=A0puts "you drew the card #{$deck[draw].name}"
=A0$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 =3D [ "a", "b", "b", "b", "c" ]
a.delete("b") #=3D> "b"
a #=3D> ["a", "c"]
a.delete("z") #=3D> nil
a.delete("z") { "not found" } #=3D> "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 =3D %w( ant bat cat dog )
a.delete_at(2) #=3D> "cat"
a #=3D> ["ant", "bat", "dog"]
a.delete_at(99) #=3D> 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

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
J

Josh Rowe

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
 
R

Robert Klemme

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

card1 =3D {:name =3D> "Celtic guardian", :type =3D> "monster", :atk =3D> = 1400,
:def =3D> 1200, :level =3D> 4}
card2 =3D {:name =3D> "Dark Magician", :type =3D> "monster", :atk =3D> 25= 00,
:def =3D> 2100, :level =3D> 7}
card3 =3D {:name =3D> "Spike Seadra", :type =3D> "monster", :atk =3D> 160= 0, :def
=3D> 1300, :level =3D> 5}
$deck =3D [card1,card2,card3]
def draw
=A0draw =3D rand($deck.size)
=A0puts draw
=A0puts "you drew the card #{$deck[draw][:name]}"
=A0$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 =3D rand($deck.size)
puts draw
card =3D $deck.delete_at(draw)
puts "you drew the card #{card[:name]}"
end

This avoids one Array access.
end
3.times do
=A0draw
=A0x =3D $deck.empty?
=A0if x =3D=3D true
=A0 =A0puts "Game over!"
=A0end
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

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
R

Ryan Davis

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.
 
R

Robert Klemme

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,138
Messages
2,570,803
Members
47,349
Latest member
jojonoy597

Latest Threads

Top