Most elegant way to do this?

R

rbysamppi

Are there any more elegant, concise, pithy, and more Rubyish ways of
doing this?

def roll(number_of_dice)
sum = 0
number_of_dice.times do
sum += rand(5).next
end
sum
end

Thanks in advance!
 
A

Alex Young

Are there any more elegant, concise, pithy, and more Rubyish ways of
doing this?

def roll(number_of_dice)
sum = 0
number_of_dice.times do
sum += rand(5).next
end
sum
end

Thanks in advance!

The Incredible Inevitable Inject:

def roll(number_of_dice)
(0...number_of_dice).inject(0){|m,r| rand(5)+m}
end
 
J

JC

Are there any more elegant, concise, pithy, and more Rubyish ways of
doing this?

def roll(number_of_dice)
sum = 0
number_of_dice.times do
sum += rand(5).next
end
sum
end

Thanks in advance!

I don't think there's really anything you can do to it, but I would
suggest that you add a parameter to set the sides of the dice and also
add one to the random output (if it's the random number gen I'm thinking
of, it'll give you 0-5 which means your dice have a blank side :p )

-JC
 
P

Phrogz

The Incredible Inevitable Inject:

def roll(number_of_dice)
(0...number_of_dice).inject(0){|m,r| rand(5)+m}
end

You missed the +1 needed to take rand(5) to 1..6 instead of 0..5.

And I personally like 1..num_dice instead of 0...num_dice. And,
finally, I sum things so often I usually have this lying around:

module Enumerable
def sum
if block_given?
inject(0){ |sum,obj| sum + yield(obj) }
else
inject(0){ |sum,obj| sum+obj }
end
end
end

which makes the solution simply:
def roll(number_of_dice)
(1..number_of_dice).sum{ rand(5)+1 }
end


In the vein of DRY code and unix tools, I strongly encourage everyone
to be on constant vigil looking for bits of code that can be
abstracted out to little atomic re-usable bits. After a while, coding
is less like carving entire models from styrofoam, and more like
snapping little Lego blocks together.
 
R

Robert Klemme

2007/11/27 said:
You missed the +1 needed to take rand(5) to 1..6 instead of 0..5.

And everybody apparently missed 6 because rand(5) will yield *5*
values ranging in 0..4. :))
And I personally like 1..num_dice instead of 0...num_dice. And,
finally, I sum things so often I usually have this lying around:

module Enumerable
def sum
if block_given?
inject(0){ |sum,obj| sum + yield(obj) }
else
inject(0){ |sum,obj| sum+obj }
end
end
end

which makes the solution simply:
def roll(number_of_dice)
(1..number_of_dice).sum{ rand(5)+1 }
end

There is another one, that - at least theoretically - saves some
addition efforts:

require 'enumerator'

def roll(number)
raise ArgumentError, "Negative!" if number < 0
number.to_enum:)times).inject(number) {|s,| s + rand(6)}
end

I also threw in to_enum just for the fun of it. :)
In the vein of DRY code and unix tools, I strongly encourage everyone
to be on constant vigil looking for bits of code that can be
abstracted out to little atomic re-usable bits. After a while, coding
is less like carving entire models from styrofoam, and more like
snapping little Lego blocks together.

Absolutely!

Kind regards

robert
 
R

Robert Klemme

2007/11/27 said:
There is another one, that - at least theoretically - saves some
addition efforts:

Of course I wanted to say that it /practically/ saves addition efforts
and /theoretically/ it will also save time.

Cheers

robert
 
H

Heesob Park

Hi,
unknown said:
Are there any more elegant, concise, pithy, and more Rubyish ways of
doing this?

def roll(number_of_dice)
sum = 0
number_of_dice.times do
sum += rand(5).next
end
sum
end

Thanks in advance!

If you want the dice number, you should use rand(6).

How about this:

def roll(n)
eval('+rand(6)+1'*n)
end

Regards,

Park Heesob
 
W

William James

Are there any more elegant, concise, pithy, and more Rubyish ways of
doing this?

def roll(number_of_dice)
sum = 0
number_of_dice.times do
sum += rand(5).next
end
sum
end

Thanks in advance!

def sum *x
x.inject{|a,b| a+b}
end
def roll n
sum( *(1..n).map{rand(6)+1} )
end
 
R

Robert Dober

You missed the +1 needed to take rand(5) to 1..6 instead of 0..5.

And I personally like 1..num_dice instead of 0...num_dice. And,
finally, I sum things so often I usually have this lying around:

module Enumerable
def sum
if block_given?
inject(0){ |sum,obj| sum + yield(obj) }
else
inject(0){ |sum,obj| sum+obj }
end
end
end
I agree with this need, in Labrador you can do
an_enum.inject:)+)
and as we were nitpicking ;)
inject(0){ |m,| m + rand(5) } #sic ;)

R.
 
B

Brian Adkins

Are there any more elegant, concise, pithy, and more Rubyish ways of
doing this?

def roll(number_of_dice)
sum = 0
number_of_dice.times do
sum += rand(5).next
end
sum
end

Thanks in advance!

As others have pointed out, you need rand(6).next to get (1..6);
otherwise, it's hard to improve on what you have here. This is a
simple, iterative mathematical function. I personally don't think
using map, inject, etc. is more "Rubyish" in this context, just 2 to 3
times slower.

The interface is "roll n" regardless of the underlying implementation,
so you might as well make it fast.

One style improvement might be to use a one line block:

def roll num_dice
sum = 0
num_dice.times { sum += rand(6).next }
sum
end

You can make it ~10% faster (with the loss of some readability) by not
invoking next each time and just summing at the end:

def roll num_dice
sum = 0
num_dice.times { sum += rand(6) }
sum + num_dice
end


Brian Adkins
 
B

Brian Adkins

As others have pointed out, you need rand(6).next to get (1..6);
otherwise, it's hard to improve on what you have here. This is a
simple, iterative mathematical function. I personally don't think
using map, inject, etc. is more "Rubyish" in this context, just 2 to 3
times slower.

The interface is "roll n" regardless of the underlying implementation,
so you might as well make it fast.

One style improvement might be to use a one line block:

def roll num_dice
sum = 0
num_dice.times { sum += rand(6).next }
sum
end

You can make it ~10% faster (with the loss of some readability) by not
invoking next each time and just summing at the end:

def roll num_dice
sum = 0
num_dice.times { sum += rand(6) }
sum + num_dice
end

Actually make that ~12% faster with the following - just explain with
comments :)

def roll num_dice
sum = num_dice
num_dice.times { sum += rand(6) }
sum
end
 
P

Phrogz

And everybody apparently missed 6 because rand(5) will yield *5*
values ranging in 0..4. :))

Oh crimeny...oops. :p

There is another one, that - at least theoretically - saves some
addition efforts:

require 'enumerator'

def roll(number)
raise ArgumentError, "Negative!" if number < 0
number.to_enum:)times).inject(number) {|s,| s + rand(6)}
end

You know, I _want_ to embrace to_enum, because it's certainly
excellently powerful and abstract...but somehow I just don't grok it.
Thanks for the reminder. Sometime I'll have to think about it.

(I wish I could find some flaw with it, and say "no no no, what it
really should be is ____"; I just somehow basically find it confusing.)
 
B

Brian Adkins

Why be satisfied with a 10-12% increase in speed when we can have an
order of magnitude? :)

sudo gem install rubyinline

--

require 'rubygems'
require 'inline'

module Kernel
inline do |builder|
builder.c "
int roll(int n) {
int sum = n;
while (n-- > 0) {
sum += (rand() % 6);
}
return sum;
}
"
end
end

puts roll(3)
 
E

Eivind Eklund

Why be satisfied with a 10-12% increase in speed when we can have an
order of magnitude? :)

sudo gem install rubyinline

--

require 'rubygems'
require 'inline'

module Kernel
inline do |builder|
builder.c "
int roll(int n) {
int sum = n;
while (n-- > 0) {
sum += (rand() % 6);
}
return sum;
}
"
end
end

puts roll(3)

If you're going to do overkill, do overkill. You've got an extra
compare in that main loop, with the check for n-- > 0. And it doesn't
work for negative numbers. Correcting for this (untested):
int roll(int n) {
int sum = n;
if (n > 0) {
do {
sum += rand() % 6;
} while (--n);
} else if (n < 0) {
do {
sum -= rand() % 6;
} while (++n);
}
return sum;
}

Of course, this still has the problem that rand() % 6 typically return
slightly biased numbers, as RAND_MAX is usually a 2^n-1

;-)

Eivind.
 
C

Cameron McBride

Of course, this still has the problem that rand() % 6 typically return
slightly biased numbers, as RAND_MAX is usually a 2^n-1

;-)

Eivind.

hah! overkill not only on method, but also in worry. biased Nd6?
awesome! ok, that kind of made my morning.

Cameron
 
R

Robert Klemme

2007/11/27 said:
As others have pointed out, you need rand(6).next to get (1..6);
otherwise, it's hard to improve on what you have here. This is a
simple, iterative mathematical function. I personally don't think
using map, inject, etc. is more "Rubyish" in this context, just 2 to 3
times slower.

The interface is "roll n" regardless of the underlying implementation,
so you might as well make it fast.

One style improvement might be to use a one line block:

def roll num_dice
sum = 0
num_dice.times { sum += rand(6).next }
sum
end

You can make it ~10% faster (with the loss of some readability) by not
invoking next each time and just summing at the end:

def roll num_dice
sum = 0
num_dice.times { sum += rand(6) }
sum + num_dice
end

I guess there is even more room for improvement by doing this:

def roll num_dice
sum = roll num_dice
num_dice.times { sum += rand(6) }
sum
end

SCNR ;-)

robert
 
B

Brian Adkins

If you're going to do overkill, do overkill. You've got an extra
compare in that main loop, with the check for n-- > 0.

I assume you're just having fun, but even so, if your compiler doesn't
optimize (n-- > 0) to be as efficient as (n--), get a new compiler.
And it doesn't
work for negative numbers. Correcting for this (untested):

Yes, rolling a negative number of dice is precluded, it just confuses
people.
int roll(int n) {
int sum = n;
if (n > 0) {
do {
sum += rand() % 6;
} while (--n);
} else if (n < 0) {
do {
sum -= rand() % 6;
} while (++n);
}
return sum;

}

You might want to double check that code...
Of course, this still has the problem that rand() % 6 typically return
slightly biased numbers, as RAND_MAX is usually a 2^n-1

Ok, here you have a point. The roll function won't cut it in Las
Vegas.
 

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

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top