What is wrong with my if statements? - ruby

Working in Ruby, I'm trying to make it so when I enter a line of input it'll read it and match it with a few if statements.
input_stream = $stdin
input_stream.each_line do |line|
puts line
if line == "a"
puts "test 1"
end
if line == "b"
puts "test 2"
end
end
But when I run it, and enter in "a" or "b", this is the output
a
a
b
b
It recognizes that I entered a and b, and prints it back to me, but the if statements don't function as expected. What is the problem here?

Ruby maintains the newline when using each_line. The simplest solution is to drop it with chomp.
input_stream = $stdin
input_stream.each_line do |line|
line.chomp! # The new helpful line
puts line
if line == "a"
puts "test 1"
end
if line == "b"
puts "test 2"
end
end

Because line has \n character at the end if you write this it will work:
input_stream = $stdin
input_stream.each_line do |line|
puts line
if line.chomp == "a"
puts "test 1"
end
if line.chomp == "b"
puts "test 2"
end
end

Related

Using STDIN in ruby , how to print out the multiline comments without REGEX

Given STDIN with the following:
=begin This is a multiline comment and con spwan
as many lines as you like. But =begin and =end
should come in the first line only.
=end
Without using regex , how do you print the in between line as well?
(side question, is ARGF expensive since it has to wait for all the input?)
this is a start:
starting = "=begin"
ending = "=end"
ARGF.each do | line |
comments = false
if line.include?(starting) && !line.include?(ending)
incomments = true
end
if !line.include?(starting) && line.include?(ending)
puts line
incomments = false
end
if incomments == true
puts line.lstrip
end
end
expected output is:
This is a multiline comment and con spwan
as many lines as you like. But =begin and =end
should come in the first line only.
The generic answer that works for any number of nested levels:
input = "..." # could be taken from ARGF
input.
split($/).
each_with_object(result: Hash.new {|h, k| h[k] = []}, level: 0) do |line, acc|
acc[:level] += 1 if line.include?('=begin')
(1..acc[:level]).each do |level|
acc[:result]["Level: #{level}"] << line
end
acc[:level] -= 1 if line.include?('=end');
end[:result]
#⇒ {
# "Level: 1" => [
# "=begin This is a multiline comment and con spwan as many lines as you like.",
# "But =begin and =end should come in the first line only.",
# "=end"
# ],
# "Level: 2" => [
# "But =begin and =end should come in the first line only."
# ]
# }
If you need the comments on top level, just get the value for "Level: 1" key and join it with $/ delimiter.

Ruby Hangman game, does not work when I enter the full word but only when I enter one letter

Run my code your ruby interpretor, to see my code. Afterwards, try to guess the full word. The program will tell you that your guess was correct but it doesn't end the game if you guess the entire word instead of each letter one by one.
I also want to add a Dictionary to my code to be able to play against the computer instead of with myself or a friend!
def clear_screen
return system('cls') if Gem.win_platform?
system('clear')
end
loop do
incorrect_guesses = 0
puts ''
puts 'Welcome to Hangman, Win or lose your life!'
puts ''
puts 'Choose Category: It can be anything you desire!'
player1_category = gets.chomp
puts ''
puts 'Player 1, Please enter your desired word'
secret_word = gets.chomp.downcase
clear_screen
correct_guess = ['-'] * secret_word.length
clear_screen
puts "The category is: #{player1_category}"
puts 'Player 2, Please enter your guess'
loop do
puts '_ ' * secret_word.length
player2_guess = gets.chomp.downcase
clear_screen
if secret_word.include? player2_guess
secret_word.each_char.with_index do |letter, i|
next unless letter == player2_guess
correct_guess[i] = letter
end
puts "The category is: #{player1_category}"
puts ''
print 'Guess the word: '
print correct_guess.join('')
puts ''
puts 'Correct. Keep trying!!'
puts ''
else
puts "The category is: #{player1_category}"
puts ''
print 'Guess the word: '
print correct_guess.join('')
puts ''
puts "The word doesn't contain that letter '#{player2_guess.upcase}'"
puts ''
incorrect_guesses += 1
end
puts "Incorrect Guesses: #{incorrect_guesses}"
puts ''
if incorrect_guesses == 6
puts ''
puts '|---+---+- '
puts '| |'
puts '| 0'
puts '| |\\'
puts '| /\\'
puts '-+----------'
puts "The Secret Word is '#{secret_word.capitalize!}'"
puts ''
break
end
next unless secret_word == correct_guess.join('')
puts ''
puts ' (#)'
puts ' ^\\|'
puts ' |/^'
puts '____|_____'
puts ''
puts 'You Win!'
puts ''
puts "You correctly guessed the word '#{secret_word.capitalize!}'"
break
end
end
I got to work with the following change to the next unless test:
if secret_word.include? player2_guess
secret_word.each_char.with_index do |letter, i|
next unless player2_guess.include? letter
correct_guess[i] = letter
end
You were comparing the entire entry to a single character. 't' != 'test'
As for a dictionary, the answer in this link should help
Your question is not super clear, but here are a few comments / answers:
Guessing the whole word: You could wrap your current if secret_word.include? player2_guess in another if that tests the length of the input. (This assumes all words are greater than 1 letter). The if statement should test if the user_input.length > 1. If so, evaluate whether the guess is the correct word, etc.
Adding a dictionary: Easiest was would be to hardcode an array of possible word values. If you want them to correspond to a category, you could make a hash like this {'category_1' => [word, word, word], 'category_2' => [word, word, word]}. Then you could pick a random value from the hash (category) and then a random value from the corresponding array.

Command `left`, `right`, and `justify`

line_width = 40
str = 'test'
puts (str.ljust(line_width))
puts (str.rjust(line_width))
puts (str.center(line_width))
puts (str.ljust(line_width)) + (str.rjust(line_width))
Output
test
test
test
test test
Both the fourth line:
puts (str.rjust(line_width))
and the sixth line
puts (str.rjust(line_width))
have the same value 40. Why are they printed in different locations?
It's more obvious if you specify the "pad-string":
puts 'test'.ljust(40, '<')
puts 'test'.rjust(40, '>')
puts 'test'.center(40, '-')
puts 'test'.ljust(40, '<') + 'test'.rjust(40, '>')
Output:
test<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>test
------------------test------------------
test<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>test

Why don't these string expressions print the same result?

Why does this expression:
puts "abc" * 5
=> "abcabcabcabcabc"
not equal this expression?
5.times do puts "abc"
abc
abc
abc
abc
abc
=> 5
Could you please explain why they don't print the same result?
The first writes the string "abc" concatenated to itself five times:
"abc"*5 = "abc"+"abc"+"abc"+"abc"+"abc" = "abcabcabcabcabc"
The second piece of code writes "abc" using the puts function 5 times. The puts function writes a newline character after each message, meaning that it writes "abc\n" 5 times.
5.times do puts "abc"
turns to
puts "abc" ->also jumps to the next line
puts "abc" ->also jumps to the next line
puts "abc" ->also jumps to the next line
puts "abc" ->also jumps to the next line
puts "abc" ->also jumps to the next line
you can replace puts with print, which doesn't add the new line at the end
5.times do print "abc"
end
abcabcabcabcabc => 5

Ruby: skips over a gets value

I have a file check and sort script. Now I wanted the user to be to choose how he/she wishes to have the final output sorted. Sadly Ruby seems to ignore the gets command. If I comment out the entire section the script finishes just fine. Please ignore the def readout. I never finished that one....
So my question is: Why does Ruby skip over the gets command.
class Product
attr_reader :id, :name, :price, :stock
def initialize(id,name,price,stock)
#id = id
#name=name
#price=price
#stock=stock
end
def readout
self.each do |product|
print product.id
print "|"
print product.name
print "|"
print product.price
print "|"
print product.stock
puts ""
end
end
end
products = []
newproducts= []
if ARGV[0] != nil
if File.exist?(ARGV[0])
File.open(ARGV[0] , "r") do |f|
f.each_line do |line|
products << line
end
end
products.each do |product|
data = product.split(",")
newproducts.push(Product.new(data[0].strip, data[1].strip, data[2].strip.to_i, data[3].strip.to_i))
end
puts "What to sort by?"
question = gets.strip
if question == "name"
newproducts.sort! {|a,b| b.name <=> a.name}
elsif question == "price"
newproducts.sort! {|a,b| b.price <=> a.price}
elsif question =="id"
newproducts.sort! {|a,b| b.id <=> a.id}
elsif question == "stock"
newproducts.sort! {|a,b| b.stock <=> a.stock}
else
puts "Wrong Answer."
end
#End of File Check
else
puts "File #{ARGV[0]} does not exist."
end
if ARGV[1] != nil
File.open(ARGV[1], "w") do |f|
newproducts.each do |product|
puts "Added #{product.name} to the file."
data = {product.id, product.name, product.price, product.stock}
f.puts(data)
end
end
#End of ARGV check.
else
puts "No output file assigned."
end
#End of master ARGV check.
else
puts "No command given."
end
The Kernel#gets method reads from ARGF not $stdin. This means that if command line arguments were given (or more accurately if ARGV is not empty) it reads from the files in ARGV. Only otherwise does it read from stdin.
To always read from stdin, use $stdin.gets instead of gets.

Resources