Ruby if/elsif/else - ruby

I am attempting to write a game. In the following code, it keeps skipping to the bottom else even if a valid integer is entered. Why?
puts 'You will be O\'s and I will be X\'s'
puts
puts '1,2,X'
puts '4,5,6'
puts '7,8,9'
puts
puts 'Your move...'
puts
moveOne = gets.chomp
if moveOne == 5
puts = '1,2,X'
puts = '4,O,6'
puts = 'X,8,9'
elsif moveOne == 1
puts = 'O,2,X'
puts = '4,5,6'
puts = 'X,8,9'
elsif moveOne == 7
puts = 'X,2,X'
puts = '4,5,6'
puts = 'O,8,9'
elsif moveOne == 9
puts = 'X,2,X'
puts = '4,5,6'
puts = '7,8,O'
elsif moveOne == 2
puts = '1,O,X'
puts = '4,X,6'
puts = '7,8,9'
elsif moveOne == 4
puts = '1,2,X'
puts = 'O,X,6'
puts = '7,8,9'
elsif moveOne == 6
puts = '1,2,X'
puts = '4,X,O'
puts = '7,8,9'
elsif moveOne == 8
puts = '1,2,X'
puts = '4,X,6'
puts = '7,O,9'
else
puts'please enter a number!'
end
puts
puts 'Your move again'

Because chomp is giving you a string, not an integer.
moveOne = gets.chomp.to_i

This is happening because gets.chomp returns a String, not an Integer. if you do:
"a".to_i --> 0 , Which your program might think the user has actually entered a 0.
So, first, you want to make sure that what the user has entered is a number character, even though it's of class String.
Here is what you could do:
1 - Create a method that will check if a String is number-like:
def is_a_number?(s)
s.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
2 - If it is number like, just cast it to integer using .to_i
So, your code would look like:
moveOne = gets.chomp
if is_a_number?(moveOne)
number_entered = moveOne.to_i
if number_entered == 5
...
elsif number_entered == 1
...
else
puts "enter a number..."
end

Related

Why will this not iterate through the file like I want it to?

It will just output two blank lines to the screen when it should be printing the card id and the balance
I have completely re-written the code.
I have fiddled with that code for an hour
class RBC
def initialize
#args = ["Create a new card"]
#functions = ["create_rbc"]
puts "Do you have an RBC ID yet? Yes(0) No(1)"
hasrbc = gets.chomp.to_i
if hasrbc == 1
#balance = 5
create_rbc
else
login
end
end
def create_rbc
puts "\nGenerating your rbc\n\n"
puts "\nWelcome to your Ruby Binary Card(RBC)!\n\n"
puts "Your RBC will keep track of your RubyCredits(RC).\n"
puts "You will get paid RC for work apps, and pay for game apps.\n"
puts "If you lose track of your RBC ID, you can get a new one.\n"
puts "Doing this, however, will reset your balance to the default of $5\n\n"
puts "What is your name? Do first last\n"
#fullname = gets.chomp
#card_name = get_name_codec(#fullname)
#card_cipher = "#{rand(1..9)}#{rand(1..9)}#{rand(1..9)}#{rand(1..9)}#{rand(1..9)}#{rand(1..9)}#{rand(1..9)}#{rand(1..9)}#{rand(1..9)}#{rand(1..9)}"
#card_id = "#{#card_name} - #{#card_cipher}"
instance_variable_set("#Id#{#card_cipher}", #balance)
puts "Write down your RBC ID: #{#card_id}"
file = File.open("Cards.rbc", "w")
file.puts #card_id
file.puts #balance
end
end
def get_name_codec(name)
names = name.split(" ")
fname = names[0]
lname = names[1]
fchar = fname.split(//)
fcodec = "#{fchar[0]}#{fchar[1]}"
name_codec = "#{fcodec}#{lname}"
return name_codec
end
def login
#found = false
puts "What is your RBC Id"
input = gets.chomp
File.open("Cards.RBC", "r") do |f|
f.each_line do |line|
if input == "#{line}"
#card_id = line.to_s
#found == true
elsif #found == true
#balance = line.to_i
end
end
end
puts "#{#card_id}#{#balance}"
end
RBC.new
Then the Cards.RBC
TiLan - 1122632527
5
I want it to print the balance and card Id.
It should give me my card id and then the balance like this:
0000...etc
5
input = gets.chomp removes the newline off the input, but f.each_line does not. So input == "#{line}" is comparing, for example, "1234" with "1234\n".
Chomp the line as well.
input = gets.chomp
File.open("Cards.RBC", "r") do |f|
f.each_line do |line|
line.chomp!
if input == line
#card_id = line
#found == true
elsif #found == true
#balance = line.to_i
end
end
end
You can debug this sort of thing by printing the values with p. This will show them as quoted strings and show any special characters including newlines.
p line
p input

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

Should this be refactored to be more DRY?

I am working through Chris Pine's Chapter 6 Deaf Grandman challenge. It looks very readable however I wonder if this is violating the DRY principle. If so, how can I refactor it?
puts "WHAT DID YOU SAY??"
said = gets.chomp
x = 0
bye_counter = 0
while bye_counter < 3
if said != said.upcase
puts "HUH?! SPEAK UP, SONNY!"
said = gets.chomp
bye_counter = 0
elsif said == said.upcase && said != "BYE"
puts "NO, NOT SINCE " + rand(1930..1950).to_s + "!"
bye_counter = 0
said = gets.chomp
elsif said == "BYE"
puts "HUH??"
bye_counter += 1
break if bye_counter == 3
said = gets.chomp
end
end
puts "OH.. OK!"
My solution:
message = "WHAT DID YOU SAY??"
bye_counter = 0
puts message
while bye_counter < 3
said = gets.chomp
if said == "BYE"
message = "HUH??"
bye_counter += 1
else
if said == said.upcase
message = "NO, NOT SINCE " + rand(1930..1950).to_s + "!"
else
message = "HUH?! SPEAK UP, SONNY!"
end
bye_counter = 0
end
break if bye_counter == 3
puts message
end
puts "OH.. OK!"

How to add underscores and remove them when the user inputs the correct letter?

I'm having difficulty in adding underscores in my program. Also what is troubling me is that I can't seem to figure out how to remove the underscores when the user inputs the correct letter.
class Game
attr_reader :guess_count, :is_over, :word_length
def initialize (secret_word)
#secret_word = secret_word
#guess_count = 0
#is_over = false
#word_length = secret_word.length
end
def check_word(guess)
#guess_count += 1
if #secret_word == guess
puts "Congratulations!"
#is_over = true
else
#is_over = false
puts "Sorry, try again!"
end
end
def subtract_guess_count
counter = #word_length - #guess_count
end
end
puts "User 1, What is your secret word?"
secret_word = gets.chomp
anything = Game.new(secret_word)
while !anything.is_over
puts "User 2, Guess the secret word"
guess = gets.chomp
anything.check_word(guess)
if anything.subtract_guess_count == 0
puts "You lose! the correct word was #{secret_word}"
exit!
end
if anything.is_over == false
puts "You have #{anything.subtract_guess_count} left!"
end
end
Major Edit
To create a string of underscores you can do this:
word = ""
1.upto(#secret_word.length) do
word << "_"
end
To replace a character with an underscore (and vice versa) in a ruby string you can use the syntax:
word[i] = "_"
To print a word with spaces between each letter you can use the following:
array = word.split(//)
array.join(" ")
For your code a check_letter function could be useful:
def check_letter (guess)
if (#secret_word[guess])
for i in 0..((#secret_word.length) -1 )
if #secret_word[i] == guess
#progress[i] = guess
end
end
end
show_progress
check_word(#progress)
end
Working code
#! /usr/bin/env ruby
#
class Game
attr_reader :guess_count, :is_over, :word_length, :progress
def initialize (secret_word)
#secret_word = secret_word
#guess_count = 0
#is_over = false
#word_length = secret_word.length
#progress = ""
1.upto(secret_word.length) do
#progress << "_"
end
end
def check_word(guess)
if #secret_word == guess
puts "Congratulations!"
#is_over = true
else
#is_over = false
puts "Sorry, try again!"
end
end
def check_letter (guess)
if (#secret_word[guess])
for i in 0..((#secret_word.length) -1 )
if #secret_word[i] == guess
#progress[i] = guess
end
end
end
show_progress
check_word(#progress)
end
def show_progress
array = #progress.split(//)
word = ""
array.each do |letter|
word << letter + " "
end
puts word
end
def one_less_guess
#guess_count += 1
end
def subtract_guess_count
counter = #word_length - #guess_count
end
end
puts "User 1, What is your secret word?"
secret_word = gets.chomp
anything = Game.new(secret_word)
while !anything.is_over
puts "User 2, Guess the secret word"
guess = gets.chomp
anything.one_less_guess
if guess.length == 1
anything.check_letter(guess)
else
anything.check_word(guess)
end
if anything.subtract_guess_count == 0
puts "You lose! the correct word was #{secret_word}"
exit!
end
if anything.is_over == false
puts "You have #{anything.subtract_guess_count} left!"
end
end

Can't convert Fixnum into array (TypeError) Ruby

I'm getting the error:
minesweeper.rb:32:in '|': can't convert Fixnum into Array (TypeError)
from minesweeper.rb:32:in 'block in create_hint_board'
from minesweeper.rb:31:in 'each_index'
from minesweeper.rb:31:in 'create_hint_board'
from minesweeper.rb:68:in '(main)'
when attempting to check a 2D array for a value, and adding 1 to all cells adjacent to that index location. The error occurs at subarray2 = board|i|. I'm trying to iterate over the entire 2D array
The entire code is
#def load_board(file)
# gameboard = File.readlines(file)[1..-1]
# gameboard.map! do |line|
# line.split.map(&:to_s)
# end
# $globalarray = gameboard
#end
$globalarray = [['*','.','.','.'],['.','.','*','.'],['.','.','.','.']]
def pp_board(board)
puts Array.new(board[0].size*2+1, '-').join('')
board.each do |row|
puts "|" + row.join("|") + "|"
puts Array.new(row.size*2+1, '-').join('')
end
end
def create_hint_board(board)
board = $globalarray
$globalarray.each_index do |i|
subarray = $globalarray[i]
subarray.each_index do |j|
if $globalarray[i][j] != '*'
board[i][j].to_i
board[i][j] = 0
end
puts "#{String(i)},#{String(j)} is #{board[i][j]}"
end
end
board.each_index do |i|
subarray2 = board|i|
subarray2.each_index do |j|
if board[i][j] == '*'
board[i+1][j] = board[i+1][j]+1
board[i+1][j+1] = board[i+1][j+1]+1
board[i+1][j-1] = board[i+1][j-1]+1
board[i][j-1] = board[i][j-1]+1
board[i][j+1] = board[i][j+1]+1
board[i-1][j] = board[i-1][j]+1
board[i-1][j+1] = board[i-1][j+1]+1
board[i-1][j-1] = board[i-1][j-1]+1
end
end
end
puts "new array is "
puts board
end
=begin
#def copy_to_blank(board)
# $newarrayblank = $newarray
# $newarrayblank.each_index do |i|
# subarray = $newarrayblank[i]
# subarray.each_index do |j|
# $newarrayblank[i][j] = '.'
# puts "#{String(i)},#{String(j)} is #{$newarrayblank[i][j]}"
# end
# end
#end
#load_board("mines.txt")
blank = [[]]
=end
puts "Original array is"
puts $globalarray
create_hint_board($globalarray)
#pp_board($globalarray)
#create_hint_board($globalarray)
#puts "new array is"
#pp_board($newarray)
#puts "new blank board is"
#copy_to_blank(blank)
#puts $newarrayblank
#pp_board($newarrayblank)
=begin
puts "Input Guess"
value1 = gets.split(" ")
row_guess = value1[0].to_i
col_guess = value1[1].to_i
puts $newarray[row_guess][col_guess]
while $newarray[row_guess][col_guess] != '*'
if $newarray[row_guess][col_guess] != '*'
puts "You guessed row #{row_guess} and column #{col_guess}."
puts $newarray[row_guess][col_guess]
#$newarrayblank[row_guess][col_guess] = $newarray[row_guess][col_guess]
#pp_board($newarrayblank)
puts "Input your guess in coordinates, separated by a blank space, or press q to quit."
value1 = gets.split(" ")
row_guess = value1[0].to_i
col_guess = value1[1].to_i
elsif $newarray[row_guess][col_guess] == '*'
puts "You guessed row #{row_guess} and column #{col_guess}."
puts "You hit a mine!"
puts "Game Over"
end
end
=end
The area giving me trouble is
board.each_index do |i|
subarray2 = board|i|
subarray2.each_index do |j|
if board[i][j] == '*'
board[i+1][j] = board[i+1][j]+1
board[i+1][j+1] = board[i+1][j+1]+1
board[i+1][j-1] = board[i+1][j-1]+1
board[i][j-1] = board[i][j-1]+1
board[i][j+1] = board[i][j+1]+1
board[i-1][j] = board[i-1][j]+1
board[i-1][j+1] = board[i-1][j+1]+1
board[i-1][j-1] = board[i-1][j-1]+1
end
end
end
I've also tried moving the addition section above, as an elsif statement below the if, like so
def create_hint_board(board)
board = $globalarray
$globalarray.each_index do |i|
subarray = $globalarray[i]
subarray.each_index do |j|
if $globalarray[i][j] != '*'
board[i][j].to_i
board[i][j] = 0
elsif board[i][j] == '*'
board[i+1][j] = board[i+1][j]+1
board[i+1][j+1] = board[i+1][j+1]+1
board[i+1][j-1] = board[i+1][j-1]+1
board[i][j-1] = board[i][j-1]+1
board[i][j+1] = board[i][j+1]+1
board[i-1][j] = board[i-1][j]+1
board[i-1][j+1] = board[i-1][j+1]+1
board[i-1][j-1] = board[i-1][j-1]+1
end
end
puts "#{String(i)},#{String(j)} is #{board[i][j]}"
end
end
This results in the error message:
minesweeper.rb:28:in '+': can't convert Fixnum into String (TypeError)
from minesweeper.rb:28:in 'block (2 levels) in create_hint_board'
from minesweeper.rb:28:in 'each_index'
from minesweeper.rb:28:in 'block in create_hint_board'
from minesweeper.rb:28:in 'each_index'
from minesweeper.rb:28:in 'create_hint_board'
from minesweeper.rb:28:in '(main')
The issue is at following line
subarray2 = board|i|
You are doing:
board.each_index do |i|
And in following line you are trying to get the value of board at that index. To achive this you should do:
subarray2 = board[i]
At last, there is a better way to achieve this by using each_with_index.
Eg:
board.each_with_index do |v, i|
subarray2 = v
...
end

Resources