Reservation System - ruby

Can anyone please tell me what I should be using and why this method isn't correct? The code doesn't work, I know, I just want to know how I can interface with the array for this type of thing.
Thank you.
Code:
$i = 1
$f = 0
$c = 0
answer = ""
loop do
puts "Welcome\n"
puts "If you'd like to fly in first class, Press 1. For coach, Push 2."
answer = STDIN.gets
answer.chop!
break if answer =~ /1|2/
if answer == 1 then
$i += 1.each
$available.at(0..4)
end
if answer == 2 then
$i += 1.each
$available.at(5..19)
else
puts "Invalid number, enter 1 or 2."
Console_Screen.pause
end
end
puts "Here is your boarding pass. You are in seat " + $i.to_s

For first class, you can do something like this:
next_first = (0..4).find { |i| $available[i] != 1 }
If that gives you a next_available that is nil then first class is full, otherwise you have the index of the next available first class seat.
Similarly for coach:
next_coach = (5..19).find { |i| $available[i] != 1 }
Then once you have the index, have checked that it isn't nil, and stored it in $i, just $available[$i] = 1 to reserve the seat.
And an extra hint for free, this:
answer = STDIN.gets
answer.chop!
leaves a string in answer so answer == 1 will always be false.
References:
Enumerable#find

The problem seems to be here:
break if answer =~ /1|2/
This means "stop and leave the loop entirely if if we get a 1 or 2"
ie it means that none of your code that does seat-allocation gets executed if the person actually enters something valid (ie a 1 or 2).
After that comes the errors pointed out by #mu_is_too_short above.

Related

Ruby while loop keeps repeating regardless of input

I wrote a simple guess the number game. But it keeps looping even when I input the correct number. Please help, thanks!
puts "Pick a number between 0 - 1000."
user_guess = gets.chomp.to_i
my_num = rand(831)
guess_count = 0
until user_guess == my_num do
if user_guess == my_num
guess_count += 1
puts "you got it!"
elsif user_guess <= 830
guess_count += 1
puts "higher"
else user_guess >= 1000
guess_count += 1
puts "lower"
end
end
puts "You guessed my number in #{guess_count} attempts. Not bad"
The part of the code that asks for a number from the user is outside the loop, so it will not repeat after the answer is checked. If you want to ask the user to guess again when their guess is wrong, that code needs to be inside the loop.
my_num = rand(831)
guess_count = 0
keep_going = true
while keep_going do
puts "Pick a number between 0 - 1000."
user_guess = gets.chomp.to_i
if user_guess == my_num
guess_count += 1
puts "you got it!"
keep_going = false
elsif user_guess <= 830
guess_count += 1
puts "higher"
else user_guess >= 1000
guess_count += 1
puts "lower"
end
end
puts "You guessed my number in #{guess_count} attempts. Not bad"
This code still has some bugs in it that stops the game from working correctly though, see if you can spot what they are.
As #Tobias has answered your question I would like to take some time to suggest how you might make your code more Ruby-like.
Firstly, while you could use a while or until loop, I suggest you rely mainly on the method Kernel#loop for most loops you will write. This simply causes looping to continue within loop's block until the keyword break is encountered1. It is much like while true or until false (commonly used in some languages) but I think it reads better. More importantly, the use of loop protects computations within its block from prying eyes. (See the section Other considerations below for an example of this point.)
You can also exit loop's block by executing return or exit, but normally you will use break.
My second main suggestion is that for this type of problem you use a case statement rather than an if/elsif/else/end construct. Let's first do that using ranges.
Use a case statement with ranges
my_num = rand(831)
guess_count = 0
loop do
print "Pick a number between 0 and 830: "
guess_count += 1
case gets.chomp.to_i
when my_num
puts "you got it!"
break
when 0..my_num-1
puts "higher"
else
puts "lower"
end
end
There are a few things to note here.
I used print rather than puts so the user will enter their response on on the same line as the prompt.
guess_count is incremented regardless of the user's response so that can be done before the case statement is executed.
there is no need to assign the user's response (gets.chomp.to_i) to a variable.
case statements compare values with the appropriate case equality method ===.
With regard to the last point, here we are comparing an integer (gets.chomp.to_i) with another integer (my_num) and with a range (0..my_num-1). In the first instance, Integer#=== is used, which is equivalent to Integer#==. For ranges the method Range#=== is used.
Suppose, for example, that my_num = 100 and gets.chomp.to_i #=> 50 The case statement then reads as follows.
case 50
when 100
puts "you got it!"
break
when 0..99
puts "higher"
else
puts "lower"
end
Here we find that 100 == 50 #=> false and (0..99) === 50 #=> true, so puts "higher" is displayed. (0..99) === 50 returns true because the integer (on the right of ===) is covered by the range (on the left). That is not the same as 50 === (0..90), which loosely reads, "(0..99) is a member of 50", so false is returned.
Here are a couple more examples of how case statements can be used to advantage because of their reliance on the triple equality method.
case obj
when Integer
obj + 10
when String
obj.upcase
when Array
obj.reverse
...
end
case str
when /\A#/
puts "A comment"
when /\blaunch missiles\b/
big_red_button.push
...
end
Use a case statement with the spaceship operator <=>
The spaceship operator is used by Ruby's Array#sort and Enumerable#sort methods, but has other uses, as in case statements. Here we can use Integer#<=> to compare two integers.
my_num = rand(831)
guess_count = 0
loop do
print "Pick a number between 0 and 830: "
case gets.chomp.to_i <=> my_num
when 0
puts "you got it!"
break
when -1
puts "higher"
else # 1
puts "lower"
end
end
In other applications the spaceship operator might be used to compare strings (String#<=>), arrays (Array#<=>), Date objects (Date#<=>) and so on.
Use a hash
Hashes can often be used as an alternative to case statements. Here we could write the following.
response = { -1=>"higher", 0=>"you got it!", 1=>"lower" }
my_num = rand(831)
guess_count = 0
loop do
print "Pick a number between 0 and 830: "
guess = gets.chomp.to_i
puts response[guess <=> my_num]
break if guess == my_num
end
Here we need the value of gets.chomp.to_i twice, so I've saved it to a variable.
Other considerations
Suppose we write the following:
i = 0
while i < 5
i += 1
j = i
end
j #=> 5
j following the loop is found to equal 5.
If we instead use loop:
i = 0
loop do
i += 1
j = i
break if i == 5
end
j #=> NameError (undefined local variable or method 'j')
Although while and loop both have access to i, but loop confines the values of local variables created in its block to the block. That's because blocks create a new scope, which is good coding practice. while and until do not use blocks. We generally don't want code following the loop to have access to local variables created within the loop, which is one reason for favouring loop over while and until.
Lastly, the keyword break can also be used with an argument whose value is returned by loop. For example:
def m
i = 0
loop do
i += 1
break 5*i if i == 10
end
end
m #=> 50
or
i = 0
n = loop do
i += 1
break 5*i if i == 10
end
n #=> 50
1. If you examine the doc for Kernel#loop you will see that executing break from within loop's block is equivalent to raising a StopIteration exception.

Simple program but so very stuck- Loops in Ruby

I have to write a program which asks the user to enter a number.
The program keeps on asking the user for a number until the user types 'Stop'
at which point the sum of the numbers that the user has entered should be printed.
I've tried many,many things and none of my ideas work.
This is what I have - but I can that it isn't correct. What am I doing wrong?
I've only used while loops and arrays
total_user_input = []
# As long as the user inputs a number, the program will keep putting Give me a number
# and then adding that number to the total_user_input array.
puts "Give me a number: "
while user_input = gets.chomp.to_i
#add the input to the array total_user_input
total_user_input.push(user_input.to_i)
puts "Give me a number: "
# If the user however types stop, then the loop is broken and we jump down to the
# sum bit - where all of the numbers in the total_user_input array are added together
# and printed. End of program!
if user_input == "stop"
break
end
sum = 0
total_user_input.each { |num|
sum += num
}
puts sum
end
The output isn't as it should be.
As others have identified the problems with your code let me suggest how you might reorganize it. Ruby provides many ways to execute loops but you many find it desirable to primarily relay on the method Kernel#loop and the keyword break. (As you will learn in time, loop is particularly convenient when used with enumerators.)
def sum_numbers
tot = 0
loop do
print 'Gimme a number: '
s = gets.chomp
break if s == 'Stop'
tot += s.to_i
end
tot
end
The keyword break can optionally take an argument (though why that is not mentioned in the doc I cannot say), in which case it (if a literal) or its value (if a variable or method) is returned by loop. Here one would generally see
break tot if s == 'Stop'
without the final line, tot. As the loop returns tot and that is the last calculation performed by the method, the method will return the final value of tot.
You could have instead written
return tot if user_input == 'Stop'
but I think most coders believe best practice dictates that one should not return from a method from within a loop (or from within nested loops) unless there is a good reason for doing so.
Some small points:
I used print rather than puts to that the user's entry will be shown on the same line as the prompt.
I used s (for "string") rather than user_input because it reduces the chance of spelling mistakes (e.g., user_imput), speeds reading, and (possibly a foible of mine), looks neater. True, s is not descriptive, but one only has to remember its meaning for three consecutive lines of code. Others may disagree.
You could write, break if s.downcase == 'stop' if you want, say, 'stop' or 'STOP' to have the same effect as 'Stop'.
'23O3'.to_i #=> 23 (that's an an oh, not a zero), so in real life you'd want to confirm that either 'Stop' or the string representation of a number had been typed.
This is how I would do this preferring to use loop do end syntax with a break when it should. Also added a bit more text so user knows what's happening.
total_user_input = []
puts 'Give me a number or "stop" to end: '
loop do
user_input = gets.chomp
total_user_input << user_input.to_i
puts "Give me a number: "
break if user_input.downcase == "stop"
end
puts "Total entered: #{total_user_input.inject(&:+)}" unless total_user_input.empty?
puts 'goodbye!'
Note these few things:
get.chomp.to_i will convert every input to integer. ("stop" or any non integer string will be 0)
Arrangement of the flow is quite messy.
total_user_input = []
puts "Give me a number: "
while user_input = gets.chomp.strip
total_user_input.push(user_input.to_i)
sum = 0
total_user_input.each { |num|
sum += num
}
puts sum
if user_input == "stop"
break
end
end
Hope you understand this.

Loop error for multiple conditions

I have this loop:
puts "Welcome to the Loop Practice Problems"
puts " Write a number between 1 and 10, but not 5 or else...."
ans = gets.chomp!
if ans < 1
puts "Tf bruh bruh"
elsif ans > 10
puts "Now you just playin"
elsif x == 5
print "You wildin B"
else
puts "Fosho that's all I require"
end
It doesn't run properly, and I'm trying to understand why. If you can help me with this, I'd appreciate it.
If you know a good site for practice problems, I'd love to try it. I checked out Coderbyte and Code Kata, but the way they're set up doesn't look right, and they don't have questions to solve for fundamentals.
The issue here is that you're not converting ans to a number, but you're comparing it to one. ans is going to be a string.
In Ruby, when you compare a number to a string, Ruby says that the two aren't equal:
"1" == 1
=> false
You can reproduce the problem with this code:
puts "Welcome to the Loop Practice Problems"
puts " Write a number between 1 and 10, but not 5 or else...."
ans=gets.chomp!
p ans
The p method will output an "inspected" version of that object, (it's the same as doing puts ans.inspect). This will show it wrapped in quotes, which indicates that it's a string.
You probably want to do this:
ans = gets.chomp!.to_i
The to_i method here will convert the number to an integer, and then your comparisons will work correctly.
You have to convert input string type object into integer type
ans = gets.chomp!.to_i #input string convert into integer.
if ans < 1
puts "Tf bruh bruh"
elsif ans > 10
puts "Now you just playin"
elsif x == 5
print "You wildin B"
else
puts "Fosho that's all I require"
end

Ruby code efficiency

Is there a way to make this code shorter and simpler?
loop do
if possibleSet.split(" ").map(&:to_i).any? {|e| (e<0 || e>12)}
print "Please enter valid numbers (between 1 and 12): "
possibleSet = gets
errorinput = false
else
errorinput = true
end
break if errorinput
end
Refactored a bit :)
loop do
print "Please enter valid numbers (between 1 and 12): "
possibleSet = gets.chomp
break unless possibleSet.split(" ").map(&:to_i).any? {|e| (e<0 || e>12)}
end
The code below will check input for correctness:
input = loop do
print "Please enter valid numbers (between 1 and 12): "
# ⇓⇓⇓ as many spaces as user wants
input = gets.chomp.split(/\s+/).map(&:to_i) rescue []
break input unless input.empty? || input.any? { |i| !(0..12).include? i }
end
This parses the user input in an array (not exactly the same behavior, but I hope it is cleaner and you can work from there)
set = []
until set.all? {|i| (1..11).include?(i) } && !set.empty? do
set = gets.split(' ').map(&:to_i)
end

Read data from STDIN specific number of times

I am writing a code that is supposed to read from STDIN exactly n number of times.So lets say 3 times.What is the best way to do that ?
I tried this
counter = 0
while sentence = gets.chomp && counter < 3 do
...
counter += 1
end
but for some strange reason, sentence variable inside loop is Boolean ?
You can do as below:
n.times { sentence = gets.chomp }
or
n.times do
sentence = gets.chomp
# your code here
end
Operator precedence. The line:
while sentence = gets.chomp && counter < 3 do
Is being interpretted as
while sentence = ( gets.chomp && counter < 3 ) do
So, you could do this:
while ( sentence = gets.chomp ) && counter < 3 do
That explains why you got true or false values into sentence, and the third option should fix this, so your code is very close to working. However, it is probably more usual in Ruby to see solutions like Babai's

Resources