The following is a portion of my code. Any advice is appreciated.
def how_many_guesses?
guesses = 0
end
def guess
puts "Please type a number between 1 and a 100."
gets.chomp
end
def correct?
if guess == guess
puts "You have already guessed this number, try again!"
guess
elsif guess == random_num
you_are_correct
elsif guess > correct_num
puts "Too high!"
how_many_guesses? += 1
guess
else
puts "Too low!"
how_many_guesses? += 1
guess
end
end
The error I received was:
syntax error, unexpected tOP_ASGN
how_many_guesses? += 1
I don't understand what unexpected tOP_ASGN means.
As other commented you are trying to assign a value to a function.
You can use some other approaches for example using a class variable, or a setter method.
In the first case you use an instance variable, and you just increment or decrement its value:
class Guess
def initialize
#guesses = 0
end
def guess
puts "Please type a number between 1 and a 100."
gets.chomp
end
def correct?
if guess == guess
puts "You have already guessed this number, try again!"
guess
elsif guess == random_num
you_are_correct
elsif guess > correct_num
puts "Too high!"
#guesses += 1
guess
else
puts "Too low!"
#guesses += 1
guess
end
end
end
In this example you can use attr_reader to publish the guesses variable
The other way, more c++ style, is using getter and setter functions:
class Guess
def initialize
#guesses = 0
end
def get_guesses
#guesses
end
def set_guesses(guesses)
#guesses = guesses
end
def how_many_guesses?
guesses = 0
end
def guess
puts "Please type a number between 1 and a 100."
gets.chomp
end
def correct?
if guess == guess
puts "You have already guessed this number, try again!"
guess
elsif guess == random_num
you_are_correct
elsif guess > correct_num
puts "Too high!"
set_guesses(get_guesses + 1)
guess
else
puts "Too low!"
set_guesses(get_guesses + 1)
guess
end
end
end
This is another solution, but it is not recommended in ruby.
EDIT: Some comments included the option of using global variables, just don't!
To elaborate on #Gavriel's answer, functions are singletons, while += is an assignment operator
Your code can be rewritten to basically look like so:
def how_many_guesses?
guesses = 0
end
how_many_guesses? = how_many_guesses? + 1
Which is impossible, as you can not assign to function symbols in this manner. It is possible to redefine a function on the fly due to Ruby's robust metaprogramming capabilities, but that falls far outside the scope of this question.
The easiest way for you to fix it is to do the following:
numGuesses = how_many_guesses?
numGuesses += 1
how_many_guesses? is a function, you can only assign a value to a variable. But maybe you should read a bit more about functions generally, as your code indicates you might need some clarification.
What you probably wanted to do is something like:
$guesses = 0
and
$guesses += 1
You don't need a function here I think.
But the bigger problem will be that every time you wrote down "guess" it will wait for you to type a number.
if guess == guess # here you'll enter 2 numbers
puts "You have already guessed this number, try again!"
guess # here you'll enter another one
elsif guess == random_num # and if the 1st and 2nd numbers were different then you'll be asked another one here...
Option 1:
Replace all how_many_guesses? with $guesses making it a global variable. Define guesses at the top of the file: $guesses = 0
Option 2 (Better):
Put everything in a class and make guesses an instance variable:
class GuessGame
def initialize
#guesses = 0
end
def guess
# ...
end
def correct?
# ...
#guesses += 1
end
end
Related
I tried to rewrite the "if/else statement" in the following piece of code by replacing it with a "case" statement, and I am deadly stuck with it for a few hours - what am I missing?
puts "Welcome to 'Guess My Number!'"
print "What is your name?"
input = gets
name = input.chomp
puts "Welcome, #{name.upcase!}!"
puts "I've got a random number between 1 and 100!"
puts "Can you guess it?"
target = rand(100) + 1
num_guesses = 0
guessed_it = false
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "You've got #{remaining_guesses.to_s} guesses left!"
print "Make a guess, put down a number: "
guess = gets.chomp.to_i
num_guesses = num_guesses + 1
end
puts case verification
when guess < target
then "Ooops. Your guess was LOW."
when guess > target
then "Ooops. Your guess was HIGH."
when guess < -1
then puts "Oooops. You have entered a number lower that 1!"
when guess > 100
then puts "Oooops. You have entered a number higher than 100!"
when guess =~ /^([w])/
then puts "Ooops. Looks like you have entered a non numeric
value!"
when guess == String
then puts "Oooops! Looks like you have entered a non numeric
value"
when guess == target
then puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
unless guessed_it
puts "Sorry, you didn't get my number. My number was #{target}."
end
The "case statement" was used to replace and enhance the logic of the following if else statement:
if guess < target
puts "Ooops. Your guess was LOW."
elsif guess > target
puts "Ooops. Your guess was HIGH."
elsif guess == target
puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
Your problem is that you're using the form of case with the optional condition, but you're using when clauses as if you were using the condition-less case.
puts case
when guess < target
"Ooops. Your guess was LOW."
should work.
Further explanation:
using case without a condition, the earliest when branch with a truthy expression is executed. This is what you want here.
But you were using case with verification. In this case, all branches are compared to verification, and the first branch where verification === branch condition is true is executed.
Since in your example I'm guessing verification is always nil, and all your branches' conditions are always true or false, no branch will ever get executed.
You can use a case statement like so:
class String
def green;"\e[32m#{self}\e[0m";end
def yellow;"\e[33m#{self}\e[0m";end
def cyan;"\e[36m#{self}\e[0m";end
def bg_blue;"\e[44m#{self}\e[0m";end
def bold;"\e[1m#{self}\e[22m";end
def underline;"\e[4m#{self}\e[24m";end
def border(num);"\n#{'-' * num}\n#{self}\n#{'-' * num}\n";end
end
puts;puts "Welcome to 'Guess My Number!'".bold.bg_blue;puts
print 'What is your name? '.green
name = gets.chomp
puts "\nWelcome, #{name.upcase!}!\n".cyan.underline
puts "I've got a random number between 1 and 100!\nCan you guess it?".border(44)
target = rand(100) + 1
num_guesses = 0
guessed_it = false
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "\nYou've got #{remaining_guesses} guesses left!\n"
puts;print 'Make a guess, put down a number: '
guess = gets.chomp
case guess.to_i
when (1...target)
puts 'Ooops. Your guess was LOW'.yellow.border(26)
when (target + 1..100)
puts 'Ooops. Your guess was HIGH'.yellow.border(26)
when target
puts; puts; puts
puts "Good job, #{name}!".bold.green
puts 'You guessed my number in ' + "#{num_guesses} guesses!".cyan
puts; puts; puts
guessed_it = true
else
puts "Oooops. You didn't enter a number from 1 to 100".yellow.border(47); puts
end
num_guesses += 1
end
unless guessed_it
puts;puts;puts "Sorry, you didn't get my number. My number was #{target}.".yellow;puts
end
Thanks a lot to everybody! With your invaluable help I managed to regain patience in my soul and satisfaction from this small task :) My mistake is that I violated the rules of common sense by trying to run several pieces of code in a wrong sequence. I moved the case statement inside the until loop and now all I have to do is correct the mistakes in particular when/then statements. It works :)
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "You've got #{remaining_guesses.to_s} guesses left!"
print "Make a guess, put down a number: "
guess = gets.chomp.to_i
num_guesses = num_guesses + 1
puts case
when guess < target
then "Ooops. Your guess was LOW."
when guess > target
then "Ooops. Your guess was HIGH."
when guess < -1
then puts "Oooops. You have entered a number lower that 1!"
when guess > 100
then puts "Oooops. You have entered a number higher than 100!"
when guess =~ /^([w])/
then puts "Ooops. Looks like you have entered a non numeric value!"
when guess == String
then puts "Oooops! Looks like you have entered a non numeric value"
when guess == target
then puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
end
unless guessed_it
puts "Sorry, you didn't get my number. My number was #{target}."
end
I created a guessing game through Ruby and I believe the structure of my code is off. When entering 'Cheat', you are given the random number then asked to type it in again. When typed in again, it says the random number is not correct and always defaults to my 'elseif' in line 45.
puts "Hey! I'm Sam. What's your name?"
name = gets
puts "Welcome #{name}. Thanks for playing the guessing game.
I've chosen a number between 1-100.
You'll have 10 tries to guess the correct number.
You'll also recieve a hint when you're guess is wrong.
If you feel like being a big ol cheater, type 'Cheat'.
Let's get started..."
random_number = rand(1...100)
Cheat = random_number
counter = 10
loop do
break if counter == 0
divisor = rand(2...10)
guess = gets.chomp
break if guess.to_i == random_number
counter -= 1
if
guess == random_number
puts 'You guessed the right number! You win!'
end
if counter < 4
puts "You can go ahead and cheat by typing 'Cheat'..."
end
if guess.to_s.downcase.eql? "cheat"
puts "The random number is #{random_number} you CHEATER!! Go ahead and type it in..."
guess = gets.chomp
puts = "You win cheater!"
end
if
guess.to_i < random_number
puts 'Ah shucks, guess again!'
guess = gets.chomp
elsif
guess.to_i > random_number
puts 'Too high, guess again!'
guess = gets.chomp
end
if random_number % divisor == 0
puts "Thats not it.\n #{guess} is #{guess.to_i > random_number ? 'less' : 'greater'} than the random number.
The random number is divisible by #{divisor}.\nTry again: "
elsif
puts "That's not the random number.\n #{guess} is #{guess.to_i > random_number ? 'less' : 'greater'} than the random number.
The random number is NOT divisible by #{divisor}.\nTry again: "
end
end
if counter > 0
puts "The number is #{random_number}! You win!"
else
puts "You lose! Better luck another time."
end
this is the response i get in the terminal
Let's get started...
Cheat
The random number is 96 you CHEATER!! Go ahead and type it in...
96
Thats not it.
96 is greater than the random number.
The random number is divisible by 8.
Try again:
The problem is here:
puts = "You win cheater!"
You're assigning the string "You win cheater!" to a local variable named puts. Changing it to this fixes the problem:
puts "You win cheater!"
You'll probably also want to put a break after that line.
As an aside, this pattern:
loop do
break if counter == 0
# ...
end
...would be better expressed as:
while counter > 0
# ...
end
...or:
until counter == 0
# ...
end
Also, you should always put the condition for an if/elsif/whathaveyou on the same line as if et al. Why? Because if you don't you get bugs like this:
if random_number % divisor == 0
# ...
elsif
puts "..."
end
Can you spot the bug? You forgot to put a condition after elsif, or used elsif when you meant to use else, which means that the return value of puts (which is always nil) is being used as the condition, just as if you had written elsif puts "...".
If you make a habit of always putting the condition on the same line as if/elsif, your eye will get used to it and errors like this will jump out at you.
I have a code below:
secret_number = 8
user_input = ""
def number_guesser(user_input)
while user_input != secret_number
puts "Guess a number between 1 and 10:"
user_input = gets.chomp
if user_input != secret_number
puts "Wrong! Try again."
else
puts "You guessed correctly!"
end
end
end
number_guesser(user_input)
when I tried to run the above program it showed as below:
****undefined local variable or method secret_number' for main:Object
(repl):211:innumber_guesser'
(repl):221:in `'****
Any ideas?
You can't use a local variable like that inside another scope such as a method, it's two different contexts. Instead you need to pass that in if you want to use it.
It's a simple change:
def number_guesser(user_input, secret_number)
# ...
end
Then just feed that argument in.
You'll note that user_input isn't really necessary as a parameter, you can always initialize and use that locally, so it's actually pointless as an argument.
The pattern to use in that case:
loop do
input = gets.chomp
# Prompting...
break if input == secret_number
# Guessed wrong...
end
I'm having a problem with my ruby script. If anyone could help, I'd really appreciate it. The problem is that the number is stuck between 1-2; where 2 is too high and 1 is too low. The guesses should be integers only.
#!/usr/bin/ruby
def highLow(max)
again = "yes"
while again == "yes"
puts "Welcome to the High Low game"
playGame(max)
print "Would you like to play again? (yes/no): "
again = STDIN.gets.chomp
if again == 'no'
puts "Have a nice day, Goodbye"
end
end
end
#This method contains the logic for a single game and call the feedback method.
def playGame(max)
puts "The game gets played now"
puts "I am thinking of a number between 1 and #{max}." #It show what chosen by user
randomNumber = rand(max)+ 1
print "Make your guess: "
guess = STDIN.gets.chomp
feedback(guess, randomNumber)
end
#Start while loop
#Logic for feedback method. It's ganna check the guess if it's high or low.
def feedback(guess, randomNumber)
count = 1
while guess.to_i != randomNumber
count = count + 1
if guess.to_i < randomNumber
print "That's too low. Guess again: "
else
print "That's too high. Guess again: "
end
guess = STDIN.gets.chomp
end
puts "Correct! You guessed the answer in #{count} tries!"
end
highLow(ARGV[0])
Change your last line to this:
highLow(ARGV[0].to_i)
The ARGV array contains all the passed in arguments as strings, so you have to cast it to integer.
I am trying to make a number guessing game in Ruby but the program exits after I type in yes when I want to play again. I tried using the catch and throw but it would not work. Could I please get some help.
Here is my code.
class Game
def Play
catch (:start) do
$a=rand(11)
puts ($a)
until $g==$a
puts "Guess the number between 0-10."
$g=gets.to_i
if $g>$a
puts "The number you guessed is too high."
elsif $g==$a
puts "Correct you won!!!"
puts "Would you like to play again?"
$s=gets()
if $s=="yes"
$c=true
end
if $c==true
throw (:start)
end
elsif $g<$a
puts "The number you guessed is too low."
end
end
end
end
end
Game.new.Play
Edit: Here's my new code after trying suggestions:
class Game
def Play
catch (:start) do
$a=rand(11)
puts ($a)
while $s=="yes"
until $g==$a
puts "Guess the number between 0-10."
$g=gets.chomp.to_i
if $g>$a
puts "The number you guessed is too high."
elsif $g==$a
puts "Correct you won!!!"
puts "Would you like to play again?"
$s=gets.chomp
if $s=="yes"
throw (:start)
end
elsif $g<$a
puts "The number you guessed is too low."
end
end
end
end
end
end
Game.new.Play
Your first problem is here:
$s=gets()
if $s=="yes"
$c=true
end
The gets method will read the next line including the new line character '\n', and you compare it to only "yes":
> gets
=> "yes\n"
The idiomatic way to fix this in Ruby is the chomp method:
> gets.chomp
=> "yes"
That said, your code has two other deficiencies.
You may come from a language such as PHP, Perl, or even just Bash scripting, but Ruby doesn't require the dollar sign before variables. Using a $ gives a variable global scope, which is likely not what you want. In fact, you almost never want a variable to have global scope.
Ruby uses three types of symbol prefixes to indicate scope - # for instance, ## for class, and $ for global. However the most common type of variable is just local which doesn't need any prefix, and what I would suggest for your code.
I have always been told that it is very bad practice to use exceptions for control structure. Your code would be better served with a while/break structure.
When you do gets(), it retrieves the full line with a '\n' in the end. You need to trim the new line character by using:
$g=gets.chomp.to_i
Same for other gets
Based on your updated code (where you fixed the newline problem shown by others), your new problem is that you have wrapped all your game inside while $s=="true". The very first time your code is run, $s is nil (it has never been set), and so you never get to play. If you used local variables instead of global variables (s instead of $s) this would have become more obvious, because the code would not even have run.
Here's one working way that I would re-write your game.
class Game
def play
keep_playing = true
while keep_playing
answer = rand(11) # Make a new answer each time
puts answer if $DEBUG # we don't normally let the user cheat
loop do # keep going until I break from the loop
puts "Guess the number between 0-10."
guess = gets.to_i # no need for chomp here
if guess>answer
puts "The number you guessed is too high."
elsif guess<answer
puts "The number you guessed is too low."
else
puts "Correct you won!!!",
"Would you like to play again?"
keep_playing = gets.chomp.downcase=="yes"
break
end
end
end
end
end
Game.new.play
I know this doesn't really answer your question about why your code isn't working, but after seeing the code you posted I just had to refactor it. Here you go:
class Game
def initialize
#answer = rand(11)
end
def play
loop do
guess = get_guess
display_feedback guess
break if guess == #answer
end
end
def self.play_loop
loop do
Game.new.play
break unless play_again?
end
end
private
def get_guess
puts "Guess the number between 0-10."
return gets.chomp.to_i
end
def display_feedback(guess)
if guess > #answer
puts "The number you guessed is too high."
elsif guess < #answer
puts "The number you guessed is too low."
elsif guess == #answer
puts "Correct you won!!!"
end
end
def self.play_again?
puts "Would you like to play again?"
return gets.chomp == "yes"
end
end
Game.play_loop