Creating multiple objects from a model

Hi all,

I'm new to the programming world, so much of this stuff is still pretty
foreign to me.

I've created a 'roll_dice.rb' program that draws on the 'die.rb' model.
When the roll_dice program is run, the user is simply prompted to type
'roll' to roll the dice and get a result. Typing 'quit' exits the
program.

I'd like to expand the functionality of this program such that when the
program is run, the user is first prompted to enter in how many dice
they would like to roll. After answering, the user would then type
'roll' and receive back the same number of answers as number of dice.
i.e. :

How many dice would you like to roll?

2

Type 'roll' to roll your dice.

roll

3
2
Type 'roll' to roll your dice.

roll

6
4

The thing is, I'm not sure how to add that kind of functionality to my
program yet. Thoughts and suggestions are appreciated. Thanks!

Here is my current code (I've also included it as an attachment):

die.rb

Class Die
  def rolled_dice
    1 + rand(6)
  end
end

roll_dice.rb

require_relative 'die'

@die = Die.new

while true
  puts "Type 'roll' to roll the dice."
  answer = gets.chomp
  if answer == 'roll'
    puts @die.rolled_dice
  elsif answer == 'quit'
    break
  else
    puts "Please type 'roll' or 'quit'."
  end
end

Attachments:
http://www.ruby-forum.com/attachment/8742/die.rb
http://www.ruby-forum.com/attachment/8743/roll_dice.rb

···

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

You need to do two things:

1. Add another prompt before the while loop which asks for number of
dice, reads the user input and converts it to an integer value.
2. Use the integer value inside the loop where you print out results
of rolling dice to do so repeatedly (e.g. by using method
Fixnum#times).

Does that help?

Kind regards

robert

···

On Tue, Sep 24, 2013 at 2:48 PM, Mike Vezzani <lists@ruby-forum.com> wrote:

The thing is, I'm not sure how to add that kind of functionality to my
program yet. Thoughts and suggestions are appreciated. Thanks!

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

You could use an Array of Dice, based on the number given by the user:

puts 'Enter the number of dice to use'
number = Integer( gets )
@dice = Array.new( number, Dice.new )

# ask about rolling, etc...
puts @dice.map { |die| die.rolled_dice }

···

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

Thanks Robert and Joel for your suggestions. It forced me to browse some
Ruby functionality online. In the end, I went with Robert's suggestion.
Here is the code as it stands now:

The individual Die:

class Die
  def roll_dice
    1 + rand(6)
  end
end

The program:

require_relative 'die'

@die = Die.new

# Ask user how many dice to roll
puts "How many dice would you like to roll?"

# Store that value into a variable as an integer
number_of_dice = gets.chomp.to_i

# Run a loop that allows to user to roll until they type quit
while true
  puts "Please type 'roll' to roll the dice or 'quit' to quit."
  response = gets.chomp
  if response == 'roll'
    rolling_dice = number_of_dice
    puts

    # Utilize number_of_dice variable to simulate multiple dice being
      rolled
    while rolling_dice > 0
      puts @die.roll_dice
      rolling_dice -= 1
    end

    puts
  elsif response == 'quit'
    break
  else
    puts "Please type 'roll' or 'quit'."
  end
end

I've heard a little bit about the MVC structure. I recognize that the
command line output is my view, and for right now I'm not interested in
customizing that. However, I am curious to know if I'm following proper
form in terms of what code is in my controller (roll_dice.rb) and my
model (die.rb). Thoughts/comments/suggestions are always appreciated.

Thanks!

···

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

The way Dice is implemented it does not make sense to have more than
one of them.

Kind regards

robert

···

On Tue, Sep 24, 2013 at 4:49 PM, Joel Pearson <lists@ruby-forum.com> wrote:

You could use an Array of Dice, based on the number given by the user:

puts 'Enter the number of dice to use'
number = Integer( gets )
@dice = Array.new( number, Dice.new )

# ask about rolling, etc...
puts @dice.map { |die| die.rolled_dice }

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

Thanks Robert and Joel for your suggestions. It forced me to browse some
Ruby functionality online. In the end, I went with Robert's suggestion.
Here is the code as it stands now:

The individual Die:

class Die
  def roll_dice
    1 + rand(6)
  end
end

The program:

require_relative 'die'

@die = Die.new

# Ask user how many dice to roll
puts "How many dice would you like to roll?"

# Store that value into a variable as an integer
number_of_dice = gets.chomp.to_i

Disadvantage of #to_i vs. Integer() is that #to_i will happily convert
whatever it sees and you won't notice errors - you end up wondering
why there is no output because the default value is 0. So better do
what Joel suggested (#chomp is not needed).

number_of_dice = Integer(gets)

# Run a loop that allows to user to roll until they type quit
while true
  puts "Please type 'roll' to roll the dice or 'quit' to quit."
  response = gets.chomp
  if response == 'roll'
    rolling_dice = number_of_dice
    puts

    # Utilize number_of_dice variable to simulate multiple dice being
      rolled
    while rolling_dice > 0
      puts @die.roll_dice
      rolling_dice -= 1
    end

You can abbreviate the loop to

number_of_dice.times { puts @die.roo_dice }

    puts
  elsif response == 'quit'
    break
  else
    puts "Please type 'roll' or 'quit'."
  end
end

I've heard a little bit about the MVC structure. I recognize that the
command line output is my view, and for right now I'm not interested in
customizing that. However, I am curious to know if I'm following proper
form in terms of what code is in my controller (roll_dice.rb) and my
model (die.rb). Thoughts/comments/suggestions are always appreciated.

Generally for such a console application the term MVC is not used so
it feels a bit awkward here. But I think you got it about right.
Some things which are unusual:

- Your model does not have state.
- Your model does not notify anybody of state changes (well, since
there is no state, it cannot change :-))
- There are no events because the structure of interactions is fixed
(opposed to graphical user interfaces where the user can click on this
button or enter text in an input field or close the window or...).

Kind regards

robert

···

On Tue, Sep 24, 2013 at 9:38 PM, Mike Vezzani <lists@ruby-forum.com> wrote:

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

Robert Klemme wrote in post #1122292:

···

On Tue, Sep 24, 2013 at 4:49 PM, Joel Pearson <lists@ruby-forum.com> > wrote:

You could use an Array of Dice, based on the number given by the user:

puts 'Enter the number of dice to use'
number = Integer( gets )
@dice = Array.new( number, Dice.new )

# ask about rolling, etc...
puts @dice.map { |die| die.rolled_dice }

The way Dice is implemented it does not make sense to have more than
one of them.

Kind regards

robert

Fair point, I was thinking that if added complexity was required later -
e.g. dice maintaining their state - then an Array would be more
suitable.
As it stands there isn't even a point in having a Die class, a single
method could do the job :slight_smile:

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

Absolutely. One could even wonder whether this problem warrants a
method of its own. :slight_smile:

There are two more remarks I forgot in my previous post:

1. instead of if...elsif a case construct would also fit nicely.
2. Endless loop can be done with loop and a block. Or we can place the
loop body in the where condition. Better still use a loop which test
the condition at the end

# Ask user how many dice to roll
puts "How many dice would you like to roll?"

# Store that value into a variable as an integer
number_of_dice = Integer(gets)

1 while puts "Please type 'roll' or 'quit'." or
  case gets.chomp
  when 'roll'
    number_of_dice.times { puts 1+rand(6) }
  when 'quit'
    false
  else
    true
  end

I admit, this is a bit weird way to do it. :slight_smile: A more conservative
approach might be

begin
  puts "Please type 'roll' or 'quit'."
  go = case gets.chomp
  when 'roll'
    number_of_dice.times { puts 1+rand(6) }
  when 'quit'
    false
  else
    true
  end
end while go

Cheers

robert

···

On Tue, Sep 24, 2013 at 10:09 PM, Joel Pearson <lists@ruby-forum.com> wrote:

Robert Klemme wrote in post #1122292:

On Tue, Sep 24, 2013 at 4:49 PM, Joel Pearson <lists@ruby-forum.com> >> wrote:

You could use an Array of Dice, based on the number given by the user:

puts 'Enter the number of dice to use'
number = Integer( gets )
@dice = Array.new( number, Dice.new )

# ask about rolling, etc...
puts @dice.map { |die| die.rolled_dice }

The way Dice is implemented it does not make sense to have more than
one of them.

Fair point, I was thinking that if added complexity was required later -
e.g. dice maintaining their state - then an Array would be more
suitable.
As it stands there isn't even a point in having a Die class, a single
method could do the job :slight_smile:

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