Hw Impossibility: "Create a Rock Paper Scissors Program in Ruby Without Using Conditionals"

HW impossibility?: Create a rock paper scissors program in ruby WITHOUT using conditionals

Here's one only using hashes:

RULES = {
:rock => {:rock => :draw, :paper => :paper, :scissors => :rock},
:paper => {:rock => :paper, :paper => :draw, :scissors => :scissors},
:scissors => {:rock => :rock, :paper => :scissors, :scissors => :draw}
}

def play(p1, p2)
RULES[p1][p2]
end

puts play(:rock, :paper) # :paper
puts play(:scissors, :rock) # :rock
puts play(:scissors, :scissors) # :draw

Learning ruby, what do these snippets of code mean?

I admit, this is not the most readable code for a novice programmer. I rewrote it, extracted some variables and added comments. Hope you can understand it better now.

def winner(p1, p2)
# rules of dominance, who wins over who
wins = {
rock: :scissors,
scissors: :paper,
paper: :rock
}

# this hash is here to bypass restriction on using conditional operators
# without it, the code would probably look like
# if condition
# p1
# else
# p2
# end
answers = {
true => p1,
false => p2
}

# given the choice of first player, which element can he beat?
element_dominated_by_first_player = wins[p1]

# did the second player select the element that first player can beat?
did_player_one_win = element_dominated_by_first_player == p2

# pick a winner from our answers hash
answers[did_player_one_win]
end

winner(:rock, :scissors) # => :rock
winner(:rock, :paper) # => :paper
winner(:scissors, :paper) # => :scissors

ruby: Rock Scissors Paper program. How to make algorithm function properly?

def judge(p1, p2)
case
when @wins[p1] == p2 then "Win"
when @wins[p2] == p1 then "Lose"
else "Draw"
end
end

Is there a way to include an 'OR' statement in this method? (Ruby) Rock, Paper, Scissors

(x == y && z == a) || (x == b && z == y) and so on should do the trick?

If-less programming (basically without conditionals)

There are some resources on the Anti-IF Campaign site, such as this article.

I believe it's a matter of degree. Conditionals aren't always bad, but they can be (and frequently are) abused.

Additional thoughts (one day later)

Refactoring: Improving the Design of Existing Code is a good reference on this subject (and many others). It covers Replace Conditional with Polymorphism. There's also a new one, Replace Conditional with Visitor, on the web site.

I value simplicity and single responsibility over removing all if statements. These three goals often coincide. Static analysis tools that support the cyclomatic complexity metric can quickly point out code with nested or serial conditionals. The if statements may remain post-refactoring, but could be broken out into smaller methods and/or multiple classes.

Update: Michael Feathers wrote an article on Unconditional Programming.

This is a popular topic: Phil Haack on Death to the IF statement!

Call * method on implicit receiver

That's not possible. There are some methods that simply cannot be called without an explicit receiver because they would otherwise be ambiguous. In particular, in every case where you have both a unary prefix and a binary infix operator, it would be impossible to distinguish the two cases:

+ a == a.+@()
- a == a.-@()
& a # interpreted as the unary prefix proc-block conversion operator
* a # interpreted as the unary prefix splat operator

or in cases where the operator conflicts with other syntax:

/ a # interpreted as the start of a Regexp literal

For consistency, Ruby forces the use of two operands for all binary infix operators, not just the ones for which the grammar would be ambiguous.

Likewise, [] cannot be called without an explicit receiver because it would conflict with literal syntax for arrays.

The other well-known example of methods that cannot be called without an explicit receiver, is setters:

self.foo = bar # setter
foo = bar # local variable

For private setters, there is actually an exception to the rule for private methods, that allows them to be called with an explicit receiver, as long as that explicit receiver is the literal pseudo-variable keyword self. However, no such exception exists for calling private binary operators or methods like []. (There are proposals to that effect, though.)

Manipulating arrays with recursive function

Several problems with your original code:

  • You mix iteration with recursion
  • You throw away the result of the recursion (rps_tournament_winner(tournament[i]))
  • You don't return anything useful (return simply returns nil, but it doesn't matter, because you don't use the result anyways)

A fixed version using the original logic would be:

def rps_tournament_winner(tournament)
result = []
for i in 0..1 do
if tournament[i][0][0].is_a? Array then
result << rps_tournament_winner(tournament[i])
else
result << rps_game_winner(tournament[i])
end
end
return result
end

But actually that's equivalent to a simple

def rps_tournament_winner(tournament)
if tournament[0][0].is_a? String
rps_game_winner(tournament)
else
tournament.map { |t| rps_tournament_winner(t) }
end
end

And it would be so much nicer using objects:

class Game < Struct.new(:player1, :choice1, :player2, :choice2)
def winner
'PRSP'.include?(choice1 + choice2) ? player1 : player2
end
end

def rps_tournament_winner(tourn)
return tourn.winner if tourn.is_a? Game
tourn.map { |t| rps_tournament_winner(t) }
end


Related Topics



Leave a reply



Submit