烘干岩石剪刀

时间:2015-08-19 20:38:02

标签: ruby methods dry

我是一名新手ruby程序员,虽然这段代码有效,但我想知道如何改进它。我对lambda和procs等知识非常有限,但任何建议都会很棒。在每种情况下,有没有办法简化if else语句?另外,是否有任何替代方法可以跳过case语句而不是将几乎整个代码作为一个大的if else语句?

def rps(roll)
    roll_ops = ["rock", "paper", "scissors"]
    pick = roll_ops.sample
    result = nil
    if roll == pick
        result = "tie"
    else
    case roll
    when "scissors" then
        if pick == "paper"
            result = "win"
        else
            result = "lose"
        end
    when "rock" then
        if pick == "scissors"
            result = "win"
        else
            result = "lose"
        end
    when "paper" then
        if pick == "rock"
            result = "win"
        else
            result = "lose"
        end
    else
        puts "Please input rock paper or scissors"
    end
    end

    puts "#{pick}, #{result}"
end

rps("scissors")

4 个答案:

答案 0 :(得分:4)

您可以构建一个包含选择的哈希,以及针对该选择丢失的选项:

hash = {'scissors' => 'paper', 'rock' => 'scissors', 'paper' => 'rock'}

然后检查机器选择是否与您一样:

roll_ops = ["rock", "paper", "scissors"]
pick = roll_ops.sample
if roll == pick

赢/输条件变成这样:

if hash[roll] == pick
  "win"
else
  "lose"
end

只有2个条件,很干净。

答案 1 :(得分:2)

ROLL_OPS = %w[rock paper scissors]
RESULTS = %w[tie lose win]
def rps(roll)
  unless i = ROLL_OPS.index(roll)
    return puts "Please input rock paper or scissors".freeze
  end
  pick = ROLL_OPS.sample
  puts "#{pick}, #{RESULTS[(i - ROLL_OPS.index(pick)) % 3]}"
end

答案 2 :(得分:2)

以下是两种方法:

#1使用Array#cycle

OPS = %w[rock paper scissors]

def rps(roll)
  pick = OPS.sample
  enum = OPS.cycle
  (prev = enum.next) until enum.peek == roll
  return [pick, "lose"] if prev == pick
  enum.next
  return [pick, "win"] if enum.peek == pick
  [pick, "tie"]
end

rps "scissors" #=> ["scissors", "tie"] 
rps "scissors" #=> ["scissors", "tie"] 
rps "scissors" #=> ["rock", "win"] 
rps "scissors" #=> ["paper", "lose"] 

#2将@MurifoX的答案更进一步

def rps(roll)
  roll_ops = %w|rock paper scissors|
  h = (roll_ops + [roll_ops.first]).each_cons(2).
    with_object(Hash.new("tie")) { |(a,b),h| h[[a,b]]="lose"; h[[b,a]]="win" }
  pick = roll_ops.sample
  [pick, h[[roll,pick]]]
end

rps "scissors" #=> ["rock", "lose"] 
rps "scissors" #=> ["scissors", "tie"] 
rps "scissors" #=> ["paper", "win"] 

下面:

h #=> {["rock", "paper"]=>"lose", ["paper", "rock"]=>"win",
  #    ["paper", "scissors"]=>"lose", ["scissors", "paper"]=>"win",
  #    ["scissors", "rock"]=>"lose", ["rock", "scissors"]=>"win"} 

并且由于默认值“tie”:

h[["rock", "rock"]]         #=> "tie"
h[["paper", "paper"]]       #=> "tie"
h[["scissors", "scissors"]] #=> "tie"

答案 3 :(得分:1)

我认为proc或其他类似的设置可能有点过分。只需使用inline-ifs:

def rps(roll)
  raise "Choose rock, paper, or scissors" if roll.nil?
  roll_ops = ["rock", "paper", "scissors"]
  pick = roll_ops.sample
  result = if roll == pick
    "tie"
  else
    case roll
    when "scissors"
      pick == "paper" ? 'win' : 'lose'
    when "rock"
      pick == "scissors" ? 'win' : 'lose'
    when "paper" then
      pick == "rock" ? 'win' : 'lose'
    end
  end
  puts "#{pick}, #{result}"
end

rps("scissors")

我删除了你应该处理非输入的额外的其他内容。在这种情况下最好使用错误。

这里有一些技巧:

1-内联ifs。那些应该很清楚。

2-结果变量设置为等于if表达式的返回值。这是一个方便的技巧,你可以使用,因为在Ruby中,一切都是表达式!

如果你对使用lambda感兴趣,它应该也能很好地工作:

def rps(roll)
  raise "Choose rock, paper, or scissors" if roll.nil?
  roll_ops = ["rock", "paper", "scissors"]
  pick = roll_ops.sample
  did_win = lambda do |choice|
    return choice == pick ? 'win' : 'lose'
  end
  result = if roll == pick
    "tie"
  else
    case roll
    when "scissors"
      did_win.call('paper')
    when "rock"
      did_win.call('scissors')
    when "paper" then
      did_win.call('rock')
    end
  end
  puts "#{pick}, #{result}"
end