烘干岩纸剪刀
我是一个新手ruby程序员,虽然这段代码有效,但我想知道如何改进它。 我对lambdas和procs等知识非常有限,但任何建议都会很棒。 有没有办法在每种情况下简化if else
语句? 另外,是否有任何替代方法可以跳过case
语句,而不是将几乎整个代码作为else if语句?
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")
您可以构建包含选择的散列以及针对该选择丢失的选项:
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个条件,干净整洁。
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
以下是几种方法:
#1使用Array#循环
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"
我认为proc或其他类似的设置可能有点过分。 只需使用内联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