Output Method Return Value to Variable? Ruby - ruby

Is there a way to store the output of a method in a variable in Ruby? For example, if I wanted to store the return value of display_results in a variable to be evaluated by win_counter is that possible? I want win_counter to increment every time display_results has a winner.
win_combos = [
['rock', 'scissors'],
['paper', 'rock'],
['scissors', 'paper'],
['rock', 'lizard'],
['lizard', 'spock'],
['spock', 'scissors'],
['scissors', 'lizard'],
['lizard', 'paper'],
['paper', 'spock'],
['spock', 'rock']
]
scores = { player: 0, computer: 0 }
def display_results(first, second, combos = [])
combos.each do |combo|
if combo == [first, second]
puts "Player won!"
break
elsif combo == [second, first]
puts "Computer won!"
break
end
end
if first == second
puts "It's a tie!"
end
end
def win_counter(player, computer, scores)
if display_results(player, computer)
scores[:player] = scores[:player] + 1
elsif display_results(computer, player)
scores[:computer] = scores[:computer] + 1
end
puts "players wins: #{scores[:player]}; computer wins: #{scores[:computer]}"
end
display_results('spock', 'rock', win_combos)
win_counter('spock', 'rock', scores)

All you need to do is set a variable equal to the method call. You could use:
if display_results(player, computer) == "Player won!"
However, it might be more useful to split the logic for printing the winner away from the logic for the actual game. In ruby methods that return booleans are stylized with a '?' i.e empty? display_results should only display the results of the game, you shouldn't use an if statement on it.

Related

Building tic tac toe game through scratch stuck while checking winning

I can play the game. Switch the player all working fine but not getting result who won the game.
def initialize_board
#count = 9
#player = PLAYER_ONE #current_player
#board = Array.new(3){ Array.new(3, " ") }
end
def play
inputs = get_inputs
return false if !inputs
update_board(inputs)
print_board
end
def switch_player
if(#player == PLAYER_ONE)
#player = PLAYER_TWO
else
#player = PLAYER_ONE
end
end
def game_over?
# #count = #count - 1
# #count <= 0
if check_winner
puts "#{#player} won "
end
end
def check_winner
WIN_COMBINATIONS.find do |indices|
binding.pry
values = #board.values_at(*indices)
values.all?('X') || values.all?('O')
end
end
Here I am getting indices [0,1,2] in all cases while debugging.
The main reason why you're not getting the winner is because your 'values = #board.values_at(*indices)' statement returns an array of arrays. And values.all?('X') || values.all?('O') checks not an 'X' or 'O' pattern but an array object. So you need to flatten an array first.
values.flatten!
Stefan already answered similar question , but his board was one-dimensional because of %w expression, you can read about it here

Why am I always getting a rock response from p2, p3 and p4?

Hi I'm just learning ruby and decided to try and eloborate on codewars Kata to create quick rock, paper, scissors game. At first I was getting random responses but now it's alway rock. Please help and sorry if this is ridiculously easy.
module Promtable
def prompt(message = "What would you like to do? ", symbol = ":> ")
print message
print symbol
var = gets.chomp.to_s
if !var.match /rock|paper|scissors/
puts "I'm sorry that is not a valid response please try again"
print message
print symbol
gets.chomp
else
var
end
end
end
def rps(p1, p2)
if #p1 == 'rock' && #p2 == 'scissors'
puts "Player 1 won!"
elsif
#p1 == 'paper' && #p2 == 'rock'
puts "Player 1 won!"
elsif
#p1 == 'scissors' && #p2 == 'paper'
puts "Player 1 won!"
elsif
#p1 == 'rock' && #p2 == 'paper'
puts "Computer won!"
elsif
#p1 == 'scissors' && #p2 == 'rock'
puts "Computer won!"
elsif
#p1 == 'paper' && #p2 == 'scissors'
puts "Computer won!"
else
puts "It's a draw!"
end
end
def game
include Promtable
p1 = prompt("Player 1 plays...?")
choices = ["rock", "paper", "scissors"]
p2 = choices[rand]
p3 = choices[rand]
p4 = choices[rand]
rps(p1, p2)
puts "The computer chose #{p2}!"
p1 = prompt("What's your second choice...? ")
p3 = choices[rand]
rps(p1, p3)
puts "The computer chose #{p3}!"
p1 = prompt("What's your final choice...? ")
p4 = choices[rand]
rps(p1, p4)
puts "The computer chose #{p4}!"
end
puts "Hi welcome to Rock, Paper, Scissors"
game
puts "Would you like to play again? (Y/N)"
var = gets.chomp.downcase
if var.match /y/
game
end
I see two issues. One which has already been pointed out about the default return value of rand. I recommend using choices.sample. The other issue is in rps: note that p1 and #p1 are different variables. There's no need to use instance variables in rps; I'd change them all to local p1 and p2.
Now, some code review style comments:
It's cool that you are experimenting with mixins with the module Promtable (which is missing a 'p' by the way). Of course you have some RPS logic embedded in it, so it isn't really reusable. Maybe you can make it more generic by adding a way to pass in an array of valid values. Speaking of valid values, you are checking them with a regular expression (/rock|paper|scissors/) which just checks a substring. If I were to type "rocky" it would pass through and be treated as a draw. You may want to use
if !valid_values.include? var or unless valid_values.include? var instead of the regex.
The rps method can be simplified in a number of ways. Cary Swoveland had a clever idea in the comments of using a hash to look up the winning combinations. Another way to simplify would be to use a case statement:
case [p1,p2]
when ['rock', 'scissors'], ['paper', 'rock'], ['scissors', 'paper']
puts "Player 1 won!"
when ['scissors', 'rock'], ['rock', 'paper'], ['paper', 'scissors']
puts "Computer won!"
else
puts "It's a draw!"
end
rand returns a number between 0 and 1. Essentially, choices[rand] always becomes choices[0].
You may want to use choices[rand(0..2)] instead.
Alternatively, you could use choices.sample.
Check the docs for rand here.

Building Tic Tac Toe game to learn OOP, but my game board isn't updating

These are incomplete codes, but it should at least update the game board until it fills up and error out. I don't know why its not updating the board. It definitely is registering my inputs as well as the computer's since the game does print my coordinates. Can someone please help me figure out what I'm doing wrong?
class Board
attr_reader :grid
def initialize
#grid = Array.new(3) { Array.new(3) }
#human = HumanPlayer.new
#computer = ComputerPlayer.new
#game = Game.new
end
def place_mark(pos)
if (pos[0] < 0 || pos[0] > 2) || (pos[1] < 0 || pos[1] > 2)
puts "Invalid coordinates! Please try again!"
#game.play
elsif empty?(pos)
if #game.current_player == "human"
puts "Player 1 goes: #{pos}"
#grid[pos[0]][pos[1]] = 'X'
elsif #game.current_player == "computer"
puts "Computer goes: #{pos}"
#grid[pos[0]][pos[1]] = "O"
end
if winner
puts "Congratulations! #{#game.current_player} wins!"
else
#game.switch_players!
end
else
puts "Space Taken! Please Try Again!"
#game.play
end
end
def empty?(pos)
#grid[pos[0]][pos[1]].nil?
end
def winner
#Need to set winning combinations
false
end
def over?
false #for now, it will go until all spaces are filled. Still need to set end game condition.
end
end
class HumanPlayer
def display
p Board.new.grid
end
def get_move
puts "Please enter your the quadrant you wish to place your mark."
pos = gets.chomp.scan(/[0-9]/).map!(&:to_i)
Board.new.place_mark(pos)
end
end
class ComputerPlayer
def get_move
x = rand(3).round
y = rand(3).round
Board.new.place_mark([x,y])
end
end
class Game
##turn_tracker = 0
def current_player
##turn_tracker.even? ? "human" : "computer"
end
def switch_players!
##turn_tracker += 1
play
end
def play_turn
if current_player == "human"
HumanPlayer.new.display
Board.new.place_mark(HumanPlayer.new.get_move)
elsif current_player == "computer"
ComputerPlayer.new.get_move
end
end
def play
play_turn until ##turn_tracker == 9 #Still need to set win conditions
end
end
board = Game.new
board.play
1) Game Initiates with Game#new#play
2) #play will run the game until 9 turns have passed (temporary
condition). It is passed to #play_turn
3) #play_turn figures out whose turn it is by using the
current_player.
4) It is then passed to HumanPlayer.get_move or
ComputerPlayer#get_move. These two will determine the moves of each
player and pass it to Board#place_mark.
5) #place_mark will determine if the move is valid using #empty? If
valid, it SHOULD update the grid. Then passes to the
Game#switch_players!
6)#switch_players! will change the player and passes back to #play.
7) It should iterate through this loop.
You always generate a new board, which then of course is again initalized with the starting position:
class HumanPlayer
def display
p Board.new.grid
end
...
end
As you want to learn something, I don't present you a solution.

Using a Ruby while loop to access a class method

I'm creating a simple game of rock-paper-scissors that can be played in the console. The RPS game itself is stored in one class, and the console-player version is stored in another class. The RPS game is working and the console-player is working for one game, but when I try to loop through to allow the users to play 3 games I'm getting stuck. The users still aren't allowed to play more than three games, but the console no longer outputs the winner of the game.
Here's my code so far:
class Game
attr_accessor :status
def initialize(name1, name2)
#name1 = name1
#name2 = name2
#status = []
end
def play(str1, str2)
if #status.size == 3
total = #status.inject(0) { |i, total| total += i }
if total > 0
"Game over, Player 2 wins"
elsif total < 0
"Game over, Player 1 wins"
end
else
if (str1 == 'rock' && str2 == 'paper') || (str1 == 'scissors' && str2 == 'rock') || (str1 == 'paper' && str2 == 'scissors')
#status << 1
"Player 2 wins!"
elsif (str2 == 'rock' && str1 == 'paper') || (str2 == 'scissors' && str1 == 'rock') || (str2 == 'paper' && str1 == 'scissors')
#status << -1
"Player 1 wins!"
else
"No winner"
end
end
end
end
require 'io/console'
class RPSPlayer
def start
puts "Enter player 1 name"
#player1 = gets.chomp
puts "Enter player 2 name"
#player2 = gets.chomp
#new_game = Game.new(#player1, #player2)
puts "#{#player1} challenges #{#player2} to an R-P-S showdown."
player1_prompt = "#{#player1}: what's your move?"
player2_prompt = "#{#player2}: what's your move?"
while #new_game.status.size < 3
puts player1_prompt
str1 = gets.chomp
puts player2_prompt
str2 = gets.chomp
#new_game.play(str1, str2)
end
end
end
If I delete the while loop in the console game (just prompting the players for input and inputting into #new_game) I get the winner name, but when I'm in the while loop the console just prompts the players for their move 3 times, without giving any output. Can anyone tell me why that would be?
The method #play returns a string, it does not print it. To output the winner, you need to puts the result:
while #new_game.status.size < 3
puts player1_prompt
str1 = gets.chomp
puts player2_prompt
str2 = gets.chomp
puts #new_game.play(str1, str2)
end

undefined method (NoMethodError) ruby

I keep getting the following error message:
text.rb:2:in `<main>': undefined method `choices' for main:Object (NoMethodError)
But I can't seem to understand why my method is "undefined":
puts "Select [1] [2] [3] or [q] to quit"; users_choice = gets.chomp
choices(users_choice)
def choices (choice)
while choice != 'q'
case choice
when '1'
puts "you chose one!"
when '2'
puts "you chose two!"
when '3'
puts "you chose three!"
end
end
end
This is because you are calling method choices, before defining it. Write the code as below:
puts "Select [1] [2] [3] or [q] to quit"
users_choice = gets.chomp
def choices (choice)
while choice != 'q'
case choice
when '1'
break puts "you chose one!"
when '2'
break puts "you chose two!"
when '3'
break puts "you chose three!"
end
end
end
choices(users_choice)
I used break, to exit from the while loop. Otherwise it will create an infinite loop.
def main
puts "Select [1] [2] [3] or [q] to quit"; users_choice = gets.chomp
choices(users_choice)
end
def choices (choice)
while choice != 'q'
case choice
when '1'
puts "you chose one!"
break
when '2'
puts "you chose two!"
break
when '3'
puts "you chose three!"
break
end
end
end
main
The method only needs to be called prior to being executed. Here I wrap the definition in the main method, but only call main after the definition of choices().
I was getting the same error running Ruby in Eclipse working out the App Academy practice exercises. I forgot to add "object." to the supplied test cases. The following syntax works:
#!/usr/bin/ruby
class Prime
# Write a method that takes in an integer (greater than one) and
# returns true if it is prime; otherwise return false.
#
# You may want to use the `%` modulo operation. `5 % 2` returns the
# remainder when dividing 5 by 2; therefore, `5 % 2 == 1`. In the case
# of `6 % 2`, since 2 evenly divides 6 with no remainder, `6 % 2 == 0`.
# More generally, if `m` and `n` are integers, `m % n == 0` if and only
# if `n` divides `m` evenly.
#
# You would not be expected to already know about modulo for the
# challenge.
#
# Difficulty: medium.
def primer(number)
if number < 2
return false
end
i = 10
while i > 1
if number > i && number != i
if number % i == 0
return false
end
end
i -= 1
end
return true
end
end
object = Prime. new
# These are tests to check that your code is working. After writing
# your solution, they should all print true.
puts("\nTests for #primer")
puts("===============================================")
puts('primer(2) == true: ' + (object.primer(2) == true).to_s)
puts('primer(3) == true: ' + (object.primer(3) == true).to_s)
puts('primer(4) == false: ' + (object.primer(4) == false).to_s)
puts('primer(9) == false: ' + (object.primer(9) == false).to_s)
puts("===============================================")

Resources