Ruby undefined method `+' for nil:NilClass - ruby

I'm a total beginner in ruby but I can't get out of this issue
I get these when I run the code, it all works well until the end:
INPUT TEXT: It all works well until
INPUT SUBTEXT: ll
TEXT: It all works well until SUBTEXT: ll
OUTPUT:
4
15
undefined method +' for nil:NilClass
(repl):18:ininitialize'
puts "\nINPUT TEXT:"
#text = gets.chomp
puts "\nINPUT SUBTEXT:"
#subtext = gets.chomp
puts "\nTEXT: " + #text
puts "SUBTEXT: " + #subtext
puts "\n"
i = #text.index (#subtext)
puts "OUTPUT:"
while i != -1
puts i.to_s + ' '
i = #text.index #subtext, i+1
end

In Ruby, String#index doesn't return -1 when the substring is not found; it returns nil. Change your condition from while i != -1 to while i. (This works because, unlike some other languages, Ruby considers the value 0 to be true; only false and nil are false.)

Index return nil if substrings doesn't exist. So this should solve this issue
#text = gets.chomp
puts "\nINPUT SUBTEXT:"
#subtext = gets.chomp
puts "\nTEXT: " + #text
puts "SUBTEXT: " + #subtext
puts "\n"
i = #text.index (#subtext)
puts "OUTPUT:"
while i
puts i.to_s + ' '
i = #text.index #subtext, i+1
end

Related

Stuck in while loop even though condition has been met

I'm writing this script to build a tic-tac-toe game. This is only the beginning (no turns yet). I want to let the user input again if the previous input is invalid.
def display_board(board)
first_row = " #{board[0]} | #{board[1]} | #{board[2]} "
second_row = " #{board[3]} | #{board[4]} | #{board[5]} "
third_row = " #{board[6]} | #{board[7]} | #{board[8]} "
row_divider = "-----------"
puts first_row
puts row_divider
puts second_row
puts row_divider
puts third_row
end
def valid_move?(board,index)
if (index >= 0) && (index <= board.length - 1) && (position_taken?(board,index) != FALSE)
return TRUE
else
return FALSE
end
end
def input_to_index(user_input)
index = user_input.to_i - 1
return index
end
def move(board, index, character = "X")
board[index] = character
end
def position_taken?(board,index)
if (board[index] == "X") || (board[index]=="O")
return FALSE
end
end
def turn(board)
puts "Please enter 1-9:"
user_input = gets.strip
index = input_to_index(user_input)
while valid_move?(board,index) == FALSE
puts "invalid"
turn(board)
end
move(board, index, character = "X")
display_board(board)
end
I am stuck on the while loop. If I input an invalid input and then a valid input, it runs through the while loop instead of ending the program. It should be true. The problem is fixed if I use an if statement instead of a while loop, but I want to learn to use while loops better.
Because you call "turn" (internal) from "turn" (external) and then the internal "turn" called is valid but the board and index on the external
"turn" didn't change.
try this:
def turn(board)
loop do
puts "Please enter 1-9:"
user_input = gets.strip
index = input_to_index(user_input)
if valid_move?(board,index) == TRUE
break
end
puts "invalid"
end
move(board, index, character = "X")
display_board(board)
end

Ruby Word Guessing Game

I am new to Ruby and working with this hangman style word guessing game. I have 2 main issues. Here is what I am working with now:
class Word_game
def initialize(word)
#word = word.downcase
#display_word = "_ " * word.length
end
def guess_the_word(word_guess)
word_guess.downcase
#word.split("").each_with_index do |word_letter, index|
if word_guess == word_letter
#display_word[index] = word_guess
p #display_word
puts "You're getting somewhere! Keep trying!"
end
end
if !#word.include? (word_guess)
puts "Nope, guess again..."
end
def win?
if #word == #display_word
puts "Congratulations you won!!! You are the word master!!!"
true
else
false
end
end
def lose?
if #attempts == 0
puts "You lose!!"
true
end
end
puts "Welcome to the Word Guessing Game! Let's see if YOU have what it TAKES!!!"
puts "This is a 2 player game. "
puts "Player 1... please enter a word for Player 2 to guess!"
puts ">>"
game_word = gets.chomp
game = Word_game.new(game_word)
attempts = 0
guessed_letters = []
until #attempts == game_word.length
puts "Ok Player 2, Guess a letter! GO!!!"
letter_guess = gets.chomp
if guessed_letters.include? letter_guess
puts "You already guessed that letter! Enter a new one."
letter_guess = gets.chomp
end
guessed_letters << letter_guess
game.guess_the_word(letter_guess)
if game.win?
attempts += 1
else game.lose?
end
end
end
First, the word progress should look like this if the word is hello:
h _ e _ _ o
Instead of this, the spaces are not in the right places and looks like this (an actual outcome of running my code):
.
Ok Player 2, Guess a letter! GO!!!
h
"h _ _ _ _ "
You're getting somewhere! Keep trying!
Ok Player 2, Guess a letter! GO!!!
o
"h _ o _ _ "
You're getting somewhere! Keep trying!
Ok Player 2, Guess a letter! GO!!!
e
"he_ o _ _ "
You're getting somewhere! Keep trying!
Ok Player 2, Guess a letter! GO!!!
l
"hel o _ _ "
You're getting somewhere! Keep trying!
"hello _ _ "
When the user guesses the word, it does not put my "congrats" statement and end the game.
I am also stuck on my 'lose' method. I am not sure how to fix the method so that the game ends when the user runs out of attempts and prints the "lose" statement.
Thanks for your help!
I think you're making the output too complicated. I would track the word and the guesses in an array. Instead of a display_word variable, I'd make it a method, possibly "to_s"
By the way, Ruby convention is to use CamelCase class names.
class WordGame
def initialize(word)
#word = word.downcase.chars
#guesses = ["_"] * #word.size
end
def to_s
#guesses.join " "
end
This should fix your spacing problem. This will also simplify guesses.
Also, the checking to see if you've already used the letter should probably be handled by the WordGame class.
For your first problem, your #display_word starts as follows:
[0] = '_' # For h
[1] = ' '
[2] = '_' # For e
[3] = ' '
...
When you guess 'e', for instance, you do:
#display_word[index] = word_guess
Where index equals 1, the second character in "hello", so as you can see it doesn't write to the 'e' index in #display_word.
For your second problem, there are a number of ways to fix it. For instance, I would do something like using #attempts_remaining starting from a value of 10 or so, then using the existing code:
if !#word.include? (word_guess)
#attempts_remaining -= 1 # Count failure to guess
puts "Nope, guess again..."
end
Then:
def win?
# If you've guessed all the letters, there's no '_' left in the display word
if !#display_word.include? ('_')
puts "Congratulations you won!!! You are the word master!!!"
true
else
false
end
end
def lose?
if #attempts_remaining == 0
puts "You lose!!"
true
end
end
Finally, tweak the until loop termination condition:
until game.win? or game.lose?
The existing calls to win? and lose? can be deleted.
(WORD MISSING GAME)
puts " "
puts "Total Round"
puts " "
puts "=> [Round-One ,Round-two,Round -three Round-four]"
puts " "
puts "=> [TOTAL 5 Tries]"
puts " "
one=""
two=""
three=""
four=""
puts " "
puts " --ROUND One press-- => (1)"
one=gets.to_i
puts '==================='
puts "Question:=> ( K ? N G )"
puts ""
c=5
5.times do
string1 = 'i'
stringone ="I"
puts "Answer:=> Try NO:#{c}"
string2 = gets.chomp
if (string1==string2)
puts "Good Work correct spaling"
break
elsif (stringone == string2 )
puts "Good Work correct spaling"
break
else
puts "-Worng spaling-"
end
c -=1
end
puts " Round Over "
if c<1
puts " Tries Over Game End "
exit
end
puts '==================='
puts "--ROUND Two press-- => (2)"
two=gets.to_i
puts '==================='
puts "Question:=> (P L ? Y )"
5.times do
string1 = 'a'
stringone = "A"
puts "Answer:=> Try NO:#{c}"
string2 = gets.chomp
if (string1==string2)
puts "Good Work correct spaling"
break
elsif (stringone==string2)
puts "Good Work correct spaling"
break
else
puts "-Worng spaling-"
end
c -=1
if c<1
puts " Tries Over Game End "
exit
end
end
puts " Round Over "
puts '==================='
puts "--ROUND Three press-- => (3)"
three=gets.to_i
puts '==================='
puts "Question:=> ( S P ? T )"
5.times do
string1 = 'o'
stringone= 'O'
puts "Answer:=> Try NO:#{c}*"
string2 = gets.chomp
if (string1==string2)
puts "_Good Work correct spaling_"
break
elsif (stringone == string2)
puts "_Good Work correct spaling_"
break
else
puts "-Worng spaling-"
end
c -=1
if c<1
puts " *Tries Over Game End* "
exit
end
end
puts " *Round Over* "
puts '==================='
puts "--ROUND Four press-- => (4)"
four=gets.to_i
puts '==================='
puts "Question:=> ( G ? M E )"
5.times do
string1 = 'a'
stringone = "A"
puts "Answer:=> Try NO:#{c}*"
string2 = gets.chomp
if (string1==string2)
puts "_Good Work correct spaling_"
break
elsif (stringone == string2)
puts "_Good Work correct spaling_"
break
else
puts "-Worng spaling-"
end
c -=1
if c<1
puts " *Tries Over Game End* "
exit
end
end
puts "**Yahoo Congragualtion complete All Round**"

Creating A Caesar Cipher in Ruby, getting an error

I am attempting to create a Caesar Cipher in Ruby for my computer science class. My friend was able to create part of the code:
def cipher(word, n)
new_word = ""
word.each_char do |i|
n.times do
if(i == "z")
i = "a"
next
elsif(i == "Z")
i = "A"
next
end
i.next!
i == "%" ? i = " " : ""
end
new_word += i
end
puts new_word
end
cipher("phrase", 5)
Where the last line is where you would put the phrase you want to scramble, and the number is how much you want to scramble it by. One of the requirements is that we use gets.chomp to specify a phrase and amount to scramble by without editing the .rb file itself. So I came up with this:
puts "What would you like to scramble?"
word = gets.chomp
puts "How much would you like to scramble that?"
n = gets.chomp
def cipher(word, n)
new_word = ""
word.each_char do |i|
n.times do
if(i == "z")
i = "a"
next
elsif(i == "Z")
i = "A"
next
end
i.next!
i == "%" ? i = " " : ""
end
new_word += i
end
puts new_word
end
cipher(word, n)
And I get the following error outputed when run in Terminal:
some.rb:10:in `block in cipher': undefined method `times' for "5":String (NoMethodError)
from some.rb:9:in `each_char'
from some.rb:9:in `cipher'
from some.rb:26:in `<main>'
If someone could help me figure out what I'm doing wrong, that would help me out a lot.
gets.chomp returns a string
word = gets.chomp
So word is a string, as expected, but then you call gets.chomp again, this time to get number of scrabbles that should be applied to the string. So n is a string as well.
n = gets.chomp
When you call the times method on n it's not defined, because it only makes sense on integers. The solution is to convert n to an integer. This should work:
n = gets.chomp.to_i
Update
Documentation on the to_i method on String instances: http://ruby-doc.org/core-2.0.0/String.html#method-i-to_i
Call .to_i on n.
You need to convert that string you got from the user's input into a number before you can run .times on it. .to_i does this for you.
Example:
http://progzoo.net/wiki/Ruby:Convert_a_String_to_a_Number
Did this a while ago, the requirements were only lowercase ASCII alphabet letters, hope you get the general idea to do it your way:
def encrypt(msg, key)
msg.downcase.split("").each_with_index do |char, i|
next if msg[i] == " "
msg[i] = (msg[i].ord + key) > 122 ? (((msg[i].ord + key) % 123) + 97).chr : (msg[i].ord + key).chr
end
msg
end
def decrypt(msg, key)
msg.downcase.split("").each_with_index do |char, i|
next if msg[i] == " "
msg[i] = (msg[i].ord - key) < 97 ? (123 - (97 - (msg[i].ord - key))).chr : (msg[i].ord - key).chr
end
msg
end
gets.chomp return a string, you must convert it to a number in order to call .times method. Change this line n = gets.chomp by n = gets.chomp.to_i

Why can't I convert a fixnum into a string?

I am creating a quiz-maker program in Ruby. It opens and reads a text file, and is able to make a quiz of of the questions and answers in the text file. I am trying to let the user know how many question they got wrong after they complete the quiz.
The error I am getting is:
quiz.rb:180:in `+': can't convert Fixnum into String (TypeError)
from quiz.rb:180:in `<main>'
I get this error after it goes through all the questions.
Here is my code. correct_count is where I try to subtract 1 from the starting 10 everytime someone gets a question wrong. Let me know if you would like to see the text file.
questions = File.open("question.txt","r+")
array = {}
contents = questions.readlines
questions.close
contents.collect! do |x|
x.chomp
end
contents.collect! do |x|
x.split(',')
end
contents.each do |x|
array[x[0]] = x
end
correct_count = 10
question1 = contents[0][1]
choice11 = contents[0][2]
choice12 = contents[0][3]
answer11 = contents[0][4]
question2 = contents[1][1]
choice21 = contents[1][2]
choice22 = contents[1][3]
answer21 = contents[1][4]
question3 = contents[2][1]
choice31 = contents[2][2]
choice32 = contents[2][3]
answer31 = contents[2][4]
question4 = contents[3][1]
choice41 = contents[3][2]
choice42 = contents[3][3]
answer41 = contents[3][4]
question5 = contents[4][1]
choice51 = contents[4][2]
choice52 = contents[4][3]
answer51 = contents[4][4]
question6 = contents[5][1]
choice61 = contents[5][2]
choice62 = contents[5][3]
answer61 = contents[5][4]
question7 = contents[6][1]
choice71 = contents[6][2]
choice72 = contents[6][3]
answer71 = contents[6][4]
question8 = contents[7][1]
choice81 = contents[7][2]
choice82 = contents[7][3]
answer81 = contents[7][4]
question9 = contents[8][1]
choice91 = contents[8][2]
choice92 = contents[8][3]
answer91 = contents[8][4]
question10 = contents[9][1]
choice101 = contents[9][2]
choice102 = contents[9][3]
answer101 = contents[9][4]
topic = contents[11][1]
puts "Welcome to this " + topic + " quiz. Please spell the answers exactly right to get them correct (don't worry about caps). Good Luck!"
puts question1
puts choice11 + " or " + choice12 + "?"
user1 = gets.chomp
if user1.downcase == answer11.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "Next question: " + question2
puts choice21.downcase + " or " + choice22 + "?"
user2 = gets.chomp
if user2.downcase == answer21.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "Next question: " + question3
puts choice31.downcase + " or " + choice32.downcase + "?"
user3 = gets.chomp
if user3.downcase == answer31.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "Next question: " + question4
puts choice41.downcase + " or " + choice42.downcase + "?"
user4 = gets.chomp
if user4.downcase == answer41.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "Next question: " + question5
puts choice51.downcase + " or " + choice52.downcase + "?"
user5 = gets.chomp
if user5.downcase == answer51.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "Next question: " + question6
puts choice61.downcase + " or " + choice62.downcase + "?"
user6 = gets.chomp
if user6.downcase == answer61.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "Next question: " + question7
puts choice71.downcase + " or " + choice72.downcase + "?"
user7 = gets.chomp
if user7.downcase == answer71.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "Next question: " + question8
puts choice81.downcase + " or " + choice82.downcase + "?"
user8 = gets.chomp
if user8.downcase == answer81.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
if user9.downcase == answer91.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "Next question: " + question10
puts choice101.downcase + " or " + choice102.downcase + "?"
user10 = gets.chomp
if user10.downcase == answer101.downcase
puts "correct"
else
puts "incorrect" and correct_count -1
end
puts "you got" + correct_count + "out of 10 correct"
Change:
puts "you got" + correct_count + "out of 10 correct"
to:
puts "you got" + correct_count.to_s + "out of 10 correct"
or:
puts "you got #{correct_count} out of 10 correct"
NOTE:
correct_count = 10
puts "incorrect" and correct_count -1
correct_count # => 10
# >> incorrect
correct_count still evaluates to 10.
You should be doing:
if user6.downcase == answer61.downcase
puts "correct"
else
puts "incorrect"
correct_count -= 1
end

ruby, unexpected kend and end errors

new to ruby, keep getting "kend and $end errors...Not too sure what i'm doing wrong.
Two options in this code, one should search for a user and return the tweet for each tweet which is a max of the given number. And other should search twitter tweets for a string and then return the result also.
require "rubygems"
require "twitter"
tweetsorlooks = String.new ARGV[1]
namesearchword = String.new ARGV[2]
number = String.new ARGV[3]
userurl = 'https://api.twitter.com/1/statuses/user_timeline.json?
include_entities=true&include_rts=true&screen_name=#{namesearchword }&count=#{number}'
searchurl = 'http://search.twitter.com/search.json?q=#
{namesearchword}&result_type=mixed'
statusresponse = RestClient.get(userurl)
userdata = statusresponse.body
userresult = JSON.parse(userdata)
queryresponse = RestClient.get(queryurl)
queryurl= queryresponse.body
queryresult= JSON.parse(queryurl)
if ARGV[1] == 'tweets'
puts
ref["userresult"].each do
puts tweet["from_user"] + " : " + tweet["text"]
end
else
puts
ref["queryresul"].each do
puts tweet["from_user"] + " : " + tweet["text"]
end
Get used to indent your code properly:
if ARGV[1] == 'tweets'
puts
ref["userresult"].each do
puts tweet["from_user"] + " : " + tweet["text"]
end
else
puts
ref["queryresul"].each do
puts tweet["from_user"] + " : " + tweet["text"]
end
now the problem is obvious.
An end is missing in the end. The outer if loop is not properly closed.

Resources