How to solve Ruby Wizardry "Staying in the loop" example program? - arrays

The book Ruby Wizardry Chapter 4 includes the following sample program
we_wanna_ride = true
stops = ["East Bumpspark", "Endertromb Avenue", "New Mixico", "Mal Abochny"]
while we_wanna_ride
print "Where ya headin', friend?"
destination = gets.chomp
if stops.include? destination
puts "I know how to get to #{destination}! Here's the station list:"
stops.each do |stop|
puts stop
break if stop == destination
end
else
puts "Sorry, we don't stop at that station. Maybe another time!"
we_wanna_ride = false
end
end
It then goes on to pose a few additional challenges:
"What if a passenger is going the other way on the train (for instance, from Mal Abochny to East Bumpspark)? How could you update your program to work in both directions? Even trickier, what if the train route is a big circle (meaning if a passenger goes from East Bumpspark to Mal Abochny, the next stop after Mal Abochny should be East Bumpspark again)? How could you update your program to print out the right list of train stops if a passenger wants to go all the way around the circle?"
Does anybody have any ideas how to proceed here ? I'm a beginning programmer so any help would be greatly appreciated. Here's my progress so far. I figured I would get a departure from the user and then use to.i to get the input into an integer. I could then use the integer value to compare to the index position in the array. If the rider wants to go in the opposite direction I could use something like stops.each.reverse to print out the array items in reverse order.
we_wanna_ride = true
stops = ["East Bumpspark(1)", "Endertromb Avenue(2)", "New Mixico(3)", "Mal Abochny(4)"]
puts "#{stops}"
while we_wanna_ride
print "Select a destination number"
destination = gets.chomp.to_i
print "Select a departure number"
departure = gets.chomp.to_i
if departure <= destination
stops.each do |stop|
puts stop
break if stop == destination
end
else puts "Sorry"
we_wanna_ride = false
end
end

Here is how I solved this challenge. It works but is rather lengthy. More advanced ruby coders may be able to provide a shorter solution:
we_wanna_ride = true
stops = ["East Bumpspark", "Endertromb Avenue", "New Mixico", "Mal Abochny"]
while we_wanna_ride
print "Where do you wish to depart from?: "
depart = gets.chomp.split.map(&:capitalize).join(' ')
depart_index = stops.index(depart)
# puts depart_index
print "Where ya headin' friend?: "
destination = gets.chomp.split.map(&:capitalize).join(' ')
destination_index = stops.index(destination)
# puts destination_index
index_diff1 = depart_index - destination_index
index_diff2 = destination_index - depart_index
if stops.include? destination && depart
puts "\nI know how to get to #{destination}! Here's the station list:"
if destination_index > depart_index && index_diff2 < 3
stops[depart_index..-1].each do |stop|
puts stop
break if stop == destination
end
we_wanna_ride = false
elsif destination_index > depart_index && index_diff2 >= 3
dubstops = stops.concat(stops)
dubstops[0..depart_index+4].reverse_each do |stop|
puts stop
break if stop == destination
end
we_wanna_ride = false
elsif destination_index < depart_index && index_diff1 < 3
stops[0..depart_index].reverse_each do |stop|
puts stop
break if stop == destination
end
we_wanna_ride = false
elsif destination_index < depart_index && index_diff1 >= 3
dubstops = stops.concat(stops)
dubstops[depart_index..-1].each do |stop|
puts stop
break if stop == destination
end
we_wanna_ride = false
end
else
puts "Sorry, we don't service that station. Maybe another time!"
we_wanna_ride = false
end
end

Related

I want to list "user inputs" with using method

So i create a new class and i have a lot of objects in this class such as name, surname age etc.
But i am geting the same error everytime. And also i do not now how to list my arrays with using method.
Error: no implicit conversion of Array into String
def main
patients = []
puts "What do you want to do \nadd \nlist \nexit"
process = gets.chomp
if process == "add"
puts "Please enter patient's name"
patient1 = Patient_Covid_19.new()
patient1.Name = gets.chomp.to_s
patient1.Name << patients #error line
elsif process == "list"
#And i want to print the arrays(patients, ages, surnames etc.) in here but using a method.
elsif process == "exit"
puts "Have a nice day"
else
puts "Please enter add, list or exit"
main
end
end
main
Edit: It was small syntax mistake(error line). But i still need help for the list process.
You probably meant to do patients << patient1.Name.
You can loop over and print out attributes as follows:
patients.each do |patient|
puts "Name: #{patient.Name}, etc"
end
class Patient_Covid_19
attr_accessor :Ssn, :Name, :Surname, :Sex, :Age
end
def main
patients = []
puts "What do you want to do \nadd \nlist \nexit"
process = gets.chomp
if process == "add"
puts "Please enter patient's name"
patient1 = Patient_Covid_19.new()
patient1.Name = gets.chomp.to_s
patients << patient1.Name
main
elsif process == "list"
elsif process == "exit"
puts "Have a nice day"
else
puts "Please enter add, list or exit"
main
end
end
main
This is my code. When the user writes Add, he will enter the patient's information from the console and this information will be added to an array. When the user writes list, he/she will be able to see the information of the patients he has written before. I want to do the listing with a method.

Ruby, how can i compare a string with a specific element of array?

I create an array from a text file which contains the english irregular verbs. I want the code to ask me the verbs in random order letting me proceed only if I respond correctly. I need to compare a string with an element of array. I wrote this:
a = []
File.open('documents/programmi_test/verbi.txt') do |f|
f.lines.each do |line|
a <<line.split.map(&:to_s)
end
end
puts ''
b = rand(3)
puts a[b][0]
puts 'infinitive'
infinitive = gets.chomp
if infinitive = a[b][1] #--> write like this, I receive alway "true"
puts 'simple past'
else
puts 'retry'
end
pastsimple = gets.chomp
if pastsimple == a[b][2] #--> write like this, I receive alway "false"
puts 'past participle'
else
puts 'retry'
end
pastpart = gets.chomp
if pastpart == a[b][3]
puts 'compliments'
else
puts 'oh, no'
end
can somebody help me?
if infinitive = a[b][1] is assigning to inifinitive the value of a[b][1], unlike pastsimple == a[b][2] that's a comparation between both values.
You could try replacing the = for ==.
a = []
File.open('documents/programmi_test/verbi.txt') do |file|
file.lines.each do |line|
a << line.split.map(&:to_s)
end
end
puts ''
b = rand(3)
puts a[b][0]
puts 'infinitive'
infinitive = gets.chomp
puts infinitive == a[b][1] ? 'simple past' : 'retry'
pastsimple = gets.chomp
puts pastsimple == a[b][2] ? 'past participle' : 'retry'
pastpart = gets.chomp
puts pastpart == a[b][3] ? 'compliments' : 'oh, no'

How do I get the elsif for #correct_tries to work properly?

My first hangman game from scratch is almost done with the real basic stuff. I just need a counter for when a player gets it right to work correctly. I haven't figured out a good way to do it without deleting everything and starting over.
the #correct_tries counts correctly then in the elsif compare the numerical value to the number of elements in the given word that were answered correctly.
It'll keep counting when it should have stopped when #correct_tries was compared to the number when .inspect happens on the array. But it keeps counting.
class Hangman
Profanity = ['cobol','snit','crap','court']
Adjective = ['foul','repugnant','swift','fast']
Noun = ['king','queen','prince','princess']
def self.start_game
print "Welcome to Hangman V1 by Clueless! Please select which category of words do you want to use: \n Profanity, Adjective, Noun "
#selection = gets.chomp.downcase
case
when #selection == 'profanity'
puts 'You have selected profanity! '
hangman_word_selection
when #selection == 'adjective'
puts 'You have selected Adjectives! '
hangman_word_selection
when #selection == 'noun'
puts 'You have selected nouns! '
hangman_word_selection
end
end
def self.hangman_word_selection
if #selection == 'profanity'
hangman_word = Profanity.sample
hangman_word_setup(hangman_word)
#puts '_ ' * hangman_word.size
elsif #selection == 'adjective'
hangman_word = Adjective.sample
hangman_word_setup(hangman_word)
elsif
#selection == 'noun'
hangman_word = Noun.sample
hangman_word_setup(hangman_word)
end
end
def self.hangman_word_setup(hangman_word)
hangman_word_array = hangman_word.chars.to_a
#hangman_end = false
#while(#hangman_end == false)
#puts "*" * 40
#puts
#puts
puts 'You have five tries to get the word correct. If you can guess the whole word do so but you only have one try. Or just guess letter by letter.'
p hangman_word_array
#total_tries = 0
#correct_tries = 0
game_check = true
while game_check == true
first_try = gets.chomp.downcase
if(first_try == hangman_word_array[0] || first_try == hangman_word_array[1] || first_try == hangman_word_array[2] || first_try == hangman_word_array[3] || first_try == hangman_word_array[4])
puts 'Check'
#correct_tries += 1
p #correct_tries
#correct tries equal to the number of chars in the given word check it.
puts 'You have gotten it correct!'
elsif(first_try == hangman_word)
puts 'You have completed the word! Congratulations you win!'
hangman_win
break
elsif(first_try != hangman_word_array)
puts 'Wrong.'
#total_tries += 1
p #total_tries
#puts "*" * 40
elsif(#correct_tries == hangman_word_array.inspect)
puts 'done.'
break
end
end
end
def self.hangman_loss
puts ' +---+-
| |
| 0
| |\\
| /\\
-+----------'
puts 'You lose!'
end
def self.hangman_win
puts 'NEED HANGMAN VICTORY POSE HERE.'
end
start_game
end
The elsif condition
elsif(#correct_tries == hangman_word_array.inspect) will never be true. #correct_tries is a numerical value and hangman_word_array.inspect will return the array of words for hangman in a string format (e.g. hangman_word_array = ['a', 'b', 'c'] then hangman_word_array.inspect will be "[\"a\", \"b\", \"c\"]".

Adding an Array to an Array Ruby

Im trying to learn how to add arrays into arrays, I have the following code:
puts "would you like to save a data set"
response = gets.chomp
if response == "y"
puts "create a new dataset?"
create_data_set = gets.chomp
while create_data_set == "y"
puts "what do you want to name the data set?"
dataset = gets.chomp
dataset = Array.new
puts 'would you like to add some grades to the array?'
store_grades_response = gets.chomp
while store_grades_response == "y"
puts 'enter grade ->'
grade = gets.chomp.to_i
dataset << grade
puts 'would you like to store another grade?'
store_grades_response = gets.chomp
end
all_data_sets = Array.new
all_data_sets.push(dataset)
puts "would you like to create a new data set?"
create_data_set = gets.chomp
end
end
puts all_data_sets
Im basically asking a user to enter a array name which should create an array, add values to the array and if required by the user add some more arrays and values to it. At last the array should be added to an array. And then I'm trying to display all the arrays.
The code works fine, I'm looping through everything but when it puts all_data_sets It only shows the last array that was created? i would like to store all the arrays within the one array called all_data_sets
The problem is that you are creating a new array all_data_sets at the end of each loop. One solution will be to have it before the loop.
puts "would you like to save a data set"
response = gets.chomp
all_data_sets = []
if response == "y"
puts "create a new dataset?"
create_data_set = gets.chomp
while create_data_set == "y"
puts "what do you want to name the data set?"
dataset = gets.chomp
dataset = Array.new
puts 'would you like to add some grades to the array?'
store_grades_response = gets.chomp
while store_grades_response == "y"
puts 'enter grade ->'
grade = gets.chomp.to_i
dataset << grade
puts 'would you like to store another grade?'
store_grades_response = gets.chomp
end
all_data_sets << dataset
puts "would you like to create a new data set?"
create_data_set = gets.chomp
end
end
puts all_data_sets
This way, you keep pushing the datasets into the all_data_sets after each loop.
I hope this is explanatory enough.
Fix
Its because your create new_data_sets array each time you do the loop, declare it outside enclosing while loop
Code
def main
mainDataSet = [] # All datasets
dataSetNames = [] # Incase you want to store data set names
response = getInput("Would you like to save a data set")
if(response == "y")
choice = getInput("Create a new dataset?")
while choice == "y"
dataset = getInput("What do you want to name the data set?")
dataSetNames << dataset
dataset = []
choice_2 = getInput("would you like to add some grades to the array?")
while choice_2== "y"
grade = getInput("Enter grade")
dataset << grade
choice_2 = getInput("Store another grade?")
end
mainDataSet << dataset
choice = getInput("Create a new data set?")
end
end
puts mainDataSet
puts dataSetNames
end
def getInput(message)
puts "#{message} -> "
gets.chomp
end
Hope this helps.
you can concat, prepend or append arrays just like this
dataset.concat all_dataset
dataset + all_dataset
Concat documentation
prepend or append
dataset.push(*all_dataset)
all_dataset.unshift(*dataset)
Array stuffs
Also you can do slice and whole bunch of stuffs check at the ruby docs link

Class-Array Interaction Ruby

I'm trying to set up a program to help me take care of grading for students in a class. I've set it up to make a class of student then to read in from the file (something I'm not very familiar with in Ruby) via an array. My programming experience is in java so if there are errors that can be explained by that I apologize. Thank you in advance for your help.
class Student
def initialize(str_LastName, str_FirstName, arr_Score)
#str_LastName = str_LastName
#str_FirstName = str_FirstName
#arr_Score = arr_Score
str_Grade = ""
int_OutOf = 415
end
def get_LastName
str_LastName
end
def get_FirstName
str_FirstName
end
def get_Grade
str_Grade
end
def set_TotalScore()
sum = 0
arr_Score.each do |item|
sum += item
end
arr_Score[12] = sum
end
def set_Grade
if arr_Score[12]/int_OutOf >= 0.9
str_Grade = "A"
elsif arr_Score[12]/int_OutOf >= 0.8
str_Grade = "B"
elsif arr_Score[12]/int_OutOf >= 0.7
str_Grade = "C"
elsif arr_Score[12]/int_OutOf >= 0.6
str_Grade = "D"
else
str_Grade = "F"
end
end
end
def main
file_name = "Grades"
arr_students = Array.new(31)
arr_scores = Array.new(12)
int_i = 0
file_io = open(file_name).readlines.each do |line|
array = line.split(",").map(&:strip)
student = Student.new(array[0],array[1],array[2..-2]) #the final element in the array is for the final score
arr_students[int_i] = student
puts "read #{arr_students[int_i]}"
end
file_name = "Graded"
file_io = open(file_name,"a+")
arr_students.each do |student|
set_TotalScore
set_Grade
file.io_write(student)
puts "write #{student}"
end
end
main if __FILE__==$0
Here is my run at it. I tried to stay true in general to the original intent of your code while introducing more Rubyish ways of doing things.
class Student
def initialize(firstname, lastname, *scores)
#firstname, #lastname, #scores = firstname, lastname, scores
end
def total_score
#scores.map(&:to_i).inject(:+)
end
def grade
raise "TOO HIGH!" if total_score > MAX_SCORE
case total_score / MAX_SCORE
when 0.9..1.0; "A"
when 0.8...0.9; "B"
when 0.7...0.8; "C"
when 0.6...0.7; "D"
else "F"
end
end
def to_s
"#{#lastname}, #{#firstname}: #{total_score}, #{grade}"
end
end
MAX_SCORE = 415.0
DATA.each_line do |line|
arr = line.split(",").map(&:strip)
student = Student.new *arr
puts student
end
__END__
Herb,Goldberg,22,99,44,22,88,88
Mark,Sullivan,77,88,88,44,33
You can read and write to files like this(not tested):
outfile = File.open("Graded", "a+")
File.open("Grades").each_line do |line|
...
outfile.puts student
end
outfile.close
We can not easily reproduce your code because you open a file called "Grades" and we do not have or know of its content.
You should also add some code to first check whether your file exists, before continuing - right now your script exits with a Errno::ENOENT.
I would also suggest putting the logic in main into your class instead - let your class handle everything.
In the part:
if __FILE__ == $PROGRAM_NAME
end
You can then simply initialize your class with a simple call such as:
Foobar.new(ARGV)
You described the "Grades" file but I did not understand what you wrote - it would be easier if you could link in to a sample, like via a pastie or gist, then link it in; and to also say what the part is that is not working, which is also unclear.
The style issues are secondary, I consider your code ok - the other poster here does not.
You should go through codecademy to get your ruby syntax down.
To access your initialized instance variables (#str_LastName (which should be #last_name), etc) you need to use "attr_reader :str_LastName", preferably at the top of the class. That'll definite you getter (setter is attr_writer, both is attr_accessor).
You can also do a sum on an array like this: [1,4,6,7].inject(:+).
Does Java not allow case statements? You should use that in set_grade. You also don't need to initialize str_Grade. In set grade, you could do #grade_letter ||= "A", and then calling set_grade will return that value on each call.
I didn't look through your main method. It's ugly though. Ruby methods probably shouldn't be more than 5 lines long.

Resources