Ruby: variable acting as nul when set to integer - ruby

After a good 10 minutes of trying to come up with a more informative title, I ran out of ideas.
I have 2 prolems. The first is that whenever I try to input a position for pos_in, it registers as nul when run through the case statement that determines what m_index will be for that turn.
The second is that whenever the AI takes a turn, it always selects 1 1.
My question is: is there some way to fix this? I've tried switching the input types to no avail and I'm completely clueless on what to do.
My code:
$moves = ["x", "o"]
$move = 1
m_index = 0
$spots = [" ", " ", " ", " ", " ", " ", " ", " ", " "]
possiblesx = (1..3)
possiblesy = (1..3)
def board
puts """
TicTacToe 1.5 by Touka
#{$spots[0]}|#{$spots[1]}|#{$spots[2]}
-----
#{$spots[3]}|#{$spots[4]}|#{$spots[5]}
-----
#{$spots[6]}|#{$spots[7]}|#{$spots[8]}
move: #{$c_move}
"""
end
def ai_move
if $spots[3, 6] == "x" || $spots[4, 8] == "x" || $spots[1, 2] == "x"
pos_in = "1 1"
elsif $spots[1, 3] == "x" || $spots[4, 7] == "x"
pos_in = "1 2"
elsif $spots[0, 1] == "x" || $spots[6, 4] == "x" || $spots[5, 8] == "x"
pos_in = "1 3"
elsif $spots[0, 6] == "x" || $spots[4, 5] == "x"
pos_in = "2 1"
elsif $spots[0, 8] == "x" || $spots[1, 7] == "x" || $spots[2, 6] == "x" || $spots[5, 3] == "x"
pos_in = "2 2"
elsif $spots[2, 8] == "x" || $spots[3, 4] == "x"
pos_in = "2 3"
elsif $spots[0, 3] == "x" || $spots[2, 4] == "x" || $spots[7, 8] == "x"
pos_in = "3 1"
elsif $spots[1, 4] == "x" || $spots[6, 8] == "x"
pos_in = "3 2"
elsif $spots[6, 7] == "x" || $spots[0, 4] == "x" || $spots[2, 5] == "x"
pos_in = "3 3"
else
aimx = possiblesx.to_a.sample
aimy = possiblesy.to_a.sample
pos_in = "#{aimx} #{aimy}"
end
end
def game
system "cls"
if $move == 1
$move = 0
else
$move = 1
end
$c_move = $moves[$move]
board
if $opp == 2 && $c_move == "o"
ai_move
else
puts "Enter move coordinates (ex \"1 1\"):"
pos_in = gets.chomp
end
case pos_in
when ["1 1"]
m_index = 0
when ["1 2"]
m_index = 1
when ["1 3"]
m_index = 2
when ["2 1"]
m_index = 3
when ["2 2"]
m_index = 4
when ["2 3"]
m_index = 5
when ["3 1"]
m_index = 6
when ["3 2"]
m_index = 7
when ["3 3"]
m_index = 8
end
if $spots[m_index] == " "
$spots[m_index] = "#{$c_move}"
else
if $opp == 2 && $c_move == "o"
$move = $c_move
game
end
system "cls"
puts "
Error.
Re-enter $move."
sleep(3)
system "cls"
$move = c_$move
game
end
system "cls"
game
end
puts "Play vs. [1]Friend or [2]AI"
$opp = gets.to_i
game

The problem you had was with your scoping, along with the fact you were trying to match a string to an array as Piotr Kruczek pointed out.
Make the pos_in variable global and change the when statements from an array input to a string.
Here is the working version of your code:
$moves = ["x", "o"]
$move = 1
m_index = 0
$spots = [" ", " ", " ", " ", " ", " ", " ", " ", " "]
$pos_in = nil
def board
puts """
TicTacToe 1.5 by Touka
#{$spots[0]}|#{$spots[1]}|#{$spots[2]}
-----
#{$spots[3]}|#{$spots[4]}|#{$spots[5]}
-----
#{$spots[6]}|#{$spots[7]}|#{$spots[8]}
move: #{$c_move}
"""
end
def ai_move
if $spots[3, 6] == "x" || $spots[4, 8] == "x" || $spots[1, 2] == "x"
$pos_in = "1 1"
elsif $spots[1, 3] == "x" || $spots[4, 7] == "x"
$pos_in = "1 2"
elsif $spots[0, 1] == "x" || $spots[6, 4] == "x" || $spots[5, 8] == "x"
$pos_in = "1 3"
elsif $spots[0, 6] == "x" || $spots[4, 5] == "x"
$pos_in = "2 1"
elsif $spots[0, 8] == "x" || $spots[1, 7] == "x" || $spots[2, 6] == "x" || $spots[5, 3] == "x"
$pos_in = "2 2"
elsif $spots[2, 8] == "x" || $spots[3, 4] == "x"
$pos_in = "2 3"
elsif $spots[0, 3] == "x" || $spots[2, 4] == "x" || $spots[7, 8] == "x"
$pos_in = "3 1"
elsif $spots[1, 4] == "x" || $spots[6, 8] == "x"
$pos_in = "3 2"
elsif $spots[6, 7] == "x" || $spots[0, 4] == "x" || $spots[2, 5] == "x"
$pos_in = "3 3"
else
aimx = (1..3).to_a.sample
aimy = (1..3).to_a.sample
$pos_in = "#{aimx} #{aimy}"
end
end
def game
m_index = nil
system "cls"
if $move == 1
$move = 0
else
$move = 1
end
$c_move = $moves[$move]
board
if $opp == 2 && $c_move == "o"
ai_move
else
puts "Enter move coordinates (ex \"1 1\"):"
$pos_in = gets.chomp
end
case $pos_in
when "1 1"
p m_index = 0
when "1 2"
p m_index = 1
when "1 3"
p m_index = 2
when "2 1"
p m_index = 3
when "2 2"
p m_index = 4
when "2 3"
p m_index = 5
when "3 1"
p m_index = 6
when "3 2"
p m_index = 7
when "3 3"
p m_index = 8
end
if $spots[m_index] == " "
$spots[m_index] = "#{$c_move}"
else
if $opp == 2 && $c_move == "o"
$move = $c_move
game
end
system "cls"
puts "
Error.
Re-enter $move."
sleep(3)
system "cls"
$move = c_$move
game
end
system "cls"
game
end
puts "Play vs. [1]Friend or [2]AI"
$opp = gets.to_i
game

You assign
pos_in = "1 1"
as a String, while in you case statement you check for Array
case pos_in
when ["1 1"]

As Stated by Piotr and Menelik, there were a few obvious errors in this. Oddly enough, the structure of ai_move was one of those. The working code is as follows. It's not the cleanest thing ever and there are some bugs to iron out but it does it's job.
$moves = ["x", "o"]
$move = 1
m_index = 0
$spots = Array.new(9, " ")
$possiblesx = [1, 2, 3]
$possiblesy = [1, 2, 3]
def board
puts """
TicTacToe 1.5 by Touka
#{$spots[0]}|#{$spots[1]}|#{$spots[2]}
-----
#{$spots[3]}|#{$spots[4]}|#{$spots[5]}
-----
#{$spots[6]}|#{$spots[7]}|#{$spots[8]}
move: #{$c_move}
"""
end
def ai_move
if $spots[3] == "x" && $spots[6] == "x"
$pos_in = "1 1"
elsif $spots[4] == "x" && $spots[8] == "x"
$pos_in = "1 1"
elsif $spots[1] == "x" && $spots[2] == "x"
$pos_in = "1 1"
elsif $spots[1] == "x" && $spots[3] == "x"
$pos_in = "1 2"
elsif $spots[4] == "x" && $spots[7] == "x"
$pos_in = "1 2"
elsif $spots[0] == "x" && $spots[1] == "x"
$pos_in = "1 3"
elsif $spots[6] == "x" && $spots[4] == "x"
$pos_in = "1 3"
elsif $spots[5] == "x" && $spots[8] == "x"
$pos_in = "1 3"
elsif $spots[0] == "x" && $spots[6] == "x"
$pos_in = "2 1"
elsif $spots[4] == "x" && $spots[5] == "x"
$pos_in = "2 1"
elsif $spots[0] == "x" && $spots[8] == "x"
$pos_in = "2 2"
elsif $spots[1] == "x" && $spots[7] == "x"
$pos_in = "2 2"
elsif $spots[2] == "x" && $spots[6] == "x"
$pos_in = "2 2"
elsif $spots[5] == "x" && $spots[3] == "x"
$pos_in = "2 2"
elsif $spots[2] == "x" && $spots[8] == "x"
$pos_in = "2 3"
elsif $spots[3] == "x" && $spots[4] == "x"
$pos_in = "2 3"
elsif $spots[0] == "x" && $spots[3] == "x"
$pos_in = "3 1"
elsif $spots[2] == "x" && $spots[4] == "x"
$pos_in = "3 1"
elsif $spots[7] == "x" && $spots[8] == "x"
$pos_in = "3 1"
elsif $spots[1] == "x" && $spots[4] == "x"
$pos_in = "3 2"
elsif $spots[6] == "x" && $spots[8] == "x"
$pos_in = "3 2"
elsif $spots[6] == "x" && $spots[7] == "x"
$pos_in = "3 3"
elsif $spots[0] == "x" && $spots[4] == "x"
$pos_in = "3 3"
elsif $spots[2] == "x" && $spots[5] == "x"
$pos_in = "3 3"
else
aimx = $possiblesx.sample
aimy = $possiblesy.sample
$pos_in = "#{aimx} #{aimy}"
end
end
def game
system "cls"
if $move == 1
$move = 0
else
$move = 1
end
$c_move = $moves[$move]
board
if $opp == 2 && $c_move == "o"
ai_move
else
puts "Enter move coordinates (ex \"1 1\"):"
$pos_in = gets.chomp
end
case $pos_in
when "1 1"
m_index = 0
when "1 2"
m_index = 1
when "1 3"
m_index = 2
when "2 1"
m_index = 3
when "2 2"
m_index = 4
when "2 3"
m_index = 5
when "3 1"
m_index = 6
when "3 2"
m_index = 7
when "3 3"
m_index = 8
end
if $spots[m_index] == " "
$spots[m_index] = "#{$c_move}"
else
if $opp == 2 && $c_move == "o"
$move = $c_move
game
end
system "cls"
puts "
Error.
Re-enter move."
sleep(3)
system "cls"
$move = $c_move
game
end
system "cls"
game
end
puts "Play vs. [1]Friend [2]AI"
$opp = gets.to_i
game

Related

Among Us Random Generator

I'm having trouble with my code here what it's supposed to do is generate a number from 1 to 6 and than ask you who you think the imposter is after it asks you it waits for input and than checks for the input and the random number that was generated if the input is Red and the random number was 1 it would say that red is the imposter and so on with Orange and 2 Green and 3 Yelow and 4 Cyan with 5 and Black with 6 but the problem is that if you put anything that isn't red EX: Orange it just stops for no reason. What did I do wrong with the code? Please help.
susas = rand (1..6)
puts "Who is the imposter?"
sleep (1)
puts "Is it Red, Orange, Green, Yellow, Cyan, Or Black (use capital format EX:Red)"
answr = gets.chomp
if answr == "Red" && susas == 1
puts "Red was the imposter"
elsif answr == "Red" && susas != 1
puts "Red was not the imposter you failed"
if answr == "Orange" && susas == 2
puts "Orange was the imposter"
elsif answr == "Orange" && susas != 2
puts "Orange was not the imposter you failed"
if answr == "Green" && susas == 3
puts "Green was the imposter"
elsif answr == "Green" && susas != 3
puts "Green was not the imposter you failed"
if answr == "Yellow" && susas == 4
puts "Yellow was the imposter"
elsif answr == "Yellow" && susas != 4
puts "Yellow was not the imposter you failed"
if answr == "Cyan" && susas == 5
puts "Cyan was the imposter"
elsif answr == "Cyan" && susas != 5
puts "Cyan was not the imposter you failed"
if answr == "Black" && susas == 6
puts "Black was the imposter"
elsif answr == "Black" && susas != 6
puts "Black was not the imposter you failed"
end
end
end
end
end
end
Here is a repl.it link https://repl.it/#Student_Aiden_K/SmoothFaithfulComputerscience#main.rb
if you put anything that isn't red EX: Orange it just stops for no reason. What did I do wrong with the code?
You have two main branches:
if answr == "Red" && susas == 1
puts "Red was the imposter"
elsif answr == "Red" && susas != 1
puts "Red was not the imposter you failed"
# anything else
end
The other colors are all under the elsif branch but Ruby will not reach them because answr == "Red" will be false for all colors beside red.
What you want is more elsif's on the same level:
if answr == "Red" && susas == 1
puts "Red was the imposter"
elsif answr == "Red" && susas != 1
puts "Red was not the imposter you failed"
elsif answr == "Orange" && susas == 2
puts "Orange was the imposter"
elsif answr == "Orange" && susas != 2
puts "Orange was not the imposter you failed"
# ...
end
Needless to say, there's a lot of repetition in your code. You should try to reduce that.
You could for example add a hash to map color names to numbers:
colors = {
'Red' => 1, 'Orange' => 2, 'Green' => 3,
'Yellow' => 4, 'Cyan' => 5, 'Black' => 6
}
Then fetch the number for the given answer:
answer = gets.chomp
number = colors[answer]
And have just one if to check whether it is correct or not:
if number == susas
puts "#{answer} was the imposter"
else
puts "#{answer} was not the imposter you failed"
end

Condition operators don't give correct result

I am trying to develop a battleship game in console. I need input of coordinates that guess where the game is. I did it:
#array1 and array2 are not obvious boards of player1 and player2 respectly
array1 = [ ['*', 'A', 'B', 'C', 'D', 'E'],['1',0, 1, 1, 1, 0], ['2',1, 0, 0, 0, 0], ['3',1, 0, 1, 0, 0], ['4',0, 0, 1, 0, 1], ['5',0, 0, 0, 0, 0] ]
array2 = [ ['*', 'A', 'B', 'C', 'D', 'E'],['1',1, 0, 1, 1, 0], ['2',0, 0, 0, 0, 1], ['3',0, 1, 0, 0, 1], ['4',0, 1, 0, 0, 1], ['5',0, 0, 0, 0, 0] ]
#arr1 and arr2 are obvious boards of player1 and player2 respectly
arr1 = [['*', 'A', 'B', 'C', 'D', 'E'],['1','.','.','.','.','.'],['2','.','.','.','.','.'],['3','.','.','.','.','.'],['4','.','.','.','.','.'],['5','.','.','.','.','.']]
arr2 = [['*', 'A', 'B', 'C', 'D', 'E'],['1', '.','.','.','.','.'],['2', '.','.','.','.','.'],['3', '.','.','.','.','.'],['4', '.','.','.','.','.'],['5', '.','.','.','.','.']]
coor = ['A', 'B', 'C', 'D', 'E']
#board1 and board2 are the final boards of player1 and player2
#this arrays will be seen during game
#every changes will be seen on these boards
board1 = arr1.map { |x| x.join(' ') }
board2 = arr2.map { |x| x.join(' ') }
#num1 and num2 are the numbers of the parts of ships respectively
num1 = 8
num2 = 8
#count1 and count2 are the numbers of poped ship parts respectively
count1 = 0
count2 = 0
#Starting of the game and the printing the board
#If we type "start" game will be started
#"Reset" game will be ended
#If we type words except "start" or "reset" program will ask "Do you want to start? (start/reset)" again
while true do
puts "Welcome to the game!!!"
puts "Do you want to start? (start/reset):"
respond = gets.chomp
if respond == 'start'
puts "\n"
puts "Player ONE"
puts board1
puts "\n"
puts "Player TWO"
puts board2
while true do
#Burada while ile player1 in shertleri olacaq
while true do
puts "\n"
puts "Turn - Player ONE"
puts "Enter coordinate: "
a = gets.chomp
a1 = a.split('')
b = coor.index(a1[0]) +1
col1 = b
row1= a1[1].to_i
if a == '""'
puts "You have to enter any coordinate"
break
elsif array1[row1][col1] == 'X' or array1[row1][col1] == '0'
puts "You have already bumped this coordinate!"
elsif col1<1 or col1>5 or row1>5 or row1<1
puts "This coordinate is out of board"
else
if array1[row1][col1] == 1
count1 = count1 + 1
arr1[row1][col1] = "X"
elsif array1[row1][col1] == 0
arr1[row1][col1] = "0"
end
board1 = arr1.map { |x| x.join(' ') }
puts "\n"
puts "Player ONE"
puts board1
puts "\n"
puts "Player TWO"
puts board2
if count1 == num1
puts "Player ONE won the game!"
break
end
end
break
end
while true do
#Burada while ile player2 in shertleri olacaq
puts "\n"
puts "Turn - Player TWO"
puts "Enter coordinate: "
c = gets.chomp
c1 = c.split('')
d = coor.index(c1[0]) + 1
col2 = d
row2= c1[1].to_i
if c == '""'
puts "You have to enter any coordinate"
break
elsif array2[row2][col2] == 'X' or array2[row2][col2] == '0'
puts "You have already bumped this coordinate!"
elsif col2<1 or col2>5 or row2>5 or row2<1
puts "This coordinate is out of board"
else
if array2[row2][col2] == 1
count2 = count2 + 1
arr2[row2][col2] = "X"
elsif array2[row2][col2] == 0
arr2[row2][col2] = "0"
end
board2 = arr2.map { |x| x.join(' ') }
puts "Player ONE"
puts board1
puts "\n"
puts "Player TWO"
puts board2
if count2 == num2
puts "Player TWO won the game!"
break
end
end
break
end
end
elsif respond == 'reset'
puts "You are off the game"
break
else
puts "\n"
puts "Answer can be only {start} or {reset}"
end
end
There are some problems, and I added if elsif else conditions to the code to solve them. One of them is for entering coordinates out of board, the second one is for not entering any coordinate, and the last one is for bumped coordinate. If these three condition are bypassed, the players can enter any coordinate.
But these codes don't work. When I check these three conditions, the result is an error. Can anyone tell me what the problem is with these conditions? Why don't they give suitable result?
When entering A8 as a value, the error you get is:
battleship.rb:54:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)
This is line 54:
elsif array1[row1][col1] == 'X' or array1[row1][col1] == '0'
In this case, the error is that array1["8"] is nil, and nil["A"] is undefined. An easy fix is to move line 56 above this one (the one that checks whether the input is actually within the board range).
elsif col1<1 or col1>5 or row1>5 or row1<1
If you do that, then since 8 is greater than 5, you'll get the "out of board" message rather than an error.
The other error you mention is when you put in an empty string. In that case the error is:
battleship.rb:48:in `<main>': undefined method `+' for nil:NilClass (NoMethodError)
Line 48 says:
b = coor.index(a1[0]) +1
In this case, the index is returning nil, and you can't add 1 to nil.
One way to fix this is to move the section a few lines down that checks whether a is blank to before line 48.

Solving foobar in Ruby?

So far I have been able to get the numbers to print properly but I don't know how to loop them.
puts "Please enter a number"
val1 = gets.to_i
val2 = val1 % 3
val3 = val1 % 5
def ordinal(a,b,c)
if b == 0 && c == 0
return "foobar"
elsif b == 0
return "foo"
elsif c == 0
return "bar"
else
return a
end
end
val5 = ordinal(val1,val2,val3)
puts "#{val5}"
I also made a loop that works but it won't recognize strings.
n = 0
x = gets.to_i
while n != x
puts "#{n}"
n = n + 1
end
How do I combine my method and loop? Or is there any other way to solve this? But I would prefer if you solve it using my code IF its any good off course so that I can understand it better.
As par your comments, the loop part is easy when leveraging Integer#times.
This is what you have that works for you:
puts "Please enter a number"
val1 = gets.to_i
val2 = val1 % 3
val3 = val1 % 5
def ordinal(a,b,c)
if b == 0 && c == 0
return "footer"
elsif b == 0
return "foo"
elsif c == 0
return "bar"
else
return a
end
end
val5 = ordinal(val1,val2,val3)
puts "#{val5}"
Right now you're just running through the final number. Try using the Integer#times to run a loop up to the number...:
puts "Please enter a number"
num = gets.to_i
num.times do |a|
a += 1 # counting is done from 0 to n-1
b = a % 3
c = a % 5
if b == 0 && c == 0
print "foobar "
elsif b == 0
print "foo "
elsif c == 0
print "bar "
else
print "#{a} "
end
end
print "\n"
Personally I would probably have written this a bit differently, but I guess it's sound enough.
I would probably write something messy because I hate long if...else statements...:
def foo_bar n
n.times {|i| i+=1; print( (i%15==0 && "FooBar ") || (i%3==0 && "Foo ") || (i%5 ==0 && "Bar ") || ("#{i} ") ) }
print "\n"
end
puts "Enter number:"
foo_bar gets.to_i
You can do this too:
def foobar n
n.times do |i|
i += 1
num = ""
num << "Foo" if i % 3 == 0
num << "Bar" if i % 5 == 0
num = i.to_s if num == ""
puts num
end
end
foobar 15
The logic is simpler than Myst's.
You don't need to test if it's a factor of 15.
Output:
1
2
Foo
4
Bar
Foo
7
8
Foo
Bar
11
Foo
13
14
FooBar
=> 15

Using `each` to check whether all values are the same

I'm trying to evaluate whether every space value is equal to either "X" or "O". Can I use each to do that? Is there a better way?
if #spaces.each {|x| x=="O" || x=="X"}
#winner = true
puts "It's a tie!"
break
end
ETA: all? doesn't seem to be working, either. I got this error referring to the line with the block:
tictac.rb:47: syntax error, unexpected '|', expecting '}'
{|x| x=="O" || x=="X"}
^
tictac.rb:47: syntax error, unexpected '}', expecting keyword_end
Here is the entire TicTacToe I'm working on:
class Board
def initialize
#spaces = [1, 2, 3, 4, 5, 6, 7, 8, 9]
self.print_board
#winner = false
#turn = "X"
end
def print_board
puts
puts " " + #spaces[0].to_s + " " + #spaces[1].to_s + " " + #spaces[2].to_s
puts " " + #spaces[3].to_s + " " + #spaces[4].to_s + " " + #spaces[5].to_s
puts " " + #spaces[6].to_s + " " + #spaces[7].to_s + " " + #spaces[8].to_s
puts
end
def mark(turn, move)
space = #spaces.index(move)
#spaces[space] = turn
self.print_board
end
def play
while #winner == false
puts "where would you like to put your #{#turn}?"
move = gets.chomp.to_i
self.mark(#turn, move)
if
#spaces[0] == #turn && #spaces[1] == #turn && #spaces[2] == #turn ||
#spaces[3] == #turn && #spaces[4] == #turn && #spaces[5] == #turn ||
#spaces[6] == #turn && #spaces[7] == #turn && #spaces[8] == #turn ||
#spaces[0] == #turn && #spaces[3] == #turn && #spaces[6] == #turn ||
#spaces[1] == #turn && #spaces[4] == #turn && #spaces[7] == #turn ||
#spaces[2] == #turn && #spaces[5] == #turn && #spaces[8] == #turn ||
#spaces[0] == #turn && #spaces[4] == #turn && #spaces[8] == #turn ||
#spaces[2] == #turn && #spaces[4] == #turn && #spaces[6] == #turn
#winner = true
puts "#{#turn} is the winner!"
break
elsif #spaces.all?
{|x| x=="O" || x=="X"}
#winner = true
puts "It's a tie!"
break
else
#turn == "X"? #turn = "O" : #turn = "X"
end
end
end
end
game = Board.new
game.play
I marked an answer that worked, and I guess all? was better than my each, but I'm still curious why changing it to all? didn't seem to work.
#spaces.all? { |x| x=="O" || x=="X" }
You cannot put a newline between a method call and its block. That makes Ruby think you're calling the method without a block and defining a Hash.
All elements of #spaces will be "O" or "X" if
(#spaces - ["O", "X"]).empty?
is true.
#spaces = ["O", "X", "X", "O"]
(#spaces - ["O", "X"]).empty?
#=> true
#spaces = ["O", "X", "X", "O", "cat"]
(#spaces - ["O", "X"]).empty?
#=> false
Chain Array#Uniq and Array#Size
Refactor your check into a method which takes an array of box entries (e.g. "X" or "O"), or a variable holding such an array. The method will return true if all letters in the array are the same, because there will only be one unique character. For example:
def check_spaces letters
true if letters.uniq.size == 1
end
check_spaces %w[X X X] #=> true
check_spaces %w[O O O] #=> true
check_spaces %w[O X O] #=> nil
If you do this, you can even assign the result of #check_spaces directly to #winner, like so:
#winner = check_spaces %w[X X X]
#=> true
#winner = check_spaces %w[X O X]
#=> nil

While loop continues despite conditions not being met?

When I run the game and type either "yes" or "no" at the end, it always reverts back to the start of the while loop at line 41, when the conditions for both that and the containing loop are not met.
replay = true
while replay
#Pre-var
print "What difficulty? (1 for easy, 2 for medium, or 3 for hard): "
difficulty = gets.chomp.to_i
until difficulty == 1 || difficulty == 2 || difficulty == 3 do
print "Please type either 1, 2, or 3: "
difficulty = gets.chomp.to_i
end
#Variables
if difficulty == 1
r = Random.new
number = r.rand(100..1000)
puts "You have 15 guesses. "
print "Guess a number with three digits: "
within_num = 50
elsif difficulty == 2
r = Random.new
number = r.rand(1000..10000)
puts "You have 15 guesses. "
print "Guess a number with four digits: "
within_num = 500
elsif difficulty == 3
r = Random.new
number = r.rand(10000..100000)
puts "You have 15 guesses. "
print "Guess a number with five digits: "
within_num = 5000
end
guess = ""
num_guess = 0
guess_array = Array.new
array_location = 0
count_through = 0
array_print = count_through - 1
replay_inner = true
#Body
puts number
while num_guess <= 14 || replay_inner == true #Keeping as <= 14 as to avoid unnecessarily rewriting code, still gives 15 guesses
guess = gets.chomp.to_i
if guess > number * 2
print "That is more than double the number. Guess again: "
elsif guess < number / 2
print "That is less than half the number. Guess again: "
elsif guess > number && guess < number + within_num #within_num: 50 for easy, 500 for medium, 5000 for hard
print "You are close. That is too big. Guess again: "
elsif guess < number && guess > number - within_num
print "You are close. That is too small. Guess again: "
elsif guess < number
print "That is too small. Guess again: " #Hinting the user to how close they are.
elsif guess > number
print "That is too big. Guess again: "
elsif guess == number
puts "Congragulations! You win!"
print "Your "
print guess_array.length
print " incorrect guesses were: "
if num_guess == 0
sleep(0.5)
print "... Oh."
else
while count_through < num_guess #Loop to relay user's guesses with a delay of 0.5 seconds
print guess_array[count_through]
if count_through == num_guess - 2
print ", and "
elsif count_through == num_guess - 1
puts ". "
else
print ", "
end
count_through += 1
sleep(0.5)
end
puts "Would you like to play again? (yes/no)"
replay_answer = gets.chomp
until replay_answer == "yes" || replay_answer == "y" || replay_answer == "no" || replay_answer == "n" do
print "Please answer with yes, y, no, or n: "
replay_answer = gets.chomp
end
if replay_answer == "yes" || replay_answer == "y"
replay = true
puts "yes"
elsif replay_answer == "no" || replay_answer == "n" #Determining whether or not to replay
replay = false
puts "no"
end
end
end
guess_array.push guess
num_guess += 1
#puts num_guess
#puts guess_array[array_location]
array_location += 1
if num_guess >= 15 && guess != number
puts "Sorry, you lost. "
print "Your "
print guess_array.size
print " guesses were: "
while count_through < num_guess
print guess_array[count_through] #Same as loop above; for when player fails to guess correctly
if count_through == num_guess - 2
print ", and "
elsif count_through == num_guess - 1
puts ". "
else
print ", "
end
count_through += 1
sleep(0.5)
end
puts "Would you like to play again? (yes/no)"
replay_answer = gets.chomp
until replay_answer == "yes" || replay_answer == "y" || replay_answer == "no" || replay_answer == "n" do
print "Please answer with yes, y, no, or n: "
replay_answer = gets.chomp
end
if replay_answer == "yes" || replay_answer == "y"
replay = true
replay_inner = true
puts "yes"
elsif replay_answer == "no" || replay_answer == "n" #Determining whether or not to replay
replay = false
replay_inner = false
puts "no"
end
end
end
I think the condition in the while should be:
numberGuess<=14 && replay_inner == true
The way you and especially your fellow programmers will find this and future bugs is by properly commenting your code, e.g.:
# ask the user about an optional replay
replay_answer = gets.chomp
# only accept yes/y/no/n
until replay_answer == "yes" || replay_answer == "y" || replay_answer == "no" || replay_answer == "n" do
print "Please answer with yes, y, no, or n: "
replay_answer = gets.chomp
end
## recoded this to a case, as I think it's much nicer :)
# determining whether to replay or to stop the loop
case replay_answer
when "yes", "y"
replay = true
puts "yes"
when "no", "n"
replay = false
puts "no"
replay_inner = false
end
I've modified a little your code, you should really use some decent editor with at least syntax errors highlighting. I've changed OR to AND condition in inner loop (comment in code) and added way of breaking from it when guessed number. I've also removed second occurence of code responsible of playing again, remember, DRY yourself.
replay = true
while replay
p replay
#Pre-var
print "What difficulty? (1 for easy, 2 for medium, or 3 for hard): "
difficulty = gets.chomp.to_i
until difficulty == 1 || difficulty == 2 || difficulty == 3 do
print "Please type either 1, 2, or 3: "
difficulty = gets.chomp.to_i
end
#Variables
if difficulty == 1
r = Random.new
number = r.rand(100..1000)
puts "You have 15 guesses. "
print "Guess a number with three digits: "
within_num = 50
elsif difficulty == 2
r = Random.new
number = r.rand(1000..10000)
puts "You have 15 guesses. "
print "Guess a number with four digits: "
within_num = 500
elsif difficulty == 3
r = Random.new
number = r.rand(10000..100000)
puts "You have 15 guesses. "
print "Guess a number with five digits: "
within_num = 5000
end
guess = ""
num_guess = 0
guess_array = Array.new
array_location = 0
count_through = 0
array_print = count_through - 1
replay_inner = true
#Body
puts number
while num_guess <= 14 && replay_inner == true #Keeping as <= 14 as to avoid unnecessarily rewriting code, still gives 15 guesses
guess = gets.chomp.to_i
if guess > number * 2
print "That is more than double the number. Guess again: "
elsif guess < number / 2
print "That is less than half the number. Guess again: "
elsif guess > number && guess < number + within_num #within_num: 50 for easy, 500 for medium, 5000 for hard
print "You are close. That is too big. Guess again: "
elsif guess < number && guess > number - within_num
print "You are close. That is too small. Guess again: "
elsif guess < number
print "That is too small. Guess again: " #Hinting the user to how close they are.
elsif guess > number
print "That is too big. Guess again: "
elsif guess == number
puts "Congragulations! You win!"
print "Your "
print guess_array.length
print " incorrect guesses were: "
if num_guess == 0
sleep(0.5)
print "... Oh."
else
while count_through < num_guess #Loop to relay user's guesses with a delay of 0.5 seconds
print guess_array[count_through]
if count_through == num_guess - 2
print ", and "
elsif count_through == num_guess - 1
puts ". "
else
print ", "
end
count_through += 1
sleep(0.5)
end
end
replay_inner = false # or just `break`, you have to break somehow from inner loop here
end
guess_array.push guess
num_guess += 1
#puts num_guess
#puts guess_array[array_location]
array_location += 1
if num_guess >= 15 && guess != number
puts "Sorry, you lost. "
print "Your "
print guess_array.size
print " guesses were: "
while count_through < num_guess
print guess_array[count_through] #Same as loop above; for when player fails to guess correctly
if count_through == num_guess - 2
print ", and "
elsif count_through == num_guess - 1
puts ". "
else
print ", "
end
count_through += 1
sleep(0.5)
end
end
end
puts "\nWould you like to play again? (yes/no)"
replay_answer = gets.chomp
until replay_answer == "yes" || replay_answer == "y" || replay_answer == "no" || replay_answer == "n" do
print "Please answer with yes, y, no, or n: "
replay_answer = gets.chomp
end
if replay_answer == "yes" || replay_answer == "y"
replay = true
replay_inner = true
puts "yes"
elsif replay_answer == "no" || replay_answer == "n" #Determining whether or not to replay
replay = false
replay_inner = false
puts "no"
end
end

Resources