Still learning by doing - connecting rooms in a game

Peter H. wrote in post #1076973:

Ok just a few points on the code that you did write.

Firstly as you have given both name() and state() methods you do not
need the line

attr_accessor :name, :state

I tried this and I removed the attr_accessor line and had the methods
defined, but then the code doesn’t work:

class Zombie

def initialize(name, hp, paces, target)
@name = name
@hp = hp
@paces = paces
@target = target
end

def name()
@name
end

def hp()
@hp
end

def paces()
@paces
end

def target()
@target
end

end

However, the other way around works: having the attr_accessor line and
the initialize method in place w/o specific methods:

class Zombie
attr_accessor :name, :hp, :paces, :target

def initialize(name, hp, paces, target)
@name = name
@hp = hp
@paces = paces
@target = target
end

end

What am I doing wrong now?

Sebastjan H. wrote in post #1078385:

I tried this and I removed the attr_accessor line and had the methods
defined, but then the code doesn’t work:

What do you mean by “doesn’t work”? The class does exactly what it
should:

zombie = Zombie.new ‘some_name’, ‘some_hp’, ‘some_paces’, ‘some_target’
p zombie
puts zombie.name

Note that you do not have writer methods, so you cannot do something
like

zombie.name = ‘newname’

Anyway, the right way to do this is to use attr_accessor.

Jan E. wrote in post #1078392:

Sebastjan H. wrote in post #1078385:

I tried this and I removed the attr_accessor line and had the methods
defined, but then the code doesn’t work:

What do you mean by “doesn’t work”? The class does exactly what it
should:

zombie = Zombie.new ‘some_name’, ‘some_hp’, ‘some_paces’, ‘some_target’
p zombie
puts zombie.name

Note that you do not have writer methods, so you cannot do something
like

zombie.name = ‘newname’

Anyway, the right way to do this is to use attr_accessor.

That’s what I meant. I guess it wasn’t clear from my initial code that I
need writer, that is accessor.

Sorry if I confused anyone. It’s just that I didn’t want any duplication
as Peter suggested, but then If I understand correctly I need either the
writer or accessor to be able to change the values of instance
variables.

What I meant was, that if omit the attr_accessor completely and only
have methods for instance variables defined, then

player.hp -=20 does nothing.

regards
seba

Jan E. wrote in post #1078238:

Hi,

the item does get pushed into the array, but when you call
Player#satchel again, the variable @satchel is reset to [‘test’]. So the
previous array with the new item will be overwritten.

Check it:

player = Player.new ‘testname’
player.satchel << ‘testitem’
p player.instance_variable_get :@satchel
player.satchel # this resets @satchel to [‘test’]
p player.instance_variable_get :@satchel

So you have to change those methods. This isn’t good style, anyway,
because a getter method is supposed to do nothing but get or calculate a
certain value. It shouldn’t change the object (except maybe caching of a
calculated value). When you want to set default values, do it in the
initialize method.

I didn’t want to set a default value, the “test” in the satchel was
just my primitive way of testing whether the room and the player
communicate. And yes, I see now that it gets reset.

How should I change these methods? I am not looking for the easy way
out by you just telling me;) but I am puzzled and stuck yet again. Why >> does
it get reset by just calling it?

I was dealing with instance variable modification in my last game where >> the
player hp got modified constantly. I can’t see the difference. I

guess it is back to books…

seba

Sebastjan H. wrote in post #1078397:

Sorry if I confused anyone. It’s just that I didn’t want any duplication
as Peter suggested, but then If I understand correctly I need either the
writer or accessor to be able to change the values of instance
variables.

No, you only need to define setter methods (i. e. methods ending with a
“=”).

class A

def initialize
@x = 4
end

getter for @x

def x
@x
end

setter for @x

def x=(value)
@x = value
end

end

a = A.new
puts a.x # call getter
a.x = 3 # call setter; the same as a.x=(3)
puts a.x

That’s exactly what attr_accessor does: It defines getter and setter
methods for the given variables. You could actually define it yourself:

class Module

def my_attr_accessor *vars
vars.each do |var|
# getter
define_method(var) {instance_variable_get “@#{var}”}
# setter
define_method("#{var}=") {|val| instance_variable_set “@#{var}”,
val}
end
end

end

class A

my_attr_accessor :x, :y

def initialize
@x = 2
end

end

a = A.new
puts a.x
a.x = 12
puts a.x

What I meant was, that if omit the attr_accessor completely and only
have methods for instance variables defined, then

player.hp -=20 does nothing.

You should actually get an error saying that player doesn’t have a “hp=”
method.

Sebastjan H. wrote in post #1078412:

actually, I did get that error:)

OK, then you should have told us the exact error message.

We don’t know what you’re doing on your computer, what you’ve expected
to get and what you actually got. So we need specific information.
Something like:

I tried to set the attribute “name” with

zombie.name = ‘somename’

and got a NoMethodError saying “undefined method `name=’ for
#Zombie:0x1d63f28”.

Then we know what’s going on and can help fixing the error. But when you
say that the code “doesn’t work”, it tells us pretty much nothing. This
could mean anything from a crashed Ruby interpreter to a tiny encoding
problem. It’s even more difficult when the code does work and just
doesn’t meet your expections (that we don’t know).

The error message is actually the most important part in debugging,
because it tells you exactly what went wrong. In this case it’s saying
that your object doesn’t have a method “name=”. And that’s all you need
to know. Even if you knew nothing about Ruby and didn’t have any access
to other information, you could still fix the error just by doing what
the message is telling you (which, of course, isn’t really a good
approach).

thank you for this explanation.

What I meant was, that if omit the attr_accessor completely and only
have methods for instance variables defined, then

player.hp -=20 does nothing.

You should actually get an error saying that player doesn’t have a “hp=”
method.

actually, I did get that error:)

Jan E. wrote in post #1078421:

Sebastjan H. wrote in post #1078412:

actually, I did get that error:)

OK, then you should have told us the exact error message.

You’re right, I should have put the exact error. It was an unintentional
mistake on my behalf.
Thank you for your help.