Adding points to players in RPS Game - ruby

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.

Related

Ruby (Rock, Paper, Scissors)

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)

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.

RPS Showing Up As Draw Every time

Earlier I asked about adding points to a RPS game I created, that problem is fixed, but now I have a new problem.. Every time the user rolls for their item (rock, paper, or scissors) it's a draw. I've tried adding a percentage to the array 33.5% for two and 33% for one which adds to 100 and it still comes up as a draw every time.
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']
choice2 = ['Rock', 'Paper', 'Scissors']
player1 = choice.sample
player2 = choice2.sample
puts "Press 'R' to roll for Player 1"
input = gets.chomp!
puts "Player 1 has recieved #{player1}"
puts "Press 'E' to roll for Player 2!"
input = gets.chomp!
puts "Player 2 has recieved #{player2}"
if player1 == player2
puts "Draw!"
start_game
elsif player1 == 'Paper' && player2 == 'Scissors'
start_points_P2 += 10
puts "Player 2 has won with #{player2}. You now have #{start_points_P2} points and opponent has #{start_points_P1} points"
elsif player1 == 'Scissors' && player2 == 'Paper'
start_points_P1 += 10
puts "Player 1 has won with #{player1}. You know have #{start_points_P1} points and opponent has #{start_points_P2} points"
elsif player1 == 'Rock' && player2 == 'Paper'
start_points_P2 += 10
puts "Player 2 has won with #{player2}. You now have #{start_points_P2} points and opponent has #{start_points_P1} points"
elsif player1 == 'Paper' && player2 == 'Rock'
start_points_P1 += 10
puts "Player 1 has won with #{player1}. You know have #{start_points_P1} points and opponent has #{start_points_P2} points"
elsif player1 == 'Scissors' && player2 == 'Rock'
start_points_P2 += 10
puts "Player 2 has won with #{player2}. You now have #{start_points_P2} points and opponent has #{start_points_P1} points"
elsif player1 == 'Rock' && player2 == 'Scissors'
start_points_P1 += 10
puts "Player 1 has won with #{player1}. You know have #{start_points_P1} points and opponent has #{start_points_P2} points"
end
end
welcome
Am I missing something here, why does it keep showing up as a draw if I have set the players into separate arrays and only called .sample once?

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!!

Rock Paper Scissors in Python.... do i use chained or nested conditional to get this to run?

Am i supposed to create a chained conditional or nested?
player1 = raw_input ("?")
player2 = raw_input ("?")
if (player1 == 'rock' and player2 == 'scissors'):
print "Player 1 wins."
elif (player1 == 'rock' and player2 == 'rock'):
print "Tie"
elif (player1 == 'scissors' and player2 == 'paper'):
print "Player 1 wins."
elif (player2 == 'scissors' and player2 == 'scissors'):
print "Tie"
elif (player1 == 'paper' and player2 == 'paper'):
print "Tie"
elif (player1 == 'paper' and player2 == 'scissors'):
print "Player 2 wins."
elif (player1 == 'rock'and player2 == 'paper'):
print "Player 2 wins."
elif (player1 == 'paper' and player2 == 'rock'):
print "Player 2 wins."
elif (player1 == 'scissors' and player2 == 'rock'):
print "Player 2 wins."
else:
print "This is not a valid object selection."
The question should probably be migrated to CodeReview, but until then, I'll put my answer here...
Instead of making all those checks nested or chained, you can use or to combine different conditions yielding the same result, e.g. one player winning. Also, the check whether player 1 wins over player 2 is the same as the other way around, so you can put this into a function.
This will make you code shorter, more readable and easier to maintain.
ROCK, PAPER, SCISSORS = "rock", "paper", "scissors"
def valid(s):
""" s is a valid input """
return s in [ROCK, PAPER, SCISSORS]
def wins(p1, p2):
""" p1 wins over p2 """
return (p1 == ROCK and p2 == SCISSORS or
p1 == SCISSORS and p2 == PAPER or
p1 == PAPER and p2 == ROCK)
player1 = raw_input ("Player 1: ").strip().lower()
player2 = raw_input ("Player 2: ").strip().lower()
if valid(player1) and valid(player2):
if wins(player1, player2):
print "Player 1 wins."
elif wins(player2, player1):
print "Player 2 wins."
else:
print "Tie."
else:
print "This is not a valid object selection."

Resources