Ruby 如何简化代码?

Ruby 如何简化代码?,ruby,Ruby,我是Ruby的新手,我想出了这个小游戏。感觉太长了,但我不确定。有没有办法简化内部的if语句?我应该使用while还是可以使用其他技术 如果这个问题不好,请原谅我。在发布代码之前,我尽了最大努力修复代码 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 no

我是Ruby的新手,我想出了这个小游戏。感觉太长了,但我不确定。有没有办法简化内部的if语句?我应该使用while还是可以使用其他技术

如果这个问题不好,请原谅我。在发布代码之前,我尽了最大努力修复代码

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

这更像是一个代码审查问题。 尽管如此,这里还是有一些建议/意见:

  • win(reason)
    从不使用
    reason
  • 朋友意识
    仅用于
    while
    循环,从不更改。可以去掉它,只需在为true时放入
  • 您的语句,如
    if response==(“kick”| |“punch”)
    不是您想要的。如果response==“kick”| response==“punch”
    ,请尝试
    if response==“kick”| | response==“punch”
    ,对于多个匹配,最好使用正则表达式:
    if response=~/^(kick | punch)$/
    • ^
      将匹配锚定到字符串的开头
    • $
      将匹配锚定到字符串的末尾
    • 结果是整个字符串必须匹配
  • 否则,这是一套相互依赖的规则,可能不会以更好的方式存在

    除了踢| puch |嘲弄之外的任何事情最终都会让你成为柯德

    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
    等人的声明

    这更像是一个代码审查问题。 尽管如此,这里还是有一些建议/意见:

  • win(reason)
    从不使用
    reason
  • 朋友意识
    仅用于
    while
    循环,从不更改。可以去掉它,只需在为true时放入
  • 您的语句,如
    if response==(“kick”| |“punch”)
    不是您想要的。如果response==“kick”| response==“punch”
    ,请尝试
    if response==“kick”| | response==“punch”
    ,对于多个匹配,最好使用正则表达式:
    if response=~/^(kick | punch)$/
    • ^
      将匹配锚定到字符串的开头
    • $
      将匹配锚定到字符串的末尾
    • 结果是整个字符串必须匹配
  • 否则,这是一套相互依赖的规则,可能不会以更好的方式存在

    除了踢| puch |嘲弄之外的任何事情最终都会让你成为柯德

    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
    等人的声明您可以做两件事,这将大大提高可读性和可维护性。首先,使其面向对象。我不是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
    
    我已将游戏循环放入
    游戏#play方法。当玩家输入移动时,
    游戏移动方法<代码>移动
    检查这是否是有效的移动,如果是,则使用
    send
    调用同名的方法,例如,如果玩家输入
    “kick”
    ,则调用
    kick
    方法(我们尚未定义)。如果这不是一个有效的移动,
    游戏#坏的#移动方法

    在我们充实
    kick
    punch
    等方法之前,我们应该将每个结果放在自己的方法中。您有五个失败条件,我们称之为
    lose_1
    lose_2
    ,等等,还有一个获胜条件,
    win_1
    。还有两个条件设置了
    friend.angry
    friend.blooding
    ,因此我们也将为这些设置方法。这是一个开始:

    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\u流血
    friend\u生气
    ,以及
    win\u 1
    更新friend对象的状态。
    lose.*
    方法调用
    lose方法

    现在我们有了这些方法,让我们看看你的游戏逻辑。我花时间将不同的举措和友邦及其结果列成一张表格:

    生气吗?流血?结果
    -----  ------  ---------  ---------------
    踢出真正的胜利1
    踢真假输1
    踢错-输2
    打孔真的真的输3
    打真假朋友!
    打孔错误-丢失2
    嘲弄真正的失去3
    嘲弄真假输4
    嘲笑虚伪的朋友
    
    当我们以这种方式对其进行排序时,就可以清楚地知道如何编写我们的
    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
    
    它们的优点是很容易阅读。您可能会注意到,除了调用的结果方法的名称之外,它们都是相同的,如果您查看表,这是有意义的:按“move”分组,第二列和第三列是相同的

    我们可以将这些方法组合成一个非常简洁的方法,但可读性会受到很大影响。我们还可以将每一个都转换为一个带有三元运算符的线性,得到相同的结果。我认为这是简洁性和可读性之间的一个很好的折衷

    我们还需要一个坏动作
    method,但我要将其作为
    lose_5
    方法的别名:

    alias :bad_move! :lose_5
    
    最后,我们需要
    win
    丢失结束游戏的方法:

    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!
    

    您可以做两件事,这将对可读性和可维护性产生重大影响。首先,使其面向对象。我不是OO狂热者,但我认为这很适合。其次,移动大量日志