Jan E. wrote in post #1071102:
Hi,
First of all, don’t misuse instance variables to pass values to methods.
This makes the code obscure and fragile – and it’s simply bad design.
Use method parameters instead (that’s what they’re for). The purpose of
instance variables is to hold the state of an object.
It your case it cannot even work, because you have different objects.
The dragon object cannot access the instance variables from the top
level object.
So the fix for this would be to simply add a parameter to the “effect”
method for the opponent:
def effect(opponent)
And maybe further parameters for other values.
Thank you very much for reminding me of the basic rules.
kind regards
seba
I am back with another question.
I am re-factoring the game and still trying to keep it simple, so bear
with me. I’ve added effects to cards which are activated when played.
In the main file I have this for each turn:
The cards effects are activated (opponent sequence is random)
players = [@hm_player, @ai_player]
@opponent = players.sample
if @opponent == @ai_player
@own = @hm_player
hm_card.effect
@opponent = @hm_player
@own = @ai_player
ai_card.effect
elsif @opponent == @hm_player
@own = @ai_player
ai_card.effect
@opponent == @ai_player
@own = @hm_player
hm_card.effect
else
end
Now, I wanted to keep it simple, so I have the dragon’s effect defined
as follows:
def effect()
@opponent.hp -= card.attack # I’ve just spotted this error, where I
refer to card and in the above code there is still hm_card
end
When I run the game everything goes smoothly until the effect should be
activated. I get this error:
dragon.rb:31:in effect': undefined methodhp’ for nil:NilClass
(NoMethodError)
from game_02.rb:126:in `’
If I puts the opponent.hp it works though.
regards,
seba
I wanted to test this on a simple case, so I wrote the following:
def attack(target)
target -= 200
end
class A
def initialize(name, hp)
@name = name
@hp = hp
end
def hp()
@hp
end
def name()
@name
end
end
players = [] << A.new(“test”, 400)
attack(players[0].hp)
puts players[0].hp
The code runs, but the result is 400. As if the attack method did
nothing.
What am I doing wrong?
On Fri, Aug 3, 2012 at 3:06 PM, Sebastjan H. [email protected]
wrote:
end
players = [] << A.new(“test”, 400)
attack(players[0].hp)
puts players[0].hp
The code runs, but the result is 400. As if the attack method did
nothing.
What am I doing wrong?
The reason is that this line:
target -= 200 is equivalent to this one:
target = target - 200
which is assigning a new value to the local variable of the method.
Once you exit the method, the new value is lost. In order for this to
work, you should pass a reference to a mutable object, so that the
effects of the method are visible outside. For example:
def attack(target)
target.hp -= 200 # supposing target has methods #hp and #hp=
end
later…
attack(player[0])
Hope this helps,
Jesus.
In this line you wrote
target.hp -= 200 # supposing target has methods #hp and #hp=
what is the meaning of the equal sign? #hp=
Because in my case above the target only has hp method.
And if I remodel it to your example:
def attack(target)
target.hp -= 200
end
class A
def initialize(name, hp)
@name = name
@hp = hp
end
def hp()
@hp
end
def name()
@name
end
end
players = [] << A.new(“test”, 400)
attack(players[0])
puts players[0].hp
3.rb:3:in attack': undefined methodhp=’ for #<A:0x8b7d268
@name=“test”, @hp=400> (NoMethodError)
from 3.rb:24:in `’
Once again, I turn to you for your wisdom:)
Why this works:
class Depo
attr_accessor :test
def initialize(test)
@test = test
end
def test()
@test
end
end
bla = Depo.new(“blahdsd”)
def defin (bla)
if defined? test
puts “#{bla.test}”
end
end
defin(bla)
And this doesn’t:
def effect_output(card)
if defined? attack
puts “#{card.name.capitalize} hits with #{card.attack}.”
elsif defined? heal
puts “#{card.name.capitalize} heals for #{card.heal}.”
end
end
The card is a DRAGON class object with method attack defined. It has the
attr_accessor as well as initialize method defined. I don’t even get an
error. Nothing gets putsed.
If I use
if defined? :attack
then I get the message that attack is an undefined method for class
HEAL.
Of course the HEAL class doesn’t have attack method, but it should jump
to elsif, which checks for the heal method. This is true for the HEAL
class.
???
Hi,
The “defined?” operator is simply wrong in this case. It checks the
current scope for variables, methods etc.
For example:
x = 0
C = 15
puts defined? x # this outputs “local-variable”
puts defined? C # this outputs “constant”
puts defined? a # this outputs nothing (because the result is nil)
You want something completely different, namely check if an object has a
specific method. That’s what Object#respond_to? is for:
def effect_output(card)
if card.respond_to? :attack
puts “#{card.name.capitalize} hits with #{card.attack}.”
elsif card.respond_to? :heal
puts “#{card.name.capitalize} heals for #{card.heal}.”
end
end
This will call “attack” and “heal” only if the card object does actually
have those methods.
What should have made you suspicious is that you never had to specify
any object. How is Ruby then supposed to know that you want to look into
the card object?
By the way, the reason why your program output something after you used
a symbol is that
defined? :attack
returns “expression” (which is truthy).
On Fri, Aug 3, 2012 at 3:44 PM, Sebastjan H. [email protected]
wrote:
In this line you wrote
target.hp -= 200 # supposing target has methods #hp and #hp=
what is the meaning of the equal sign? #hp=
It’s part of the method name. Ruby has a bit of sintactic sugar to
allow calling methods that end with = as if they were assignments:
target.hp = 200
is equivalent to: target.hp=(200).
@name = name
end
players = [] << A.new(“test”, 400)
attack(players[0])
puts players[0].hp
3.rb:3:in attack': undefined method hp=’ for #<A:0x8b7d268
@name=“test”, @hp=400> (NoMethodError)
from 3.rb:24:in `’
If you want the external classes the possibility to read and assign
new values to hp and name, you can use attr_accessor:
class A
attr_accessor :name, :hp
def initialize(name, hp)
@name = name
@hp = hp
end
end
attr_accessor will create methods name, name=, hp and hp= for you.
Jesus.
That sounds great. 
Can we download the game anywhere?
Jan E. wrote in post #1073084:
That sounds great. 
Can we download the game anywhere?
I haven’t uploaded it anywhere, because I am not sure whether I’ll use
github or launchpad yet and even then I have to learn how to use the
repository first as I am (as stated on several occasions:) a complete
noob in the area.
I’ll post here when it’s uploaded.
kind regards,
seba
On Aug 24, 2012, at 3:26 PM, Sebastjan H. wrote:
end
elsif defined? heal
if defined? :attack
then I get the message that attack is an undefined method for class
HEAL.
???
You don’t want defined? here, you want respond_to? as in:
if card.respond_to?(:attack)
do something involving card.attack
end
-Rob
Jan E. wrote in post #1073054:
Hi,
The “defined?” operator is simply wrong in this case. It checks the
current scope for variables, methods etc.
For example:
x = 0
C = 15
puts defined? x # this outputs “local-variable”
puts defined? C # this outputs “constant”
puts defined? a # this outputs nothing (because the result is nil)
You want something completely different, namely check if an object has a
specific method. That’s what Object#respond_to? is for:
def effect_output(card)
if card.respond_to? :attack
puts “#{card.name.capitalize} hits with #{card.attack}.”
elsif card.respond_to? :heal
puts “#{card.name.capitalize} heals for #{card.heal}.”
end
end
This will call “attack” and “heal” only if the card object does actually
have those methods.
What should have made you suspicious is that you never had to specify
any object. How is Ruby then supposed to know that you want to look into
the card object?
By the way, the reason why your program output something after you used
a symbol is that
defined? :attack
returns “expression” (which is truthy).
Thank you. That helped. I actually was wondering why I didn’t have to
specify an object, but I just couldn’t make the connection.
Anyway, I think I am finished with the game for now. It runs ok and I’ve
also included a couple of different arenas which influence on the
possibility of critical strikes. It’s fun to play regarding it’s my
first game and it runs in the command line:)
I also rewrote all the parts where I misused the instance variables.
kind regards,
seba
Jan E. wrote in post #1073084:
That sounds great. 
Can we download the game anywhere?
finally:)
http://bazaar.launchpad.net/~sebastjan-hribar/dragons/dragons_and_dire_wolves/files
I still have a lot of things planned, but it’ll take me some time.
regards,
seba