0

I need help with loops.

I'm trying to capture the input from the user and determine a hotel's cost for planning a vacation.

I have a problem looping the input so the user can pick another hotel and end the program if the user does not pick any of the keystrokes ("A", "a", "B", "b", "C", "c", "D", or "d"), and then calculate the total cost for hotels.

I came up with this so far:

puts choice = gets.chomp.downcase
puts "For how many nights?"
num=gets.chomp.to_i
puts "Okay...any other hotels?"  
puts choice = gets.chomp.downcase

#Hotel Prices  

#Hotel A
if (choice== "a" or choice=="A") 
cost_2= (num/3)*500 + (num%3)*200
end

#Hotel B
if (choice=="b" or choice=="B")
cost_3= num*250
end

#Hotel C
if (choice=="c" or choice=="C")
cost_4 = (num/3)*700 + (num%3)*300
end

#Hotel D
 if (choice== "d" or choice=="D")
  cost_5= num*500
   end

Hotel Program

4
  • 3
    Have a look at Kernel#loop. Commented May 15, 2017 at 18:18
  • "How To Ask Questions The Smart Way" would be good reading for you. Commented May 15, 2017 at 18:54
  • Don't use a link to an image for information that is important to the question. Instead, copy/paste that into the question and format it appropriately. Links rot then break, and if the information in the link is essential your question will become worthless to others. Remember, your question is an article to help others solve the same problem. Commented May 15, 2017 at 19:00
  • As @sagarpandya82, suggests, the normal way is loop do; ..; break if <some condition)>;...; end. You could use (for example) while true;..;end or while 1;...; end, but loop is preferred. In some case you may prefer while(<some condition>);..;end or until(<some condition);..;end. One advantage of loop is that when the loop contains an enumerator that attempts to enumerate beyond its end, causing the enumerator to raise a StopInteration exception, loop handles the exception by breaking out of the loop. See Kernel#loop. Commented May 15, 2017 at 21:18

3 Answers 3

2

Wrap your code in a while loop,

continue = true
while continue
  ...
  if choice == "done"
    continue = false
  end
end

Obviously the end case can be anything, not just "done".

For the sake of completion, an elegant solution to this problem would be something like:

loop do
  puts choice = gets.chomp.downcase
  puts "For how many nights?"
  num=gets.chomp.to_i
  puts "Okay...any other hotels?"  
  puts choice = gets.chomp.downcase

  selections = {
     a: (num/3)*500 + (num%3)*200,
     b: num*250,
     c: (num/3)*700 + (num%3)*300,
     d: (num*500)
  }

  if selections[choice.to_sym]
    cost += selections[choice.to_sym]
  else
    break
  end
end
Sign up to request clarification or add additional context in comments.

3 Comments

IMO it's cleaner to break rather than have such boolean variables floating around.
This is a good improvement however the code still needs some refactoring. There is duplicated code and this method knows too much about HOW we ask questions and how the costs are calculated . The method itself should only care about what he needs and trust other objects to do their part. Those parts about costs could be extracted out of here into classes and each of them could be injected as a dependency . Just an idea. The code will be much more stable and will only depend on the public methods of those classes ( which could implement same interface ) which would make the code more stable
Don't use while, use loop. It's idiomatic for Ruby.
2

There are several possible improvements to your code, but I'll keep this answer as simple and direct as I can.

Use a loop, and a single if ... else if ... else ... end block code, rather than several separate if statements:

loop do
  if (choice== "a" or choice=="A") 
    cost_2= (num/3)*500 + (num%3)*200
  #Hotel B
  elsif (choice=="b" or choice=="B")
    cost_3= num*250
  #Hotel C
  elsif (choice=="c" or choice=="C")
    cost_4 = (num/3)*700 + (num%3)*300
  #Hotel D
  elsif (choice== "d" or choice=="D")
    cost_5= num*500
  else
    puts "Final cost is: [...]"
    break
  end
end

You could also consider implementing a more explicit exit by saying something like "Type 'done' when you have finished" -- and 'ignoring' any other input that is is not a/b/c/d/done. In other words, something along the lines of:

# ...
elsif (choice== "d" or choice=="D")
  cost_5= num*500
elsif choice == 'done'
  puts "Final cost is: [...]"
  break
else
  puts 'Unknown option'
end
# ...

1 Comment

@theTinMan Done.
-1

This is untested, but it's the basic idea for what I'd use:

loop do

  cost = nil
  loop do

    puts 'Which hotel? (A, B, C, D)'
    hotel = gets.chomp.downcase

    puts 'For how many nights?'
    days = gets.to_i

    cost = if hotel == 'a' 
             (days / 3) * 500 + (days % 3) * 200
           elsif hotel == 'b'
             days * 250
           elsif hotel == 'c'
             (days / 3) * 700 + (days % 3) * 300
           elsif hotel == 'd'
             days * 500
           else
             puts 'Unknown hotel.'
           end

    break if cost

  end

  puts cost

  puts 'Okay...any other hotels? (y/n)'  

  break unless gets.downcase.start_with?('y')    
end

Instead of chained if/elsif/else/end I'd use a case statement:

cost = case hotel
       when 'a' 
         (days / 3) * 500 + (days % 3) * 200
       when 'b'
         days * 250
       when 'c'
         (days / 3) * 700 + (days % 3) * 300
       when 'd'
         days * 500
       else
         puts 'Unknown hotel.'
       end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.