How do you add to a Ruby array based on users input? - ruby

I am asking the user to input a number and based on that number I want to add certain players to my game.
class Player
def players_playing
players = []
puts('How many players are playing?')
players_amount = gets.chomp
for i in range(players_amount)
puts ('What is the players name')
name = gets.chomp
players.push(name)
end
end
end
So if they enter 3. Then the code should loop through 3 times and ask the user for names. e.g.
What is the players name? Rich
What is the players name? Tom
What is the players name? Charles
Then it would have players = ['Rich', 'Tom', 'Charles']
any ideas why my code is not correct? ( i figure it is to do with the range part maybe)

There are some mistakes in your code:
At first you are asking for a number, however players_amount is a string. You should convert it using the to_i method.
Then, for iterating over a range, there are several ways of doing it in Ruby, but there is no keyword range as in Python. For iterating over a range (that is, an interval), use:
# Exclusive:
(0...3).each do |i|
puts i
end
# 0
# 1
# 2
# Inclusive:
(0..3).each do |i|
puts i
end
# 0
# 1
# 2
# 3
So, instead of your for loop, just write (0...players_amount).each do.
With those modifications, the program has the expected behaviour. However, if you want the name to appear on the same line of the question, use print instead of puts because puts adds automatically a line break at the end of the string.

I would add a complement to T. Claverie's answer. In this case I guess you only need to iterate a certain number of times and do nothing with the iteration index. That way, I would replace the for loop in your code with the following:
players_amount.times do
puts ('What is the players name')
name = gets.chomp
players.push(name)
end
Hope it helps.

Related

Can someone explain me what this line of ruby code does?

I'm a beginner in ruby and found this example on the Odin project about the reduce method, but in line 7 it puts the result variable again, can someone explain me What's the use of putting the result variable?
Thank you in advance!
votes = ["Bob's Dirty Burger Shack", "St. Mark's Bistro", "Bob's Dirty Burger Shack"]
votes.reduce(Hash.new(0)) do |result, vote|
puts "result is #{result} and votes is #{vote}"
puts "This is result [vote]: #{result[vote]}"
result[vote] += 1
result #this part I don't understand
end
They're using the reduce(initial_operand) {|memo, operand| ... } version.
memo is a thing to collect the result. The block has to pass that along to the next iteration. For example, if you wanted to sum up a list of numbers...
(1..4).inject do |sum, element|
p "Running sum: #{sum}; element: #{element}"
# This is passed along to the next iteration as sum.
sum + element
end
Instead of using the default memo, which would be the first element, they've used Hash.new(0) to count the votes. Each iteration counts the votes, and then passes the result has to the next iteration.
# result starts as Hash.new(0)
votes.reduce(Hash.new(0)) do |result, vote|
# This prints the state of the voting and the current choice being tallied.
puts "result is #{result} and votes is #{vote}"
# This displays how many votes there are for this choice at this point
# before this choice is tallied.
puts "This is result [vote]: #{result[vote]}"
# This adds the vote to the tally.
result[vote] += 1
# This passes along the tally to the next iteration.
result
end
If you don't want to print on each iteration, use tally instead.
result = votes.tally

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.

Generate largest number of 10 inputs

New to scripting here. Basically, I am needing to write a program to accept 10 input numbers and return the largest in the list.
I have this code, but obviously it is not running:
class Generator
def getNumbers
number = Array.new
puts "To begin, You will need to enter your numbers."
print "Press Enter to continue."
Console_Screen.pause
10.times do
print "\nPlease enter any number: "
input = STDIN.gets
input.chop!
list.push
return list
end
list.push(number)
print list.max
end
end
Console_Screen.new
Find = Generator.new
end
Can anyone help me with what I coded incorrectly?
There are many problems with your code. Among them I may point:
1) You created an array named number to store your numbers and then tried to push them to another variable named list;
2) As #tadman pointed, you used a return inside a times block and this makes the block to be executed only once;
3) You never invoked getNumbers to make your process really happen!
This code would do what you need:
class Generator
def get_numbers
numbers = Array.new
puts "To begin, You will need to enter your numbers."
puts
10.times do
print "\nPlease enter any number: "
input = STDIN.gets
input.chop!
numbers.push(input.to_i)
end
print numbers.max
end
end
Find = Generator.new
Find.get_numbers
Notice that I changed the name of your method from getNumbers to get_numbers, which is much more Ruby-like.
Notice that I also changed the name of your array from number to numbers, 'cause it will store numbers, not a single number. Naming your varables correctly may help you to think correctly about your problem. It also helps when it comes for other people reading your program. Even you, six months later, will have problems to understand your own code if you don't name things correctly an comment you code well.
By the way, I also pushed the numbers to numbers as integer, using #to_i. This will make the numbers be compared as numbers, not as strings. If you researsh a bit you'll find out this could be a bit different. If someone enters 0300 as a number, it will be considered to be smaller then 200 as string, but when converted to integers, they will be in the correct order.
Consider this approach perhaps:
#script.rb
nums = []
10.times do |c|
puts "enter number #{c+1}"
nums << gets.to_i
end
puts "max number is #{nums.max}"
Example
$ ruby script.rb
enter number 1
#5
enter number 2
#3
enter number 3
#66
enter number 4
#4
enter number 5
#3
enter number 6
#2
enter number 7
#1
enter number 8
#6
enter number 9
#9
enter number 10
#0
#max number is 66
I had the same assignment and this is what I ended up creating. (I had to get a little more involved with input control and I'm sure there's easier ways of doing this. Also had to utilize the variables as part of the grade. I assume to prevent me from ripping off the code above.)
class Screen
def cls
puts ("\n" * 25)
puts "\a"
end
def pause
STDIN.gets
end
end
Console_Screen = Screen.new
num = [] #array to store user input
$counter = 1
loop do
puts "Please enter number " + $counter.to_s + " of a series of 10 numbers in order to determine the largest."
# Console_Screen.pause
loop do
print "Enter Number Here:"
number = gets.chomp
num << number.to_i if number =~ /[0-9]/ #only writes to the array if it's a number
break if number =~ /[0-9]/ #only allow numbers
end
$counter += 1
break if $counter == 11
end
puts "Press Enter to have your numbers sorted and the largest presented to you."
Console_Screen.pause
largest = num.max
puts "This is your largest number: " + largest.to_s
Console_Screen.pause

Having difficulty checking each individual users' hash of randomly generated numbers in an array, instead checks all

I am creating a bingo game for the ruby console in which, numbers are randomly put into a hash for each user, comprising of the bingo board, and each user's hash is put into an array of all "bingo boards". I am having trouble with checking the right answers against these hashes/boards within the array, because it checks the winning columns against all users instead of each individual users board (hash). The first three information/methods below are used as backup information, whereas the bottom two methods are where the problem are. How do I switch the methods to check the winning combinations against one hash in the bingo cards array, and if nothing restart over on the next hash instead of combining from different cards?
The winning combinations are below
#here are the winning combinations
#columns = [
[:a1,:a2,:a3,:a4,:a5],
[:b1,:b2,:b3,:b4,:b5],
[:c1,:c2,:c3,:c4,:c5],
[:d1,:d2,:d3,:d4,:d5],
[:e1,:e2,:e3,:e4,:e5],
[:a1,:b1,:c1,:d1,:e1],
[:a2,:b2,:c2,:d2,:e2],
[:a3,:b3,:c3,:d3,:e3],
[:a4,:b4,:c4,:d4,:e4],
[:a5,:b5,:c5,:d5,:e5],
[:a1,:b2,:c3,:d4,:e5],
[:e1,:d2,:c3,:b4,:a5]
]
This method starts a game, and fills up a hash of random bingo numbers into an array for each user. The array is called #bingo_cards
def start_game(user_goes_first)
#bingo slots
#places = Hash.new { |hash, key| hash[key] = " " }
#places_keys = [
:a1,:a2,:a3,:a4,:a5,
:b1,:b2,:b3,:b4,:b5,
:c1,:c2,:c3,:c4,:c5,
:d1,:d2,:d3,:d4,:d5,
:e1,:e2,:e3,:e4,:e5
]
#bingo_cards = []
fill_cards(#users_count)
user_turn
end
this method takes the randomly generated numbers and turns them into bingo cards (hash) and then puts them in array (#bingo_cards)
def fill_cards(number)
number.times do
#places_keys.each_with_index do |n,i|
#places[n] = pick_number(i)
end
#bingo_cards << #places.dup
end
end
This is where the number is picked each time - #user = 'X', so it replaces the number with X
def user_turn
put_line
puts "\n RUBY BINGO".purple
draw_game
print "\n Please type 'go' or type 'exit' to quit: ".neon
STDOUT.flush
input = gets.chomp.downcase.to_str
put_bar
if input.length == 2
#random = rand(1..75)
puts #random
#bingo_cards.each do |bingo|
#places_keys.each do |key|
bingo[key] = #user if bingo[key] == #random
end
end
put_line
check_game(#user)
else
wrong_input unless input == :exit
end
end
Here is where I am having the problem. It does properly count the X's, but for every user. Meaning it only works properly if one person is playing. If two people are playing it if a user has two X's (meaning the number came up) in a row in the the top left, and the other user has three x's in a row in the top right it ends the game - it should only end when a user has 5 X's, aka the random number is picked 5 times on their board.
def times_in_column arr, item
#count the number of X's in the column to see if 5 in a row
times = 0
#bingo_cards.each do |bingo|
arr.each do |i|
times += 1 if bingo[i] == item
end
end
times
end
This method is responsible for checking the game, alongside the method above.
def check_game(next_turn)
game_over = nil
#bingo_cards.each do |bingo|
#columns.each do |column|
# see if user has won
if times_in_column(column, #user) == 5
put_line
draw_game
put_line
puts ""
puts " Game Over -- WINS!!!\n".blue
game_over = true
#user_score += 1
ask_to_play_again(true)
end
end
end
unless game_over
user_turn
end
end
Here is a gist for any additional needed information - I commented everything throughout.
Here's a problem:
def times_in_column arr, item
#count the number of X's in the column to see if 5 in a row
times = 0
#bingo_cards.each do |bingo|
arr.each do |i|
times += 1 if bingo[i] == item
end
end
times
end
Consider what happens in the code above. times_in_column is called with an array of keys, say the one across the top [a1:, a2:, a3:, a4:, a5:]. times is set to 0. For each bingo card in play, each key in the array is examined on a card, and if an X is found, times is increased. Notice that as the bingo card loop (#bingo_cards.each do |bingo|) progresses, times is never reset to 0, so the count increases each time an X is found on any bingo card in the loop.
To fix this, I'd suggest moving the bingo card loop out of the times_in_column method, and call times_in_column on each individual bingo card, then check the return value.
Actually, I'd suggest rewriting this method to take a single bingo card and check all possible winning patterns (in #columns), and for each winning pattern, start the times count at 0, and remember if any of the winning patterns ever found 5 Xs, and return true if this is so, false otherwise.
You're seeing the results you're seeing because of two factors:
You're using the same value of #user on all the bingo cards. In
fact, #user never changes.
You're adding up the instances of #user across all bingo cards for each column
If you know which cards a user owns, there is no need for user-specific marks on the cards, as you can just check the card that the user owns. Similarly, if you use unique marks for each user, you can count across all cards provide that each user only has one card. If a user can play more than one card, as is common in bingo, then it's still going to be important to look at the columns for each card separately.
BTW, there are lots of quality issues with this code, such as recursively calling user_turn for each move. I would strongly encourage you to subject this to a code review.

Program to take input from command line into an array and find the biggest among them

I am new to Ruby and just can't figure out how you take input for an array from a user and display it.If anyone could clear that I can add my logic to find the biggest number.
#!/usr/bin/ruby
puts "Enter the size of the array"
n = gets.chomp.to_i
puts "enter the array elements"
variable1=Array.new(n)
for i in (0..n)
variable1[i]=gets.chomp.to_i
end
for i in (0..n)
puts variable1
end
How about capturing the array in one line?
#!/usr/bin/ruby
puts "Enter a list of numbers"
list = gets # Input something like "1 2 3 4" or "3, 5, 6, 1"
max = list.split.map(&:to_i).max
puts "The largest number is: #{max}"
You are doing it ok. But try this little change
#!/usr/bin/ruby
puts "Enter the size of the array"
n = (gets.chomp.to_i - 1)
puts "enter the array elements"
variable1=Array.new(n)
for i in (0..n)
variable1[i]=gets.chomp.to_i
end
puts variable1
or for undefined number of values here is one way
#!/usr/bin/ruby
puts "enter the array elements (type 'done' to get out)"
input = gets.chomp
arr = []
while input != 'done'
arr << input.to_i
input = gets.chomp
end
puts arr
I believe that this is a little bit more elegant solution.
puts "Please enter numbers separated by spaces:"
s = gets
a = s.split(" ")
#Displays array
puts a
#Displays max element
puts a.max
First you collect the series of numbers from the user, then you use a split method on the string, which converts it to the array. If you want to use some other separator, like "," than you can write s.split(","). After that you can use your logic to find the biggest number or you could just use max method.
Some feedback:
chomp.to_i is a bit redundant, since the latter will also remove newlines.
for x in y is not commonly seen in idiomatic Ruby code. It basically behaves like each with slightly different scoping rules and probably should have been removed from the language a while ago.
Ruby arrays are dynamic, so no need to preinitialize them. Something like (1..n).map { gets.to_i } would also produce the array you need.
Displaying it can then be done like this: array.each { |n| puts n }
Alternatively you can use the strip approach outlined before, take the numbers as command line arguments in ARGV or pipe into your program using ARGF.

Resources