There are many reasons your code doesn't work. Let's see what happens running
it in ruby (by the way, when asking for help about a piece of code which
produces an error, it's better to also show the error message):
* FIRST TRY:
./prova.rb:13:in `initialize': wrong number of arguments (2 for 0)
(ArgumentError)
This means that some initialize method is called with 2 arguments, when it
should receive no argument on line 11. The line in question is:
@power = Roll.new(10, 8)
Apparently, there's no call to initialize here. What you're trying to do in
this line, is to create an instance of class Roll, calling Roll.new. For most
classes, the 'new' method first creates a new object, then calls its
'initialize' method, which, as the name implies, is used to perform
initialization on the object (for example, giving starting values to instance
variables). Since you didn't define an initialize method for class Roll, it
uses the one defined for the parent class, which is Object.
The initialize method defined for class Object takes no argument, so you get
an error.
Looking at the definition of class Roll, i see you defined a method called
Roll, which takes two arguments and sets instance variables, just like
initialize should do. I guess you thought that method would have been called
by new. Let's rename it to initialize and see if it solves the problem.
* SECOND TRY:
./prova.rb:5:in `initialize': undefined method `random' for #<Roll:0xb7c10c70
@range=8, @base=10> (NoMethodError)
This is easy: you're calling a method named 'random', which doesn't exist.
The method which generates a random number in ruby is called rand, so we'll
replace random with rand
* THIRD TRY:
./prova.rb:26:in `health': undefined method `/' for #<Roll:0xb7beeb34
@range=8, @base=10, @roll=15> (NoMethodError)
from ./prova.rb:41
Now, ruby hits an error while calling the health method: in particular, in
line 26 there's a call to a method '/' which is undefined. Line 26 is:
@health = self.power*(self.smarts/self.speed)
In ruby, operators such as +, -, * and / are simply methods, so that when you
write, for example 2 + 3, ruby calls the '+' method of the object 2 passing
it the object 3 as argument. In your code, you're dividing self.smarts by
self.speed, which are both of class Roll. Class Roll doesn't have a method
called '/', so you get the error.
This problem could be solved defining a sensible / method for class Roll, or,
more simply, by defining a method which allows to get the value of the
variable @roll of an instance of roll (which is a number), and use that
instead of the instance of Roll itself. It may be worth asking whether class
Roll really needs to exist. If you won't require the @base and @range values
somewhere else, then it would be much easier to replace the whole class with
a method such as this:
def roll(base, range)
base + rand(range)
end
At any rate, let's assume that Roll needs to be a class and add a method
which allows to extract the @roll instance variable. We could define it by
hand, but ruby does it automatically if we add this line inside class Roll:
attr_reader :roll
This generates a method called roll which returns @roll.
Then, we need to replace speed and smarts and power with speed.roll,
smarts.roll and power.roll in lines 24, 26 and 47 (we would get an analogous
problem with the acc method if we leaved it as it is).
* FOURTH TRY
#<Roll:0xb7cd0b60> = power
#<Roll:0xb7cd0afc> = smarts
#<Roll:0xb7cd0aac> = speed
0 = health
./prova.rb:43:in `+': String can't be coerced into Float (TypeError)
from ./prova.rb:43
Before looking at the error, there are two things to notice: first, power,
smarts and speed aren't numbers but instances of class Roll. If this isn't
what you expected, then most likely you should replace class Roll with the
method roll as I mentioned above. Second, health is 0 (of course, this will
depend on the random number which have been generated). Since both
smarts.roll and speed.roll are integers, the division will return 0 if the
divider is greater than the divisor. To avoid this, add a call to to_f to one
of the operands. to_f will convert the integer to a float, so the division
will use decimals.
Looking at the error, it simply means that, in line 43, we're trying to add a
number with a string. The reason is simply that you forget to call the to_s
method on joe.acc as you did for the other ones.
* FIFTH TRY
#<Roll:0xb7c79af4> = power
#<Roll:0xb7c79a90> = smarts
#<Roll:0xb7c79a40> = speed
10 = health
10.75 = acc
#<Npc:0xb7c79b6c>
code.rb (958 Bytes)
···
On Monday 03 March 2008, August0866 wrote:
Hi All,
I am not a programmer, yet. I am trying ruby on for size, most things
fit ok, but Classes are puzzling me.
<code>
class Roll
def Roll(base,range)
@base=base
@range=range
@roll = base+random(range)
end
end
class Stats
def power
@power=Roll.new(10,8)
end
def speed
@speed=Roll.new(10,8)
end
def smarts
@smarts=Roll.new(10,8)
end
end
class Attribs < Stats
def acc
@acc=0.75*self.power+(self.speed/self.smarts)
end
def health
@health = self.power*(self.smarts/self.speed)
end
end
class Npc < Attribs
def name(name)
@name=name
end
end
joe=Npc.new
joe.name('Joe')
#puts joe.name.to_s+' = name'
puts joe.power.to_s+' = power'
puts joe.smarts.to_s+' = smarts'
puts joe.speed.to_s+' = speed'
puts joe.health.to_s+' = health'
puts joe.acc+' = acc'
puts joe
puts '======================='
puts 'Calculations'
puts 0.75*joe.power+(joe.speed/joe.smarts)
</code>
OK, so why is this broken?
=======================
Calculations
11.5
Now, it works.
Attached, you'll find a copy of the code with all the modifications I spoke
about.
I hope this helps
Stefano