Trying to create a classic tic tac toe OOP in Ruby but am having trouble with my game_results() method.
I realize this is not really complete and needs some more functionality but for now im just trying to fill my board with the inputted objects from the user and outputting the filled board and winner.
When I can see on my board that we have a winner I call for the game_results() method and it gives me the correct winner but whenever a tie game occurs, I receive a error.
Anybody got any ideas or solutions to what I'm doing wrong with the operators? Btw I know all this is pretty messy, but im a beginner.
#require "pry"
class Game
attr_reader :turn
def initialize
#turn = 1
#board = { a1: " ", a2: " ", a3: " ", b1: " ", b2: " ", b3: " ", c1: " ", c2: " ", c3: " " }
end
# def start_game
# x = Game.new
# x.player_symbol
# x.player_turn
# x.check_game
# end
def intro
puts "ULTIMATE TIC TAC TOE .. in ruby!\n"
display_board
end
def player_symbol
puts "Player 1, choose your marker. X or O?\n"
i = gets.chomp.upcase
if i == "X"
#p1 = "X"
#p2 = "O"
elsif i == "O"
#p1 = "O"
#p2 = "X"
else
puts "That is not a valid player!"
end
end
def player_turn
if #turn == 1
puts "Player 1 turn."
#turn = 2
player_move(#p1)
else
puts "Player 2 turn."
#turn = 1
player_move(#p2)
end
end
def display_board
# Displays board grid using hash values.
puts " 1 2 3 "
puts "A #{#board[:a1]} | #{#board[:a2]} | #{#board[:a3]} "
puts " ---+---+---"
puts "B #{#board[:b1]} | #{#board[:b2]} | #{#board[:b3]} "
puts " ---+---+---"
puts "C #{#board[:c1]} | #{#board[:c2]} | #{#board[:c3]} "
end
def player_move(n)
# Player picks square to claim.
# Player symbol populates hash.
puts "pick move"
x = gets.chomp.downcase.to_sym
#board[x] = "#{n}" # Directs to player X/O
display_board
end
def game_results
# Determines winner, loser, or tie game
if ((#board[:a1] == #p1) && (#board[:a2] == #p1) && (#board[:a3] == #p1)) ||
((#board[:b1] == #p1) && (#board[:b2] == #p1) && (#board[:b3] == #p1)) ||
((#board[:c1] == #p1) && (#board[:c2] == #p1) && (#board[:c3] == #p1)) ||
((#board[:a1] == #p1) && (#board[:b1] == #p1) && (#board[:c1] == #p1)) ||
((#board[:a2] == #p1) && (#board[:b2] == #p1) && (#board[:c2] == #p1)) ||
((#board[:a3] == #p1) && (#board[:b3] == #p1) && (#board[:c3] == #p1)) ||
((#board[:a1] == #p1) && (#board[:b2] == #p1) && (#board[:c3] == #p1)) ||
((#board[:a3] == #p1) && (#board[:b2] == #p1) && (#board[:c1] == #p1))
puts "Player #{#p1} is the winner!"
elsif ((#board[:a1] == #p2) && (#board[:a2] == #p2) && (#board[:a3] == #p2)) ||
((#board[:b1] == #p2) && (#board[:b2] == #p2) && (#board[:b3] == #p2)) ||
((#board[:c1] == #p2) && (#board[:c2] == #p2) && (#board[:c3] == #p2)) ||
((#board[:a1] == #p2) && (#board[:b1] == #p2) && (#board[:b1] == #p2)) ||
((#board[:a2] == #p2) && (#board[:b2] == #p2) && (#board[:c2] == #p2)) ||
((#board[:a3] == #p2) && (#board[:b3] == #p2) && (#board[:c3] == #p2)) ||
((#board[:a1] == #p2) && (#board[:b2] == #p2) && (#board[:c3] == #p2)) ||
((#board[:a3] == #p2) && (#board[:b2] == #p2) && (#board[:c1] == #p2))
puts "Player #{#p2} is the winner!"
elsif ((#board[:a1] == ("X" || "O")) &&
(#board[:a2] == ("X" || "O")) &&
(#board[:a3] == ("X" || "O")) &&
(#board[:b1] == ("X" || "O")) &&
(#board[:b2] == ("X" || "O")) &&
(#board[:b3] == ("X" || "O")) &&
(#board[:c1] == ("X" || "O")) &&
(#board[:c2] == ("X" || "O")) &&
(#board[:c3] == ("X" || "O")))
# This should represent that empty elements in the hash are now filled not making a winning pair
puts "Tie Game"
else
player_turn
end
end
end
Related
In my game, I am trying to add a tie function by using else under my win determiner, but I'm having trouble. Can someone help me add a tie function into my code under the win determiner? I have tried to add else under the win determiner, but the tie will end up printing that the game has ended in a tie randomly. Some help would be appreciated, thanks!
player1 = str(input("What is player X's name?"))
print()
player2 = str(input("What is player O's name?"))
turn = 1
location = [
[' ',' ',' '],
[' ',' ',' '],
[' ',' ',' '],
]
while turn <= 9:
if turn % 2 == 1:
print()
print("It is currently " +player1+ "'s turn")
row = int(input("What row would you like to mark?"))-1
print()
col = int(input(" What column would you like to mark?"))-1
print()
while "O" in location[row][col]:
print(player1+" that spot has already been taken")
print("Please pick again")
row = int(input("What row would you like to mark?"))-1
print()
col = int(input(" What column would you like to mark?"))-1
print()
location[row][col] = "X"
print(location[0][0] + '|' + location[0][1] + '|' + location[0][2])
print("-----")
print(location[1][0] + '|' + location[1][1] + '|' + location[1][2])
print("-----")
print(location[2][0] + '|' + location[2][1] + '|' + location[2][2])
turn = turn + 1
if ((location[0][0] == 'X' and location[0][1] == 'X' and location[0][2]
== 'X') or
(location[1][0] == 'X' and location[1][1] == 'X' and location[1][2] ==
'X') or
(location[2][0] == 'X' and location[2][1] == 'X' and location[2][2] ==
'X') or
(location[0][0] == 'X' and location[1][0] == 'X' and location[2][0] ==
'X') or
(location[0][1] == 'X' and location[1][1] == 'X' and location[2][1] ==
'X') or
(location[0][2] == 'X' and location[1][2] == 'X' and location[2][2] ==
'X') or
(location[0][0] == 'X' and location[1][1] == 'X' and location[2][2] ==
'X') or
(location[0][2] == 'X' and location[1][1] == 'X' and location[2][0] ==
'X')):
print (player1+" won the game!")
turn = 10
else:
print("The game ended in a tie!")
else:
print("It is currently " +player2+ "'s turn")
row = int(input("What row would you like to mark?"))-1
print()
col = int(input(" What column would you like to mark?"))-1
print()
while "X" in location[row][col]:
print(player2+" that spot has already been taken")
print("Please pick again")
row = int(input("What row would you like to mark?"))-1
print()
col = int(input(" What column would you like to mark?"))-1
print()
location[row][col] = "O"
print(location[0][0] + '|' + location[0][1] + '|' + location[0][2])
print("-----")
print(location[1][0] + '|' + location[1][1] + '|' + location[1][2])
print("-----")
print(location[2][0] + '|' + location[2][1] + '|' + location[2][2])
turn = turn + 1
if ((location[0][0] == 'O' and location[0][1] == 'O' and location[0][2]
== 'O') or
(location[1][0] == 'O' and location[1][1] == 'O' and location[1][2] ==
'O') or
(location[2][0] == 'O' and location[2][1] == 'O' and location[2][2] ==
'O') or
(location[0][0] == 'O' and location[1][0] == 'O' and location[2][0] ==
'O') or
(location[0][1] == 'O' and location[1][1] == 'O' and location[2][1] ==
'O') or
(location[0][2] == 'O' and location[1][2] == 'O' and location[2][2] ==
'O') or
(location[0][0] == 'O' and location[1][1] == 'O' and location[2][2] ==
'O') or
(location[0][2] == 'O' and location[1][1] == 'O' and location[2][0] ==
'O')):
print (player2+" won the game!")
turn = 10
else:
print("The game ended in a tie!")
Your problem is, that the code checks after every single turn if the player whos turn it is won the game, if he did not win (yet) it prints your "else" meaning the The game ended in a tie!
Your solution would be to add another if: to you else-es that checks if all 9 fields are either filled with X or O and if that is the case you have to print your The game ended in a tie!
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
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
I have this if statement:
if value_n_in_f > 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x+#{value_n_in_f}"
elsif value_n_in_f == 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x"
elsif value_n_in_f < 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x#{value_n_in_f}"
elsif value_n_in_f > 0 && value_m_in_f == 1
puts "I: f(x)=x+#{value_n_in_f}"
elsif value_n_in_f == 0 && value_m_in_f == 1
puts "I: f(x)=x"
elsif value_n_in_f < 0 && value_m_in_f == 1
puts "I: f(x)=x#{value_n_in_f}"
end`
I have to use this statement really often in other statements and it makes my code unnecessarily long. Obviously if_for_f=if ....... end won't work. Is there any other way?
Here's an example what I want it to look like:
puts "Now we insert #{value_of_x} in #{if_for_f}"
Is there any way I can do something like this? Note that I am absolutly new to this.
Thanks in advance,
Kaiton
can't I just def a function with its function to run this case
statement and call it then when I need it it?
Of course:
def do_stuff(m, n)
if m == 1
if n > 0 then "I: f(x)=x+#{n}"
elsif n == 0 then "I: f(x)=x"
elsif n < 0 then "I: f(x)=x#{n}"
end
else
if n > 0 then "I: f(x)=#{m}x+#{n}"
elsif n == 0 then "I: f(x)=#{m}x"
elsif n < 0 then "I: f(x)=#{m}x#{n}"
end
end
end
puts do_stuff(1, 1) #I: f(x)=x+1
Or, if compactness is the goal, we can get to this:
def do_stuff(m, n)
if m == 1
n == 0 ? "I: f(x)=x" : "I: f(x)=x#{sprintf("%+d", n)}"
else
n == 0 ? "I: f(x)=#{m}x" : "I: f(x)=#{m}x#{sprintf("%+d", n)}"
end
end
...and then a one liner:
def do_stuff(m, n)
(m == 1) ? (n == 0 ? "I: f(x)=x" : "I: f(x)=x#{sprintf("%+d", n)}") : (n == 0 ? "I: f(x)=#{m}x" : "I: f(x)=#{m}x#{sprintf("%+d", n)}")
end
end
But your methodology has some problems with zeros and -1:
def do_stuff(value_m_in_f, value_n_in_f)
if value_n_in_f > 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x+#{value_n_in_f}"
elsif value_n_in_f == 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x"
elsif value_n_in_f < 0 && value_m_in_f != 1
puts "I: f(x)=#{value_m_in_f}x#{value_n_in_f}"
elsif value_n_in_f > 0 && value_m_in_f == 1
puts "I: f(x)=x+#{value_n_in_f}"
elsif value_n_in_f == 0 && value_m_in_f == 1
puts "I: f(x)=x"
elsif value_n_in_f < 0 && value_m_in_f == 1
puts "I: f(x)=x#{value_n_in_f}"
end
end
do_stuff(1, 0)
do_stuff(1,-1)
do_stuff(1, 1)
do_stuff(0,-1)
do_stuff(0, 0)
do_stuff(-1, 1)
--output:--
I: f(x)=x
I: f(x)=x-1
I: f(x)=x+1
I: f(x)=0x-1 #<---HERE
I: f(x)=0x #<---HERE
I: f(x)=-1x+1 #<---HERE
So let's fix that:
def get_line_equ(m, b)
constant = (b == 0) ? "" : sprintf("%+d", b) # 2 => "+2"
case m
when 0
xterm = ""
constant = b
when 1
xterm = "x"
when -1
xterm = "-x"
else
xterm = "#{m}x"
end
"I: f(x)=#{xterm}#{constant}"
end
puts get_line_equ(0, 0)
puts get_line_equ(0, -1)
puts get_line_equ(0, 1)
puts get_line_equ(1, 0)
puts get_line_equ(1,-1)
puts get_line_equ(1, 1)
puts get_line_equ(-1, 0)
puts get_line_equ(-1, -1)
puts get_line_equ(-1, 1)
puts get_line_equ(2, 0)
puts get_line_equ(2, -1)
puts get_line_equ(2, 1)
--output:--
I: f(x)=0
I: f(x)=-1
I: f(x)=1
I: f(x)=x
I: f(x)=x-1
I: f(x)=x+1
I: f(x)=-x
I: f(x)=-x-1
I: f(x)=-x+1
I: f(x)=2x
I: f(x)=2x-1
I: f(x)=2x+1
Better?
spoiler:
The final def is not as efficient as it could be: the first line should be removed and copied to each of the when branches--except for the first.
In response to comment:
def my_sprintf(str, *numbers)
str.gsub(/% .*? [df]/x) do |match| #Looks for %...d or %...f sequences
puts match
end
end
my_sprintf("The answer is: %+d or %+d", -2, 3)
--output:--
%+d
%+d
Next:
def my_sprintf(str, *numbers)
str.gsub(/% .*? [df]/x) do |format_sequ|
number_as_str = numbers.shift.to_s
p number_as_str
if format_sequ[1] == "+" and number_as_str[0] != "-"
"+#{number_as_str}"
else
number_as_str
end
end
end
puts my_sprintf("The answer is: %+d or %+d.", -2, 3)
--output:--
"-2"
"3"
The answer is: -2 or +3.
Here's a more compact way to write your case statement. Recall that a <=> b => -1 if a < b, a <=> b => 0 if a == b and a <=> b => -1 if a > b.
"I: f(x)=" +
case [value_n_in_f <=> 0, value_m_in_f == 1]
when [ 1,false] then "#{value_m_in_f}x+#{value_n_in_f}"
when [ 0,false] then "#{value_m_in_f}x"
when [-1,false] then "#{value_m_in_f}x#{value_n_in_f}"
when [ 1,true] then "x+#{value_n_in_f}"
when [ 0,true] then "x"
when [-1,true] then "x#{value_n_in_f}"
end
If you wish to demonstrate how the string is built, you could do something like this (with value_n_in_f and value_m_in_f renamed intercept and slope, respectively):
"I: f(x)=" +
case
when slope.zero?
intercept.zero? ? "0" : "#{intercept}"
else
case slope.to_f
when 1.0 then ""
when -1.0 then "-"
else "#{slope}"
end + "x" +
case intercept <=> 0
when 0 then ""
when -1 then "#{intercept}"
else "+#{intercept}"
end
end
Note that this permits slope < 0, which is not part of the specification. I tested this for various combinations of intercept and slope:
intercept slope string
-2.1 4 I: f(x)=4x-2.1
-2.1 -2.2 I: f(x)=-2.2x-2.1
-2.1 0 I: f(x)=-2.1
-2.1 0.0 I: f(x)=-2.1
-2.1 -1 I: f(x)=-x-2.1
-2.1 1.0 I: f(x)=x-2.1
0 4 I: f(x)=4x
0 -2.2 I: f(x)=-2.2x
0 0 I: f(x)=0
0 0.0 I: f(x)=0
0 -1 I: f(x)=-x
0 1.0 I: f(x)=x
0.0 4 I: f(x)=4x
0.0 -2.2 I: f(x)=-2.2x
0.0 0 I: f(x)=0
0.0 0.0 I: f(x)=0
0.0 -1 I: f(x)=-x
0.0 1.0 I: f(x)=x
3 4 I: f(x)=4x+3
3 -2.2 I: f(x)=-2.2x+3
3 0 I: f(x)=3
3 0.0 I: f(x)=3
3 -1 I: f(x)=-x+3
3 1.0 I: f(x)=x+3
A couple of things here: you can put "puts" before the whole if/elsif block and avoid having puts on every line, like so:
puts case
when (value_n_in_f > 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x+#{value_n_in_f}"
when (value_n_in_f == 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x"
end
Second, a case statement would be much more readable, like so:
def big_compare(value_n_in_f, value_m_in_f)
msg = case
when (value_n_in_f > 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x+#{value_n_in_f}"
when (value_n_in_f == 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x"
when (value_n_in_f < 0 && value_m_in_f != 1) then "I: f(x)=#{value_m_in_f}x#{value_n_in_f}"
when (value_n_in_f > 0 && value_m_in_f == 1) then "I: f(x)=x+#{value_n_in_f}"
when (value_n_in_f == 0 && value_m_in_f == 1) then "I: f(x)=x"
when (value_n_in_f < 0 && value_m_in_f == 1) then "I: f(x)=x#{value_n_in_f}"
end
end
puts big_compare(0, 0)
Is it possible to use a case statement to replace these if statements?
if (a%3 == 0) then puts "%3"
elsif (a%4 == 0) then puts "%4"
elsif (a%7 == 0 && a%13 == 0) then puts "%%"
case
when (a % 3).zero? then puts "%3"
when (a % 4).zero? then puts "%4"
when (a % 7).zero? && (a % 13).zero? then puts "%%"
end
Sure:
case
when (a%3 == 0) then puts "%3"
when (a%4 == 0) then puts "%4"
when (a%7 == 0 && a%13 == 0) then puts "%%"
end
It isn't much better, is it? ;-)
puts [3,4,91,10].collect do |a|
case 0
when a % 3 then
"%3"
when a % 4 then
"%4"
when a % 91 then
"%%"
end
end
You should be able to copy that right into irb to see it work. Please forgive the slight 7*13 = 91 hack, but if you're working with actual modulos they should be equivalent.
Using Proc#===
def multiple_of( factor )
lambda{ |number| number.modulo( factor ).zero? }
end
case a
when multiple_of( 3 ): puts( "%3" )
when multiple_of( 4 ): puts( "%4" )
when multiple_of( 7*13 ): puts( "%%" )
end
(a%7 == 0 && a%13 == 0) is equal to (a%7*13 == 0).
in ruby, you can make 1-line if-else statement use && and ||.
puts (a%3 == 0)&&"%3"||(a%4 == 0)&&"%4"||(a%(7*13) == 0)&&"%%"||""
or
log = (a%3 == 0)&&"%3"||(a%4 == 0)&&"%4"||(a%(7*13) == 0)&&"%%"
puts log if log
it's looks agly but short.