我对Ruby非常陌生并且想出了这个小游戏。感觉它太长了,但我不确定。有没有办法简化里面的if语句?我也应该使用,还是可以使用其他技术?
如果这是一个糟糕的问题,请原谅我。在发布代码之前,我尽最大努力修复代码。
def win(reason)
puts "You win!"
exit(0)
end
def boring(reason)
puts reason + " Game over!"
exit(0)
end
puts "Your friend wants to fight now!"
friend_conscious = true
friend_bleeding = false
friend_angry = false
while friend_conscious
puts "Do you kick, punch or taunt?"
print "> "
response = gets.chomp
if response == ("kick" || "punch") && !friend_angry
puts "You try to hit your friend."
boring("You lost the fight, you suck!")
elsif response == "taunt" && !friend_angry
puts "Your friend is angry!"
friend_angry = true
elsif response == "taunt" && !friend_bleeding
puts "Your friend is too angry, he knocks you out!"
boring("You lost the fight, you suck!")
elsif response == "kick" && !friend_bleeding
puts "Your friend dodges your kick and knocks you out."
boring("You lost the fight, you suck!")
elsif response == "punch" && !friend_bleeding
puts "Your friend is bleeding"
friend_bleeding = true
elsif response == ("taunt" || "punch") && friend_bleeding
puts "Your friend lunges at you, knocking you to the ground."
puts "He then beats you up."
boring("You lost the fight, you suck!")
elsif response == "kick" && friend_bleeding
puts "You kick your friend in the balls, he falls to the ground"
win("You won the fight! What a great holiday.")
else
puts "Your friend knocks you out."
boring("You lost the fight, you suck!")
end
puts "What's your next move?"
end
答案 0 :(得分:0)
这是一个代码审查问题。 尽管如此,这里有一些指示/意见:
win(reason)
从不对reason
friend_conscious
仅用于while
循环,并且永远不会更改。可以摆脱它,只需放置while true
if response == ("kick" || "punch")
之类的陈述不符合您的意图。试试if response == "kick" || response == "punch"
,甚至更好地使用正则表达式进行多次匹配:if response =~ /^(kick|punch)$/
^
将匹配锚定到字符串的开头$
将匹配锚定到字符串的结尾否则,它是一组依赖规则,可能不会以更好的方式存在。
除了kick | puch | taunt以外的任何东西最终都会被你KOd
if response !~ /^(kick|punch|taunt)$/
puts "Your friend knocks you out."
boring("You lost the fight, you suck!")
else
if !friend_angry
if response =~ /^(kick|punch)$/
puts "You try to hit your friend."
boring("You lost the fight, you suck!")
elsif response == "taunt"
puts "Your friend is angry!"
friend_angry = true
end
elsif !friend_bleeding
if response == "taunt"
puts "Your friend is too angry, he knocks you out!"
boring("You lost the fight, you suck!")
elsif response == "kick"
puts "Your friend dodges your kick and knocks you out."
boring("You lost the fight, you suck!")
elsif response == "punch"
puts "Your friend is bleeding"
friend_bleeding = true
elsif friend_bleeding
if response =~ /^(taunt|punch)$/
puts "Your friend lunges at you, knocking you to the ground."
puts "He then beats you up."
boring("You lost the fight, you suck!")
elsif response == "kick"
puts "You kick your friend in the balls, he falls to the ground"
win("You won the fight! What a great holiday.")
end
end
puts "What's your next move?"
end
然后,您可以更进一步,将每个主要部分拉出自己的功能,即:
def process_not_friend_angry(response)
if response =~ /^(kick|punch)$/
puts "You try to hit your friend."
boring("You lost the fight, you suck!")
elsif response == "taunt"
puts "Your friend is angry!"
friend_angry = true
end
end
确保您的功能低于friend_angry
et al
答案 1 :(得分:0)
您可以做两件事,这对可读性和可维护性有很大影响。首先,使这个面向对象。我不是OO狂热者,但我认为这是一个很好的选择。其次,将大量逻辑转化为方法。这将使代码整体更具可读性,并且可以更容易地为其编写测试。
首先,让我们写一个简单的课程来跟踪你朋友的状态:
class Friend
attr_writer :conscious, :bleeding, :angry
def initialize
@conscious = true
@bleeding = false
@angry = false
end
def conscious?; @conscious end
def bleeding?; @bleeding end
def angry?; @angry end
end
你可以像这样使用它:
friend = Friend.new
friend.angry? # => false
friend.angry = true
friend.angry? # => true
接下来,一个跟踪游戏状态的课程:
class Game
VALID_MOVES = %w[ kick punch taunt ].freeze
attr_reader :friend
def initialize
@friend = Friend.new
end
def play!
while friend.conscious?
puts "Do you kick, punch or taunt?"
print "> "
response = gets.chomp
move!(response)
puts
end
win!
end
private
def move!(kind)
return send(kind) if VALID_MOVES.include?(kind)
bad_move!
end
# ...
end
我已将游戏循环放入Game#play!
方法中。当玩家进入移动时,会调用Game#move!
方法。 move!
检查它是否为有效移动,如果是,则使用send
调用具有相同名称的方法,例如如果玩家输入"kick"
,则调用kick
方法(我们尚未定义)。如果它不是有效的移动,则会调用Game#bad_move!
方法。
在我们充实kick
,punch
等方法之前,我们应该将每个结果都放在自己的方法中。您有五种失败条件,我们会调用lose_1
,lose_2
等,以及一种获胜条件win_1
。还有两个设置friend.angry
和friend.bleeding
的条件,因此我们也会为这些设置方法。这是一个开始:
def friend_bleeding
puts "Your friend is bleeding"
friend.bleeding = true
end
def friend_angry
puts "Your friend is angry!"
friend.angry = true
end
def win_1
puts "You kick your friend in the balls, he falls to the ground."
friend.conscious = false
end
def lose_1
puts "Your friend dodges your kick and knocks you out."
lose!
end
def lose_2
puts "You try to hit your friend."
lose!
end
# ...
您可以看到friend_bleeding
,friend_angry
和win_1
更新了Friend对象的状态。 lose_*
方法调用lose!
方法。
现在我们有了这些方法,让我们来看看你的游戏逻辑。我花时间制作了不同动作和朋友状态及其结果的表格:
move angry? bleeding? outcome
----- ------ --------- ---------------
kick true true win_1
kick true false lose_1
kick false - lose_2
punch true true lose_3
punch true false friend_bleeding
punch false - lose_2
taunt true true lose_3
taunt true false lose_4
taunt false - friend_angry
当我们以这种方式对其进行排序时,我们会清楚地知道如何编写kick
,punch
等方法:
def kick
if friend.angry?
return win_1 if friend.bleeding?
lose_1
else
lose_2
end
end
def punch
if friend.angry?
return lose_3 if friend.bleeding?
friend_bleeding
else
lose_2
end
end
def taunt
if friend.angry?
return lose_3 if friend.bleeding?
lose_4
else
friend_angry
end
end
这些的优点是它们非常容易阅读。您可能会注意到,除了调用的结果方法的名称之外,每个都是相同的,如果您查看表格,这是有意义的:按"移动,"第二列和第三列完全相同。
我们可以将这些方法组合成一个非常简洁的方法,但可读性会受到很大影响。我们也可以将每个变为带有三元运算符的单行,结果相同。我认为这是简洁和可读性之间的良好折衷。
我们还需要一种bad_move!
方法,但我只想将其作为lose_5
方法的别名:
alias :bad_move! :lose_5
最后,我们需要结束游戏的win!
和lose!
方法:
def win!
puts "You won the fight! What a great holiday.",
exit(0)
end
def lose!
puts "You lost the fight, you suck! Game over!"
exit(0)
end
让我们把它们放在一起:
class Friend
attr_writer :conscious, :bleeding, :angry
def initialize
@conscious = true
@bleeding = false
@angry = false
end
def conscious?; @conscious end
def bleeding?; @bleeding end
def angry?; @angry end
end
class Game
VALID_MOVES = %w[ kick punch taunt ].freeze
attr_reader :friend
def initialize
@friend = Friend.new
end
def play!
while friend.conscious?
puts "Do you kick, punch or taunt?"
print "> "
response = gets.chomp
move!(response)
puts
end
win!
end
private
def move!(kind)
return send(kind) if VALID_MOVES.include?(kind)
bad_move!
end
# Moves
def kick
if friend.angry?
return win_1 if friend.bleeding?
lose_1
else
lose_2
end
end
def punch
if friend.angry?
return lose_3 if friend.bleeding?
friend_bleeding
else
lose_2
end
end
def taunt
if friend.angry?
return lose_3 if friend.bleeding?
lose_4
else
friend_angry
end
end
def bad_move!
lose_5
end
# Outcomes
def friend_bleeding
puts "Your friend is bleeding"
friend.bleeding = true
end
def friend_angry
puts "Your friend is angry!"
friend.angry = true
end
def win_1
puts "You kick your friend in the balls, he falls to the ground."
friend.conscious = false
end
def lose_1
puts "Your friend dodges your kick and knocks you out."
lose!
end
def lose_2
puts "You try to hit your friend."
lose!
end
def lose_3
puts "Your friend lunges at you, knocking you to the ground."
puts "He then beats you up."
lose!
end
def lose_4
puts "Your friend is too angry, he knocks you out!"
lose!
end
def lose_5
puts "Your friend knocks you out."
lose!
end
def win!
puts "You won the fight! What a great holiday.",
exit(0)
end
def lose!
puts "You lost the fight, you suck! Game over!"
exit(0)
end
end
Game.new.play!