0

I wrote a "Rock, paper, scissors" game:

puts "Hello, this is a rock, papers, scissors game. Let's play."
puts "Player 1, plase enter your choice: \n"
puts "r for rock. \np for paper. \ns for scissors."
p1 = gets.chomp.downcase

puts "Player 2, please enter your choice: \n"
puts "r for rock. \np for paper. \ns for scissors."
p2 = gets.chomp.downcase

if p1 == 'r' && p2 == 's'
  puts "Player 1 wins."
elsif p1 == 'r' && p2 == 'p'
  puts "Player 2 wins."
elsif p1 == 'r' && p2 == 'r'
  puts "Tie."
elsif p1 == 'p' && p2 == 'r'
  puts "Player 1 wins."
elsif p1 == 'p' && p2 == 's'
  puts "Player 2 wins."
elsif p1 == 'p' && p2 == 'p'
  puts "Tie."
elsif p1 == 's' && p2 == 'r'
  puts "Player 2 wins."
elsif p1 == 's' && p2 == 'p'
  puts "Player 1 wins."
elsif p1 == 's' && p2 == 's'
  puts "Tie."
end

It works, however, that's a lot of elsifs, and I know that this is possible with case...when statements, the thing is that I can't figure out how.

I was trying to use a return statement depending on the input: "return 0 for rock, 1 for paper and 2 for scissors", and then use a conditional to say something like "hey, if player one returns 1 and player 2 also returns 1, then puts 'tie'", and the same for the other possible results.

I was trying to associate a number to the result: return - 1 when player one wins, return 0 for a tie, and return 2 for player two wins.

I did it like this, but it's kind of the same, and I feel that it's so bad:

case p1
when p1 == 'r' && p2 == 'r'
  result = 0
when p1 == 'r' && p2 == 'p'
  result = 1
when p1 == 'r' && p2 == 's'
  result = -1
when p1 == 'p' && p2 == 'r'
  result = -1
when p1 == 'p' && p2 == 'p'
  result = 0
when p1 == 'p' && p2 == 's'
  result = 1
when p1 == 's' && p2 == 'r'
  result = 1
when p1 == 's' && p2 == 'p'
  result = -1
when p1 == 's' && p2 == 's'
  result = 0
end

if result == -1
  puts "P1 wins"
elsif result == 0
  puts "Tie"
elsif result == 1
  puts "P2 wins"
end

I would appreciate any kind of help.

potashin
  • 44,205
  • 11
  • 83
  • 107

5 Answers5

1

An array can be used as a ring, with each item having a weaker item to its right, and a stronger one to its left.

weapons = ['paper', 'rock', 'scissors']

select weapons by your favorite means

w1 = weapons[rand(weapons.length)]
w2 = weapons[rand(weapons.length)]

rotate array till w1 is at the center

while weapons[1] != w1
    weapons.rotate! 1
end

now the result is indicated by the index of w2 in weapons array, conveniently.

verbs = ['is beat by', 'ties', 'beats']
puts "#{w1} #{verbs[weapons.index(w2)]} #{w2}"

Example output from a few runs:

paper beats rock
paper ties paper
rock beats scissors
scissors beats paper
rock is beat by paper

You could get creative and add a hash of verb-arrays, one for each weapon, using w1 as the key so that it would output (for example) paper covers rock, etc.

codess
  • 356
  • 1
  • 6
  • Thank you so much for that, very clear. But sorry, what does it mean the 1 in `weapons.rotate! 1` ?. Also very helpful, since I was looking for a way of do it randomly, I mean, when playing against the computer, which should pick a random choice. – Leonardo Guedez Mar 01 '15 at 04:33
  • The 1 is the number of elements to rotate. Really it wasn't necessary to specify because 1 is the default, but I did anyway. [Here's some documentation](http://ruby-doc.org//core-2.2.0/Array.html#method-i-rotate). – codess Mar 01 '15 at 05:46
0

You can try something like this :

if (p1 == p2)
  puts "Tie"
elsif (p1 == 'r' && p2 == 'p') ||
      (p1 == 'p' && p2 == 's') ||
      (p1 == 's' && p2 == 'r')
  puts "P2 wins"
else
  puts "P1 wins"
end
potashin
  • 44,205
  • 11
  • 83
  • 107
0

You could also do the ruby equivalent of saying

  If p1 = 'r' then

goto R endif If p1 = 'p' then goto S endif

etc.

then at your goto locations later

R:

if p2 = 'r' then puts "tie"

etc.

however the idea of p1 = p2 then ... is a good one.

  • `goto` is rumoured to be an experimental feature in v2.4. – Cary Swoveland Mar 01 '15 at 02:09
  • @Dommu Tous Hey thanks, I like it to see different approaches for the same result. However, although I don't consider myself an experienced programmer, I have seen a lot of bad things about the `goto` and recommendations of to not use it unless it's extremely necessary. Also, shouldn't be `if p1 == 'r' then`, with ==? – Leonardo Guedez Mar 01 '15 at 04:15
0

Here's another way:

WINNERS = {s: :p, p: :r, r: :s}
  # => {:s=>:p, :p=>:r, :r=>:s} 

def win_lose_or_tie?(me, you)
  return "I win! :-)"   if WINNERS[me] == you 
  return "you win! :-(" if WINNERS[you] == me
  "it's a tie :-|"
end

keys = WINNERS.keys
keys.product(keys).each { |me, you|
  puts "If I play #{me} and you play #{you}, then #{win_lose_or_tie?(me, you)}" }
  # If I play s and you play s, then it's a tie :-|
  # If I play s and you play p, then I win! :-)
  # If I play s and you play r, then you win! :-(
  # If I play p and you play s, then you win! :-(
  # If I play p and you play p, then it's a tie :-|
  # If I play p and you play r, then I win! :-)
  # If I play r and you play s, then I win! :-)
  # If I play r and you play p, then you win! :-(
  # If I play r and you play r, then it's a tie :-|
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
-1

I'd use a case/when statement like:

result = case [p1, p2]
         when %w[r r], %w[p p], %w[s s]
           0
         when %w[r p], %w[p s], %w[s r]
           1
         when %w[r s], %w[p r], %w[s p]
           -1
         end

puts case result
     when  0
      "Tie"
     when -1
      "P1 wins"
     when  1
      "P2 wins"
     end

But, after writing that this makes more sense:

puts case [p1, p2]
        when %w[r r], %w[p p], %w[s s]
          'Tie'
        when %w[r p], %w[p s], %w[s r]
          'P1 wins'
        when %w[r s], %w[p r], %w[s p]
          'P2 wins'
        end

Here's a test:

[
  %w[r r], %w[p p], %w[s s],
  %w[r p], %w[p s], %w[s r],
  %w[r s], %w[p r], %w[s p]
  ].each do |p1, p2|

    puts case [p1, p2]
         when %w[r r], %w[p p], %w[s s]
           'Tie'
         when %w[r p], %w[p s], %w[s r]
           'P1 wins'
         when %w[r s], %w[p r], %w[s p]
           'P2 wins'
         end

  end
# >> Tie
# >> Tie
# >> Tie
# >> P1 wins
# >> P1 wins
# >> P1 wins
# >> P2 wins
# >> P2 wins
# >> P2 wins
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • Wow that looks great, I find the second option pretty neat, and thanks for the `%w` bit, I have never seen it before, pretty handy. – Leonardo Guedez Mar 01 '15 at 04:24