ruby - SECADO de tijeras de papel roca
methods dry (4)
Soy un programador de rubí novato y, aunque este código funciona, me pregunto cómo puedo mejorarlo. Tengo un conocimiento muy limitado sobre lambdas y procs y similares, pero cualquier consejo sería genial. ¿Hay alguna manera de simplificar las declaraciones if else
en cada caso? Además, ¿hay alguna manera alternativa de omitir el enunciado de case
lugar de hacer que casi la totalidad del código sea una declaración grande si no?
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")
Aquí hay un par de formas:
# 1 Usar ciclo de matriz
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 Lleva la respuesta de @MiFoFoX un paso más allá
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"]
Aquí:
h #=> {["rock", "paper"]=>"lose", ["paper", "rock"]=>"win",
# ["paper", "scissors"]=>"lose", ["scissors", "paper"]=>"win",
# ["scissors", "rock"]=>"lose", ["rock", "scissors"]=>"win"}
y debido al valor predeterminado "empate":
h[["rock", "rock"]] #=> "tie"
h[["paper", "paper"]] #=> "tie"
h[["scissors", "scissors"]] #=> "tie"
Puede construir un hash que contenga la selección y qué opción perder contra esa selección:
hash = {''scissors'' => ''paper'', ''rock'' => ''scissors'', ''paper'' => ''rock''}
Luego, comprueba si la selección de la máquina es la misma que la que hizo:
roll_ops = ["rock", "paper", "scissors"]
pick = roll_ops.sample
if roll == pick
Y la condición de ganar / perder se convierte en algo como esto:
if hash[roll] == pick
"win"
else
"lose"
end
Agradable y limpio con solo 2 condiciones.
Creo que un proceso u otra configuración similar es probablemente excesivo. Solo use ifs en línea:
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")
Eliminé tu extra adicional que se suponía que manejaba sin entrada. Es mejor usar errores en tal caso.
Hay un par de trucos aquí:
1- Los ifs en línea. Esos deberían ser bastante claros.
2- La variable de resultado se establece igual al valor de retorno de la expresión if. Este es un truco útil que puedes usar porque en Ruby, ¡todo es una expresión!
Si está interesado en usar una lambda para esto, también debería funcionar bastante bien:
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
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