Deleting from hashes

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

···

--
Posted via http://www.ruby-forum.com/.

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],
]
[...]
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 Jan 20, 2011, at 16:56 , Josh Rowe wrote:

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

···

On Fri, Jan 21, 2011 at 1:56 AM, Josh Rowe <joshua@wired.com.au> wrote:

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)

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

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

···

--
Posted via http://www.ruby-forum.com/.

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

···

--
Posted via http://www.ruby-forum.com/.

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

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)

···

On Fri, Jan 21, 2011 at 10:44 AM, Josh Rowe <joshua@wired.com.au> wrote:
------------------------------------------------------------------------------
  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

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

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])

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 Fri, Jan 21, 2011 at 11:16 AM, Josh Rowe <joshua@wired.com.au> wrote:

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

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 Jan 21, 2011, at 02:53 , Robert Klemme wrote:

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

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

···

On Fri, Jan 21, 2011 at 12:12 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:

On Jan 21, 2011, at 02:53 , Robert Klemme 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.

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