Ruby (Rock, Paper, Scissors) - ruby

Hey I am new to ruby and I have sat for a long time trying to find out what I've done wrong in this code, there isn't any error but it isn't giving me my desired output as a normal game of rock paper scissors.
Here is my code:
puts "Rock, Paper or Scissors"
choice = gets.chomp
cchoice = ["Rock", "Paper","Scissors"]
comp = rand(1..3)
won = false
puts "Computer chose #{cchoice[comp]}"
if (choice == "Rock")
if (comp == 2)
won = false
end
if (comp == 3)
won = true
end
elsif (choice == "Paper")
if (comp == 3)
won = false
end
if (comp == 1)
won = true
end
elsif (choice == "Scissors")
if (comp == 1)
won = false
end
if (comp == 2)
won = true
end
else
puts "I dont know what that means so-"
end
if (won)
puts "YOU WON!!!"
else
puts "You lost.."
end
Thanks for any help!

The rules of rock, paper, scissors can be expressed as a simple hash:
conditions = {
"Rock" => "Scissors",
"Paper" => "Rock",
"Scissors" => "Paper"
}
So you can simply check if one player won over the other with:
if conditions[player_1] == player_2
puts "Player one wins!"
elsif player_1 == player_2
puts "Its a draw!"
else
puts "Player two wins!"
end
This is far less complex then a tree of nested if/else statements.
conditions = {
"Rock": "Scissors",
"Paper": "Rock",
"Scissors": "Paper"
}
puts "Rock, Paper or Scissors"
choice = gets.chomp.capitalize
cchoice = conditions.keys.sample
puts "Computer chose #{ cchoice }"
if conditions[choice] == cchoice
puts "You won!"
elsif cchoice == choice
puts "Its a draw."
elsif conditions[cchoice] == choice
puts "You lost."
else
puts "#{choice} is not a valid option"
end
This covers the four potential outcomes which are:
win
loss
draw
bad input (this could also be handled with controll flow like break/throw/catch)
Also instead of rand you can use Array#sample to select a random element from the keys of the hash which avoids the need to use array indices.

Your random number generator generates numbers between 1-3, it should be between 0-2 since you are trying to index a list
comp = rand(0..2)
Also change the comparison in the if clause to reflect the above change,
Another thing you might have forgot is the draw condition (if both select the same thing)

Related

How to have ruby pick randomly from an array [duplicate]

This question already has answers here:
How do I pick randomly from an array?
(7 answers)
Closed 4 years ago.
Im pretty new to programming and I'm trying to make a basic rock paper scissors program.
I've already made this program using 1 = rock, 2 = paper, 3 = scissors. but now I want to try doing it with actual words instead of numbers. How can I make ruby choose randomly from my array, mine?
Thanks!
mine = ["Rock", "Paper", "Scissors"]
mine.sample(1 + rand(mine.count))
puts 'Write your choice, Rock, Paper, or Scissors'
yours = gets.chomp.to_s
if yours == "Rock"
puts 'Your choice is Rock'
elsif yours == "Paper"
puts 'Your choice is Paper'
else yours == "Scissors"
puts 'Your choice is Scissors'
end
puts "--------------------------"
if mine == "Rock"
puts 'Computer: My choice is Rock'
elsif mine == "Paper"
puts 'Computer: My choice is Paper'
else mine == "Scissors"
puts 'Computer: My choice is Scissors'
end
print 'Computer: My choice was: '
print mine
puts
if mine == "Rock" && yours == "Paper"
puts "==========="
puts "Paper Wins!"
puts "==========="
elsif mine == "Paper" && yours == "Rock"
puts "==========="
puts "Paper Wins!"
puts "==========="
elsif mine == "Paper" && yours == "Scissors"
puts "=============="
puts "Scissors Wins!"
puts "=============="
elsif mine == "Scissors" && yours == "Paper"
puts "=============="
puts "Scissors Wins!"
puts "=============="
elsif mine == "Scissors" && yours == "Rock"
puts "=========="
puts "Rock Wins!"
puts "=========="
elsif mine == "Rock" && yours == "Scissors"
puts "=============="
puts "Rock Wins!"
puts "=============="
else
puts "======================"
puts "It's a tie! TRY AGAIN!"
puts "======================"
end
You can use sample:
[1, 2, 3].sample #=> 1
[1, 2, 3].sample(2) #=> [3, 1]
Documentation

Increment variables within a method?

I'm trying to build a rock, paper, scissors game. Could someone please tell me or point me in the right direction of where I'm going wrong with this code?
I want the players_score and cpu_score variables to increment by 1 each time either one wins a round.
choice = ["rock", "paper", "Scissors"]
players_score = 0
cpu_score = 0
def win_lose(a,b,c,d)
if a == "rock" && b == "scissors"
c+=1
puts "YOU WIN!!"
elsif a == "scissors" && b == "rock"
d+=1
puts "YOU LOSE!!"
elsif a =="paper" && b == "rock"
c+=1
puts "YOU WIN!!"
elsif a =="rock" && b == "paper"
d+=1
puts "YOU LOSE!!"
elsif a == "scissors" && b == "paper"
c+=1
puts "YOU WIN!!"
elsif a == "paper" && b == "scissors"
d+=1
puts "YOU LOSE!!"
else a == b
puts "Its a Draw this time!!"
end
end
while players_score < 2 && cpu_score < 2
print "Lets play. Plese choose rock, paper or scissors: "
players = gets.chomp.downcase
puts "You have #{players}"
cpu = choice.sample.downcase
puts "Computer has #{cpu}"
win_lose(players, cpu, players_score, cpu_score)
puts "scores are player #{players_score} , cpu #{cpu_score}"
end
Return a value from win_lose, and use that to determine increment the variable, e.g.:
def win_lose(a,b,c,d)
if a == "rock" && b == "scissors"
c+=1
winner = 'player'
elsif a == "scissors" && b == "rock"
d+=1
winner = 'computer'
# [.. etc ..]
else a == b
winner = 'draw'
end
return winner
end
player_score = 0
cpu_score = 0
choice = ["rock", "paper", "Scissors"]
while players_score < 2 && cpu_score < 2
print "Lets play. Plese choose rock, paper or scissors: "
players = gets.chomp.downcase
puts "You have #{players}"
cpu = choice.sample.downcase
puts "Computer has #{cpu}"
winner = win_lose(players, cpu, players_score, cpu_score)
if winner == 'player'
player_score += 1
puts "YOU WIN!!"
elsif winner == 'computer'
cpu_score += 1
puts "YOU LOSE!!"
else
puts "It's a draw"
end
puts "scores are player #{players_score} , cpu #{cpu_score}"
end
As you can see, this also allows you to not repeat the same "YOU WIN!!" sentence over and over again. I moved that outside the win_lose function so that this function does only one thing: determine the winner or loser, rather than two things: determine the winner or loser, and inform them of this.
This distinction is perhaps not important for such a small program, but as your programs grow it will be critical to keep your program understandable.

How do I update one element in an array and show new version of my array in the tictactoe grid?

This is a tictactoe game. When a player chooses a grid via a number, it is supposed to update the picked number with X or O, and then show the updated grid. Unfortunately, it continues to output the same default grid of numbers. I used map! but it does not work. If I switch #player1 : x to x: #player1, it changes the entire array to X or O.
Once I figure this out, the win method will be the next task to check. Will win work to determine the winning combinations?
#a = [1,2,3,4,5,6,7,8,9]
def game
#game_board = "#{#a[0]}|#{#a[1]}|#{#a[2]}\n" "------\n" "#{#a[3]}|#{#a[4]}|#{#a[5]}\n" "------\n" "#{#a[6]}|#{#a[7]}|#{#a[8]}\n"
#game_board
end
def secondchoice
if #player1 == "X"
#player2 = "O"
elsif #player1 == "O"
#player2 = "X"
else puts "please pick a valid number"
end
end
def start
puts " Player One, Pick Your Tic or Toe , X or O"
#player1 = gets.chomp.upcase
#player2 = secondchoice
puts "Player one is #{#player1}"
puts "Now Player Two is #{#player2}"
end
def player_turns
# player 1 gets then player 2 gets until game over == true
# nine total moves using a loop with a counter will work
moves = 1
while moves < 10
if moves.odd?
puts #game_board
puts "its player One's turn! place #{#player1} on the board by picking a number: "
cell = gets.chomp
#a.map! {|x|x == cell ? #player1 : x}
moves += 1
unless check_win == true
end
else
puts #game_board
puts "its player Two's turn! place #{#player2} on the board by picking a number: "
kell = gets.chomp
#a.map! {|x|x == kell ? #player2 : x}
moves += 1
unless check_win == true
end
end
end
end
def win
# 10 turns(count) with no combination is a draw
return [[#a[0]+ #a[1] + #a[2]],[#a[3] + #a[4] + #a[5]],[#a[6] + #a[7] + #a[8]],[#a[0]+ #a[3] + #a[6]],[#a[1] + #a[4] + #a[7]],[#a[2] + #a[5]+ #a[8]],[#a[0]+ #a[4] + #a[8]],[#a[2] + #a[4] + #a[6]]]
#game_over check if player has 3 in a row
end
# Create a loop that gives player turns. Player one then player two until a draw or three in row
def check_win
win.each do |arr|
str = arr.join
if str == "xxx"
puts "X Wins!"
return true
elsif str == "ooo"
puts "O Wins!"
return true
end
end
return false
end
while check_win != true
start
game
player_turns
end
It's not clear why map! would factor in here. A simple array manipulation is all that's required:
#a[cell.to_i - 1] = #player2
Specifying the cells as zero indexed would make this easier.
There's a lot of evidence of going against the grain here that's made for a ton more code than necessary. For example, variables like #player1 and #player2 are usually a sign of bad design. Why not #players = %w[ X O ]? That alone solves a lot of problems if you apply that array throughout your code instead of having per-player variables. Each turn: #players.unshift(#players.pop)

Adding points to players in RPS Game

I'm creating a Rock Paper Scissors game. There are no errors but it doesn't work how I would like it to.
Instead of adding the scores to the player it just ends when the player rolls for their choice by pressing either "R" or "E"
I don't understand what's happening here could someone please explain to me why it's not doing the adding?
def welcome
puts "Welcome to Rock, Paper, Scissors. To begin press 'S'.
To learn how to play press 'I'. To quit the game press 'Q'"
input = gets.chomp
if input =~ /s/i
start_game
elsif input =~ /i/i
instructions
else
exit
end
end
def start_game
start_points_P1 = 0
start_points_P2 = 0
choice = ['Rock', 'Paper', 'Scissors']
choicep2 = ['Rock', 'Paper', 'Scissors']
puts "Press 'R' to roll for Player 1"
input = gets.chomp!
puts "Press 'E' to roll for Player 2"
input = gets.chomp!
if choice.sample == choicep2.sample
puts "Draw!"
start_game
elsif choice.sample == 'Paper' && choicep2.sample == 'Scissors'
puts "Player 2 has won! You have gained 10 points! Score: Player 1: #{start_points_p1} Player 2: #{start_points_p2 += 10}"
elsif choice.sample == 'Scissors' && choicep2.sample == 'Rock'
puts "Player 2 has won! You have gained 10 points! Score: Player 1: #{start_points_p1} Player 2: #{start_points_p2 += 10}"
elsif choice.sample == 'Rock' && choicep2.sample == 'Paper'
puts "Player 2 has won! You have gained 10 points! Score: Player 1: #{start_points_p1} Player 2: #{start_points_p2 += 10}"
elsif choicep2.sample == 'Paper' && choice.sample == 'Scissors'
puts "Player 1 has won! You have gained 10 points! Score: Player 1: #{start_points_p1 += 10} Player 2: #{start_points_p2}"
elsif choicep2.sample == 'Scissors' && choice.sample == 'Rock'
puts "Player 1 has won! You have gained 10 points! Score: Player 1: #{start_points_p1 += 10} Player 2: #{start_points_p2}"
elsif choicep2.sample == 'Rock' && choice.sample == 'Paper'
puts "Player 1 has won! You have gained 10 points! Score: Player 1: #{start_points_p1 += 10} Player 2: #{start_points_p2}"
end
end
Every time you call sample on choicep2 or choice, a random value will be selected from the array you call it on. You should do something like player_choice = choice.sample, computer_choice = choicep2.sample (or computer_choice = choice.sample will work just as well) then make the comparison between player_choice and computer_choice.
Probably the biggest problem in the code in terms of the functionality you want is the repeated use of choice.sample and choicep2.sample. Every time that is called, it returns a new random selection from each array.
That means for each test like this:
elsif choice.sample == 'Paper' && choicep2.sample == 'Scissors'
there is an independent 1 in 9 chance of it being true and you seeing the result. That means it is possible to fail all the tests, because for each condition the "players" are going again, and you only check one possible exact outcome. This is not like the real version of this game at all, where the players make a single choice each and then you test it.
To fix this in a way which matches how this game is usually played, you should store each player's choice in a new variable, and compare those values. E.g. before your first test, do something like
p1_plays = choice.sample
p2_plays = choice.sample
(Note how you can re-use the list of choices, as it does not change, at least in this variant)
Your conditionals can then refer to those variables like this:
elsif p1_plays == 'Paper' && p2_plays == 'Scissors'
As an aside, it may be a nice addition to your code to show what each player played. If you do that as one of the first things, then it will help you verify correct logic in the rest of the code.

Ruby - rock paper scissor game using While, if/else statements, player vs computer

$player_count = 0
$computer_count = 0
what_to_include = %w{r p s}
paper = "p"
rock = "r"
scissors = "s"
def computer_input
computer = rand(3)
if computer == 0
computer = "p"
elsif computer == 1
computer = "r"
else
computer = "s"
end
end
while true
puts "Player Score: #{$player_count}, \tComputer Score: #{$computer_count}"
print "Choose rock (r), paper (p), or scissors (s): "
player_input = gets.chomp.downcase
if player_input == rock && computer_input == scissors
puts "Player chose rock. \nComputer chose scissors."
puts "Rock beats scissors, player wins the round."
$player_count += 1
elsif player_input == scissors && computer_input == paper
puts "Player chose scissors. \nComputer chose paper."
puts "Scissors beat paper, player wins the round."
$player_count += 1
elsif player_input == paper && computer_input == rock
puts "Player chose paper. \nComputer chose rock"
puts "Paper beats rock, player wins the round."
$player_count += 1
elsif computer_input == rock && player_input == scissors
puts "Player chose scissors. \nComputer chose rock."
puts "Rock beats scissos, Computer wins the round"
$computer_count += 1
elsif computer_input == scissors && player_input == paper
puts "Player chose paper. \nComputer chose scissors."
puts "Scissors beats paper, Computer wins the round"
$computer_count += 1
elsif computer_input == paper && player_input == rock
puts "Player chose rock. \nComputer chose paper."
puts "Paper beats rock, Computer wins the round"
$computer_count += 1
# elsif player_input == computer_input
# puts "Player chose #{player_input},\n Computer chose #{computer_input}"
# puts "Tie, choose again" #tried with this but returns r, s, p instead of word
elsif player_input == rock && computer_input == rock ||
player_input == paper && computer_input == paper ||
player_input == scissors && computer_input == scissors
puts "Player chose rock. \nComputer chose rock."
puts "Tie, choose again"
end
if player_input.include?("abcdefghijklmnoqtuvxzy")
puts "Invalid entry, try again."
end
if $player_count == 2
puts "Player wins!"
break
elsif $computer_count == 2
puts "Computer wins!"
break
end
end
ok, I am new to this, and i understand there is a better way of writing a rock paper scissors with less typing and better methods. I'm just not there yet. so bear with me.
The code works but sometimes when i enter "r", "p", "s" it returns nothing, or "Invalid entry, try again." I have tried entering ranges
if player_input = ["a".."o"].to_s in case the player's input was anything else than the commands for the game. but still. I tried the include? method
can anyone tell me how to work only the r, p, s. and give "Invalid entry, try again" for everything else? in this code.
Loop with Conditional Break
One way to do this is with a loop that breaks only when you have valid input. For example:
loop do
print "Choose rock (r), paper (p), or scissors (s): "
player_input = gets.chomp.downcase
break if player_input =~ /^[rps]$/
puts "Invalid entry, try again."
end
There are certainly other ways to do this, and more idiomatic ways, too. However, this should address your specific question without too much refactoring.
The =~ is testing for a regular expression in Ruby. Anything in between (2) slashes... /^[rps]$/ is a regular expression.
http://www.ruby-doc.org/core-2.1.3/Regexp.html
^ Good information there on regular expressions.
Here's a more compact and Ruby-like way to write the game.
ENTRY_TO_SYM = { 'p'=>:PAPER, 'r'=>:ROCK, 's'=>:SCISSORS }
VALID_ENTRIES = ENTRY_TO_SYM.keys
COMPUTER_CHOICES = ENTRY_TO_SYM.values
# WINNERS and LOSERS from the player's perspective, the first value of each
# pair being the player's choice, the second, the computer's choice.
WINNERS = [[:SCISSORS, :PAPER], [:PAPER, :ROCK], [:ROCK, :SCISSORS]]
LOSERS = WINNERS.map { |i,j| [j,i] }
.
class RockPaperScissors
def initialize
#player_score = #computer_score = #ties = 0
end
def play(winning_score)
while #player_score < winning_score && #computer_score < winning_score
puts "Player score: #{#player_score}, " +
"Computer score: #{#computer_score}, Ties: #{#ties}"
player = player_choice
computer = COMPUTER_CHOICES.sample
puts "\nPlayer chooses #{player.to_s}"
puts "Computer chooses #{computer.to_s}"
case player_outcome [player, computer]
when :WIN
puts "#{player.to_s} beats #{computer.to_s}, player wins the round"
#player_score += 1
when :LOSE
puts "#{computer.to_s} beats #{player.to_s}, computer wins the round"
#computer_score += 1
else
puts "Tie, choose again"
#ties += 1
end
end
puts "\nFinal score: player: #{#player_score}, " +
"computer: #{#computer_score} (ties: #{#ties})"
puts (#player_score == 2) ? "Player wins!" : "Yea! Computer wins!"
end
.
private
def player_choice
loop do
print "Choose rock (r), paper (p) or scissors (s): "
choice = gets.chomp.downcase
return ENTRY_TO_SYM[choice] if ENTRY_TO_SYM.key?(choice)
puts "That entry is invalid. Please re-enter"
end
end
def player_outcome(plays)
return :WIN if WINNERS.include?(plays)
return :LOSE if LOSERS.include?(plays)
:TIE
end
end
.
RockPaperScissors.new.play(3)
A few things to note:
I've relegated the getting of a valid entry from the player to a separate method, where I use Kernel#loop (generally preferred to while true, etc.) for looping.
I've used symbols to represent both choices and outcomes.
I used the method Array#sample to obtain the computer's random choice.
I've used arrays to represent winning and losing pairs of choices (from the player's perspective).
Using too much || and if/elsif is really weird for this problem. You can do something much simpler like this:
# I inserted the logic here in this method, so we can always
# call the game
def rock_scissors_paper(user_choice)
options = ["rock", "scissors", "paper"]
computer_choice = options.sample
computer_index = options.index(computer_choice)
user_index = options.index(user_choice)
puts "The computer went with #{computer_choice}"
# Example:
# If user chooses Rock (0 - 1) and computer paper (2), computer WINS
# because options[-1] is... paper (whenever this is equal, computer wins)
# If user chooses Paper (2 - 1) and computer rock (0), user WINS (ELSE)
# And so on.
# Pay careful attention to how we checking against VALUES (-1 is the last guy!)
if options[user_index - 1] == options[computer_index]
puts "Computer wins the game!"
elsif computer_choice == user_choice
puts "It's a draw"
else
puts "You win the game"
end
end
# Display options to the users
puts "Rock, scissors, paper?"
user_choice = gets.chomp.downcase
# Run method
rock_scissors_paper(user_choice)
so i think the issue was that you needed to define the player like you did with the computer. i redid the assignment using the same things as you and it now seems to work. $player_count = 0
$computer_count = 0
def computer_input
computer = rand(3)
if computer == 0
computer = "p"
elsif computer == 1
computer = "r"
else
computer = "s"
end
end
def player_input
if player == "r"
player = "r"
elsif player == "p"
player = "p"
else player == "s"
player = "s"
end
end
while true
puts "Player Score: #{$player_count}, \tComputer Score: #{$computer_count}"
puts "Choose rock (r), paper (p), or scissors (s) "
player_input = gets.chomp
if player_input == "r" && computer_input == "s"
puts "Player chose rock. \nComputer chose scissors."
puts "Rock beats scissors, player wins the round."
$player_count += 1
elsif player_input == "s" && computer_input == "p"
puts "Player chose scissors. \nComputer chose paper."
puts "Scissors beat paper, player wins the round."
$player_count += 1
elsif player_input == "p" && computer_input == "r"
puts "Player chose paper. \nComputer chose rock"
puts "Paper beats rock, player wins the round."
$player_count += 1
elsif computer_input == "r" && player_input == "s"
puts "Player chose scissors. \nComputer chose rock."
puts "Rock beats scissos, Computer wins the round"
$computer_count += 1
elsif computer_input == "s" && player_input == "p"
puts "Player chose paper. \nComputer chose scissors."
puts "Scissors beats paper, Computer wins the round"
$computer_count += 1
elsif computer_input == "p" && player_input == "r"
puts "Player chose rock. \nComputer chose paper."
puts "Paper beats rock, Computer wins the round"
$computer_count += 1
elsif player_input == computer_input
puts "Tie, go again!"
else
puts "Invalid Entry"
end
if $player_count == 2
puts "Player wins!"
break
elsif $computer_count == 2
puts "Computer wins!"
break
end
end
Hope this helps!!

Resources