【问题标题】:Ruby Greed Koan - How can I improve my if/then soup?Ruby Greed Koan - 我怎样才能改善我的 if/then 汤?
【发布时间】:2011-01-20 16:46:18
【问题描述】:

我正在阅读 Ruby Koans,以便尝试学习 Ruby,到目前为止,一切都很好。我已经了解了贪婪公案,在撰写本文时是 183。我有一个可行的解决方案,但我觉得我只是拼凑了一堆 if/then 逻辑,而我不是拥抱 Ruby 模式。

在下面的代码中,您有什么方法可以让我更全面地接受 Ruby 模式? (我的代码包含在“MY CODE [BEGINS|ENDS] HERE”cmets 中。

# Greed is a dice game where you roll up to five dice to accumulate
# points.  The following "score" function will be used calculate the
# score of a single roll of the dice.
#
# A greed roll is scored as follows:
#
# * A set of three ones is 1000 points
#
# * A set of three numbers (other than ones) is worth 100 times the
#   number. (e.g. three fives is 500 points).
#
# * A one (that is not part of a set of three) is worth 100 points.
#
# * A five (that is not part of a set of three) is worth 50 points.
#
# * Everything else is worth 0 points.
#
#
# Examples:
#
# score([1,1,1,5,1]) => 1150 points
# score([2,3,4,6,2]) => 0 points
# score([3,4,5,3,3]) => 350 points
# score([1,5,1,2,4]) => 250 points
#
# More scoring examples are given in the tests below:
#
# Your goal is to write the score method.

# MY CODE BEGINS HERE

def score(dice)

  # set up basic vars to handle total points and count of each number
  total = 0
  count = [0, 0, 0, 0, 0, 0]

  # for each die, make sure we've counted how many occurrencess there are
  dice.each do |die|
    count[ die - 1 ] += 1
  end

  # iterate over each, and handle points for singles and triples
  count.each_with_index do |count, index|
    if count == 3
      total = doTriples( index + 1, total )
    elsif count < 3
      total = doSingles( index + 1, count, total )
    elsif count > 3
      total = doTriples( index + 1, total )
      total = doSingles( index + 1, count % 3, total )
    end
  end

  # return the new point total
  total

end

def doTriples( number, total )
  if number == 1
    total += 1000
  else
    total += ( number ) * 100
  end
  total
end

def doSingles( number, count, total )
  if number == 1
    total += ( 100 * count )
  elsif number == 5
    total += ( 50 * count )
  end
  total
end

# MY CODE ENDS HERE

class AboutScoringProject < EdgeCase::Koan
  def test_score_of_an_empty_list_is_zero
    assert_equal 0, score([])
  end

  def test_score_of_a_single_roll_of_5_is_50
    assert_equal 50, score([5])
  end

  def test_score_of_a_single_roll_of_1_is_100
    assert_equal 100, score([1])
  end

  def test_score_of_multiple_1s_and_5s_is_the_sum_of_individual_scores
    assert_equal 300, score([1,5,5,1])
  end

  def test_score_of_single_2s_3s_4s_and_6s_are_zero
    assert_equal 0, score([2,3,4,6])
  end

  def test_score_of_a_triple_1_is_1000
    assert_equal 1000, score([1,1,1])
  end

  def test_score_of_other_triples_is_100x
    assert_equal 200, score([2,2,2])
    assert_equal 300, score([3,3,3])
    assert_equal 400, score([4,4,4])
    assert_equal 500, score([5,5,5])
    assert_equal 600, score([6,6,6])
  end

  def test_score_of_mixed_is_sum
    assert_equal 250, score([2,5,2,2,3])
    assert_equal 550, score([5,5,5,5])
  end

end

非常感谢您在我尝试了解 Ruby 时提供的任何帮助。

【问题讨论】:

    标签: ruby


    【解决方案1】:

    哇!这里有很多非常酷的方法。我喜欢每个人的创造力。但是,我对此处提供的所有答案都有一个教学问题。 (“教育学是对……教学过程的研究。”——维基百科)

    从前几个 koans(回到 about_asserts.rb)中可以明显看出,启蒙之路不需要任何 Ruby 的先验/外部知识。很明显,Path 甚至不需要事先的编程经验。因此,从教育的角度来看,此公案必须可回答,仅使用早期公案中教授的方法、语言结构和编程技术。这意味着:

    • 没有Enumerable#each_with_index
    • 没有Enumerable#count
    • 没有Enumerable#sort
    • 没有Hash.new(0)指定默认值
    • 没有Numeric#abs
    • 没有Numeric#divmod
    • 没有递归
    • 没有 case when

    现在,我并不是说你不允许在你的实现中使用这些东西,但是公文不能要求使用它们。 必须有一个解决方案,只使用先前 koans 引入的结构。

    另外,因为模板只是

    def score(dice)
      # You need to write this method
    end
    

    似乎暗示该解决方案不应定义其他方法或类。也就是说,您应该只替换 # You need to write this method 行。

    这是一个符合我的哲学要求的解决方案:

    def score (dice)
        sum = 0
        (1..6).each do |i|
            idice = dice.select { |d| d == i }
            count = idice.size
    
            if count >= 3
                sum += (i==1 ? 1000 : i*100)
            end
            sum += (count % 3) * 100   if i == 1
            sum += (count % 3) *  50   if i == 5
        end
        sum
    end
    

    这里的方法/构造在以下koan文件中介绍:

    Enumerable#each    about_iteration.rb
    Enumerable#select  about_iteration.rb
    Array#size         about_arrays.rb
    a ? b : c          about_control_statements.rb
    %                  about_control_statements.rb
    

    相关 StackOverflow 问题:

    【讨论】:

    • 这是我最喜欢的,因为它只使用了 koans 中以前出现的内容。我建议您在定义“idice”的行中执行一次“.size”操作,但除此之外我们的解决方案是相同的。或者,一旦我从太多天做 C# 重构为 Rubyisms.. .
    • @PlayTank:同意。我更新了实现以将大小存储在 count 变量中。我在单独的行中定义了count,因为我不记得是否明确教导您可以将.size 直接链接到块上。
    【解决方案2】:

    一个学生问 Joshu,“我如何编写一个算法来计算骰子游戏的分数?”

    乔修用棍子敲打学生说:“用计算器。”

    def score(dice)
      score = [0, 100, 200, 1000, 1100, 1200][dice.count(1)]
      score += [0, 50, 100, 500, 550, 600][dice.count(5)]
      [2,3,4,6].each do |num|
          if dice.count(num) >= 3 then score += num * 100 end
      end
      score
    end
    

    【讨论】:

    • 这里是最简单的答案,恕我直言。就个人而言,我会选择score += num * 100 if dice.count(num) &gt;= 3,因为它更清楚地向我表达了“业务逻辑”。
    • 这就是我来这里寻找的东西。太棒了。
    • 如果我们能有一个如此简洁的答案,而且可以扩展到无限数量的骰子,那就太好了......
    【解决方案3】:

    我一次完成并通过了每一项测试。不确定这是一个非常“红宝石”的解决方案,但我确实喜欢每个部分都在做什么,并且没有多余的值声明

    def score(dice)
      ## score is set to 0 to start off so if no dice, no score
      score = 0
      ## setting the 1000 1,1,1 rule
      score += 1000 if (dice.count(1) / 3) == 1
      ## taking care of the single 5s and 1s here
      score += (dice.count(5) % 3) * 50
      score += (dice.count(1) % 3) * 100
      ## set the other triples here
      [2, 3, 4, 5, 6].each do |num|
        score += num * 100 if (dice.count(num) / 3 ) == 1
      end
      score
    end
    

    【讨论】:

      【解决方案4】:

      看起来不错。我可能写了一些稍微不同的东西,比如:

      def do_triples number, total
        total + (number == 1 ? 1000 : number * 100)
      end
      

      如果你想做一些除了 Ruby 之外很少有其他语言可以做的事情,我认为以下 可能 在 DIE 和 DRY 下是合理的,在交替的星期二,但我不认为那些 Ruby 格言真正打算应用于常见的子表达式消除。无论如何:

      def do_triples number, total
        total +
        if number == 1
          1000
        else
          number * 100
        end
      end
      
      def do_triples number, total
        if number == 1
          1000
        else
          number * 100
        end + total
      end
      

      【讨论】:

      • 喜欢这个,谢谢罗斯。肯定会实施,我会回来报告的。
      【解决方案5】:

      这就是我所做的。看起来与一些较旧的回复非常相似。我很想为这个找到一些巧妙的注入用法(mikeonbike 的那个是 niiiice)。

      def score(dice)
        total = 0
      
        # handle triples scores for all but '1'
        (2..6).each do |num|
          total += dice.count(num) / 3 * num * 100
        end
      
        # non-triple score for '5'
        total += dice.count(5) % 3 * 50
      
        # all scores for '1'
        total += dice.count(1) / 3 * 1000 + dice.count(1) % 3 * 100
      
        total
      end
      

      【讨论】:

      • 这是我最喜欢的,因为它最容易阅读,特别是如果剩下的(非三重)一个分数有自己的线,比如 5 分
      • 谢谢@Will! cmets 确实帮助我在编写代码时保持逻辑清晰。
      【解决方案6】:

      您可以将其压缩为更少的行,但算法的可读性会丢失,所以我最终得到了这个:

      def score(dice)
        result = 0;
      
        (1..6).each do |die|
          multiplier = die == 1 ? 1000 : 100
          number_of_triples = dice.count(die) / 3
          result += die * multiplier * number_of_triples
        end
      
        result += 100 * (dice.count(1) % 3)
      
        result += 50 * (dice.count(5) % 3)
      end
      

      如果您使用的是 1.8.6,则必须使用 backports 或自己将 count 方法添加到 Array:

      class Array
        def count(item)
          self.select { |x| x == item }.size
        end
      end
      

      【讨论】:

      • 很好,这非常清晰简洁。我的方法类似,但不太优雅。我确实认为使用return 0 if dice.empty? 作为方法的第一行快速失败是个好主意。
      【解决方案7】:

      这是我经过大约四次迭代并尝试利用我正在学习的 Ruby 构造做 koans 后得到的答案:

      def score(dice)
        total = 0
        (1..6).each { |roll| total += apply_bonus(dice, roll)}
        return total
      end
      
      def apply_bonus(dice, roll, bonus_count = 3)
        bonus = 0
        bonus = ((roll == 1 ? 1000 : 100) * roll) if (dice.count(roll) >= bonus_count)
        bonus += 50 * (dice.count(5) % bonus_count) if (roll == 5)
        bonus += 100 * (dice.count(1) % bonus_count)  if (roll == 1)
        return bonus
      end
      

      【讨论】:

        【解决方案8】:

        另一个答案:)

        def score(dice)
          score = 0
          for num in 1..6
            occurrences = dice.count {|dice_num| dice_num == num}
            score += 1000 if num == 1 and occurrences >= 3
            score += 100 * (occurrences % 3) if num == 1
            score += 100 * num if num != 1 and occurrences >= 3
            score += 50 * (occurrences % 3) if num == 5
          end
          score
        end
        

        【讨论】:

          【解决方案9】:

          这是我想出的最简单、最易读的解决方案。这也解释了一些不在测试中的情况,例如掷出 6 个 5 或 6 个 1。

          def score(dice)
            score = 0
            (1..6).each { |d|
              count = dice.find_all { |a| a == d }
              score = ( d == 1 ? 1000 : 100 ) * d if count.size >= 3
              score += (count.size - 3) * 50 if (count.size >= 4) && d == 5
              score += (count.size - 3) * 100 if (count.size >= 4) && d == 1  
              score += count.size * 50 if (count.size < 3) && d == 5
              score += count.size * 100 if (count.size < 3) && d == 1
            }
            score
          end
          

          我选择使用 size 方法而不是 count 方法,因为并非所有版本的 Ruby 都支持 count,并且 koans 未测试计数到此测试。

          【讨论】:

            【解决方案10】:
            def score(dice)
              total = 0
              sets = dice.group_by{|num| num }
            
              sets.each_pair do |num, values|
                number_of_sets, number_of_singles = values.length.divmod(3)
                number_of_sets.times { total += score_set(num) }
                number_of_singles.times { total += score_single(num) }
              end
            
              total
            end
            
            def score_set(num)
              return 1000 if num == 1
              num * 100
            end
            
            def score_single(num)
              return 100 if num == 1
              return 50 if num == 5
              0
            end
            

            【讨论】:

              【解决方案11】:

              这是我在第一次尝试时遇到类似的 if/then/else 混乱之后的最终解决方案。

              def score(dice)
                score = 0
                dice.uniq.each do |roll| 
                  score += dice.count(roll) / 3 * (roll == 1 ? 1000 : 100*roll)
                  score += dice.count(roll) % 3 * (roll == 1 ? 100 : (roll == 5 ? 50 : 0))
                end
                score
              end
              

              【讨论】:

                【解决方案12】:

                我会说你已经让它看起来很像 Ruby。对我来说唯一看起来不太像 Ruby 的就是使用 camelCase 方法名称而不是 snake_case,但当然这是个人约定,我自己没有阅读过 koans。

                除此之外,使用 case/when 或任何其他解决方案不会对您的示例进行太大改进。目标是少于 3 个 elseif 操作,多于这个,您可能想要寻找更好的解决方案。

                【讨论】:

                • 感谢您澄清这一点,injekt。这些是我非常兴奋的技巧类型。当我编写新方法时,我会记住这一点:)
                【解决方案13】:

                您可以将[0, 0, 0, 0, 0, 0] 缩短为[0] * 6,但除了@injekt 提到的camelCase 之外,它对我来说看起来不错。我很高兴在代码审查中看到这一点。

                另外我想你的 doTriples 和 doSingles 并不真的需要它们的临时变量。

                def doTriples( number, total )
                  if number == 1
                    total + 1000
                  else
                    total + ( number ) * 100 # be careful with precedence here
                  end
                end
                

                【讨论】:

                • 非常感谢,面条。一旦我有机会玩这个并实现一些东西,我会回帖。
                • 没问题。我在这里看到了一些关注 ruby​​ koans 的人提出的一些有趣的问题。也许我应该自己去尝试一下。
                • 有趣。那么 += 会进行静默重新分配,而只是 + 返回新的总数?有没有比我遗漏的逻辑更有意义的东西?
                • 实际上相当微妙。在您的原始代码中,您使用+= 来增加条件每个分支中的总数。但是,在 ruby​​ 中,每个表达式都有一个值,因此在我的代码中,if/else/end 的值是评估的任何分支的值。这又是该方法的返回值,因为它是最后一个评估的表达式。 @DigitalRoss 的答案通过将条件的结果用作加法表达式中的术语来进一步说明这一点。这有意义吗?
                【解决方案14】:

                你可能想改变

                  # for each die, make sure we've counted how many occurrencess there are
                  dice.each do |die|
                    count[ die - 1 ] += 1
                  end
                

                转成散列,如

                count = Hash.new(0)
                dice.each do |die|
                  count[die] += 1
                end
                

                甚至

                count = {} # Or Hash.new(0)
                grouped_by_dots = dice.group_by {|die| die}
                1.upto(6) do |dots| # Or grouped_by_dots.each do |dots, dice_with_those_dots|
                  dice_with_those_dots = grouped_by_dots.fetch(dots) {[]}
                  count_of_that_dots = dice_with_those_dots.length
                  count[dots] = count_of_that_dots
                end
                

                这样您就不必在整个代码中乱扔index + 1

                如果 Ruby 有一个内置的 count_by 方法就好了。

                【讨论】:

                • 太棒了,安德鲁,我喜欢这种看待事物的方式,尽管我现在并不完全理解它。会修补它,希望今晚,然后报告。
                【解决方案15】:

                我的 2 美分。为单打/双打提供新方法似乎是一种非常简单的迂回方式。

                def score(dice)
                
                  #fill initial throws
                  thrown = Hash.new(0)
                  dice.each do |die|
                    thrown[die]+=1
                  end
                
                  #calculate score
                  score = 0
                  faces.each do |face,amount|
                    if amount >= 3
                      amount -= 3
                      score += (face == 1 ? 1000 : face * 100)
                    end
                    score += (100 * amount) if (face == 1)
                    score += (50 * amount) if (face == 5)
                  end
                
                  score
                end
                

                【讨论】:

                  【解决方案16】:

                  嗯,

                  这是我的解决方案:

                  def score(dice)
                      total = 0
                  
                      #Iterate through 1-6, and add triples to total if found 
                      (1..6).each { |roll| total += (roll == 1 ? 1000 : 100 * roll) if dice.count(roll) > 2 }
                  
                      #Handle Excess 1's and 5's
                      total += (dice.count(1) % 3) * 100 
                      total += (dice.count(5) % 3) * 50
                  end
                  

                  一旦我找到了数组的“计数”方法,这个练习就非常简单了。

                  【讨论】:

                    【解决方案17】:

                    这是我的答案。不知道好不好,但至少看起来很清楚:)

                    RULEHASH = { 
                        1 => [1000, 100],
                        2 => [100,0],
                        3 => [100,0],
                        4 => [100,0],
                        5 => [100,50],
                        6 => [100,0] 
                    }
                    
                    def score(dice)
                        score = 0
                        RULEHASH.each_pair do |i, rule|
                            mod = dice.count(i).divmod(3)
                            score += mod[0] * rule[0] * i + mod[1] * rule[1]
                        end
                        score
                    end
                    

                    【讨论】:

                      【解决方案18】:

                      我的解决方案不是红宝石风格。只是为了有趣和最短的代码。我们可以通过hash p来设置规则。

                      def score(dice)
                        p = Hash.new([100,0]).merge({1 => [1000,100], 5 => [100,50]})
                        dice.uniq.inject(0) { |sum, n| sum + dice.count(n) / 3 * n * p[n][0] + dice.count(n) % 3 * p[n][1] }
                      end
                      

                      【讨论】:

                        【解决方案19】:

                        我的答案使用“查找表”方法...

                        def score(dice)
                          tally = (1..6).inject(Array.new(7,0)){|a,i| a[i] = dice.count(i); a}
                          rubric = {1 => [0,100,200,1000,1100,1200], 5 => [0,50,100,500,550,600]}
                          score = rubric[1][tally[1]] + rubric[5][tally[5]]
                          [2,3,4,6].each do |i| score += 100 * i if dice.count(i) >= 3 end
                          score
                        end
                        

                        【讨论】:

                          【解决方案20】:

                          我的与此处发布的其他几个相似。

                          score = 0
                          [1,2,3,4,5,6].each {|d| 
                            rolls = dice.count(d)
                            score = (d==1 ? 1000 : 100)*d if rolls >= 3
                            score += 100*(rolls % 3) if d == 1 
                            score += 50*(rolls % 3) if d == 5 
                          }
                          score
                          

                          【讨论】:

                            【解决方案21】:

                            我和我的女朋友这个周末正在经历这些 ruby​​koans,我在这方面玩得很开心,并尝试了许多不同的解决方案。这是一个相当简短的数据驱动解决方案:

                            SCORES = [[1000, 100], [200, 0], [300, 0], [400, 0], [500, 50], [600, 0]]
                            
                            def score(dice)
                              counts = dice.group_by(&:to_i).map { |i, j| [i-1, j.length] }
                              counts.inject(0) do |score, (i, count)|
                                sets, singles = count.divmod 3
                            
                                score + sets * SCORES[i][0] + singles * SCORES[i][1]
                              end
                            end
                            

                            这是我必须的单行字(也许是 FP 版本):

                            SCORES = [[1000, 100], [200, 0], [300, 0], [400, 0], [500, 50], [600, 0]]
                            
                            def score(dice)
                              dice.group_by(&:to_i).inject(0) {|s,(i,j)| s + j.size / 3 * SCORES[i-1][0] + j.size % 3 * SCORES[i-1][1]}
                            end
                            

                            我也走了一些奇怪的路线:

                            SCORES = [[1000, 100], [200, 0], [300, 0], [400, 0], [500, 50], [600, 0]]
                            def score(dice)
                              dice.group_by(&:to_i).inject(0) do |s, (i,j)| 
                                s + j.size.divmod(3).zip(SCORES[i-1]).map {|a,b| a*b }.reduce(:+)
                              end
                            end
                            

                            所有的程序员都应该解决这样的小问题......这就像进行晨练:)

                            【讨论】:

                              【解决方案22】:
                              def score(dice)
                                  result = 0
                                  result += 1000 * (dice.find_all{|e| e == 1}).length.divmod(3)[0]
                                  result += 100 * (dice.find_all{|e| e == 1}).length.divmod(3)[1]
                                  result += 50 * (dice.find_all{|e| e == 5}).length.divmod(3)[1]
                                  (2..6).each {|value| result += value*100 * (dice.find_all{|e| e == value}).length.divmod(3)[0]}
                                  return result
                              end
                              

                              【讨论】:

                                【解决方案23】:

                                这里有一些不错的答案,是时候再来一个?

                                我采用了使用查找来最小化条件语句的方法——所以只有一个 if。 [而且我认为我只使用了 koans 中已经介绍的内容。]

                                def score(dice)
                                
                                count = [0]*7
                                score = [0, 100, 0, 0, 0, 50, 0]
                                bonus = [0, 700, 200, 300, 400, 350, 600]
                                
                                total = 0
                                
                                dice.each do |roll|
                                
                                    total += score[roll]
                                
                                    count[roll] += 1    
                                    total += bonus[roll] if count[roll]==3
                                
                                end 
                                
                                total
                                
                                end
                                

                                (我知道我可以将查找数组设为六个元素,但我认为更好的可读性值得几个字节。)

                                【讨论】:

                                  【解决方案24】:

                                  那么这个解决方案呢? 感谢您的反馈!

                                  def score(dice)
                                    count = Hash.new(0)
                                    dice.each do |die|
                                      count[die] += 1
                                    end
                                    total = 0
                                    count.each_pair { |die, set| total += set < 3 ? single_value(die,set) : triple_value(die,set)}
                                    total
                                  end
                                  
                                  def single_value(die,set)
                                    value = 0
                                    value += (set * 100) if die == 1
                                    value += (set * 50) if die == 5
                                    value
                                  end
                                  
                                  def triple_value(die,set)
                                    value = 0
                                    diff = set - 3
                                    value += single_value(die,diff)
                                    value += die == 1 ? 1000 : die * 100
                                    value
                                  end
                                  

                                  【讨论】:

                                    【解决方案25】:

                                    我在这里使用了一种与其他人略有不同的方法,并且(自然)我认为这是一种更可取的方法。它非常干燥,并且相当广泛地使用 ruby​​ 方法来尽可能避免手动循环和分支。应该是相对明显的,但本质上发生的事情是我们循环遍历每个唯一骰子掷骰,并使用该掷骰出现次数的迭代侵蚀来将适当的点添加到总分中。

                                    def score(dice)
                                      score = 0 # An initial score of 0.
                                    
                                      throw_scores = { 1 => 10, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6 }
                                        # A hash to store the scores for each dice throw
                                    
                                      dice.uniq.each { |throw| # for each unique dice value present in the "hand"
                                    
                                        throw_count = (dice.select { |item| item == throw }).count
                                          # use select to store the number of times this throw occurs
                                    
                                        while throw_count > 0 
                                          # iteratively erode the throw count, accumulating 
                                          # points as appropriate along the way.
                                    
                                          if throw_count >= 3
                                            score += throw_scores[throw] * 100
                                            throw_count -= 3
                                          elsif throw == 1 || throw == 5
                                            score += throw_scores[throw] * 10
                                            throw_count -= 1
                                          else
                                            throw_count -= 1
                                          end
                                        end
                                      }
                                      return score
                                    end
                                    

                                    【讨论】:

                                      【解决方案26】:

                                      还有一个,只是为了好玩:

                                      def score(dice)
                                        result = 0
                                        dice.uniq.each { |k|
                                          result += ((dice.count(k) / 3) * 1000 + (dice.count(k) % 3) * 100) if k == 1
                                          result += ((dice.count(k) / 3) * 100 * k + (dice.count(k) % 3) * ( k == 5 ? 50 : 0 )) if k != 1
                                        }
                                        result
                                      end
                                      

                                      【讨论】:

                                        【解决方案27】:

                                        这是我的看法。这里的所有其他解决方案都试图变得聪明。有一个学习聪明技巧的地方,但更重要的是学会编写清晰和可维护的代码。我看到所有这些解决方案的主要问题是很难从代码中辨别评分规则。您能否阅读您的解决方案并确保它在您的脑海中是正确的?然后想象有人要求你添加一个新的评分规则,或者删除一个。能否快速指出必须添加或删除规则的地方?

                                        这是我的解决方案。我确信它可以改进,但看看“分数”功能的形状。这是我不介意维护的那种代码。

                                        class Array
                                          def occurrences_of(match)
                                            self.select{ |number| match == number }.size
                                          end
                                        
                                          def delete_one(match)
                                            for i in (0..size)
                                              if match == self[i]
                                                self.delete_at(i)
                                                return
                                              end
                                            end
                                          end
                                        end
                                        
                                        def single_die_rule(match, score, dice)
                                          dice.occurrences_of(match) * score
                                        end
                                        
                                        def triple_rule(match, score, dice)
                                          return 0 if dice.occurrences_of(match) < 3
                                          3.times { dice.delete_one match }
                                          score
                                        end
                                        
                                        def score(dice)
                                          triple_rule(1, 1000, dice) +
                                          triple_rule(2, 200, dice) +
                                          triple_rule(3, 300, dice) +
                                          triple_rule(4, 400, dice) +
                                          triple_rule(5, 500, dice) +
                                          triple_rule(6, 600, dice) +
                                          single_die_rule(1, 100, dice) +
                                          single_die_rule(5, 50, dice)
                                        end
                                        

                                        【讨论】:

                                          【解决方案28】:

                                          我将不得不去:

                                          def score(dice)
                                              # some checks
                                              raise ArgumentError, "input not array" unless dice.is_a?(Array)
                                              raise ArgumentError, "invalid array size" unless dice.size <= 5
                                              raise ArgumentError, "invalid dice result" if dice.any? { |x| x<1 || x>6 }
                                          
                                              # setup (output var, throws as hash)
                                              out = 0
                                              freqs = dice.inject(Hash.new(0)) { |m,x| m[x] += 1; m }
                                          
                                              # 3-sets
                                              1.upto(6) { |i| out += freqs[i]/3 * (i == 1 ? 10 : i) * 100 }
                                          
                                              # one not part of 3-set
                                              out += (freqs[1] % 3) * 100
                                          
                                              # five not part of 3-set
                                              out += (freqs[5] % 3) * 50
                                          
                                              out
                                          end
                                          

                                          因为到目前为止提出的大多数解决方案都缺乏基本检查。其中一些是相当不可读的(在我的书中),而且不是很地道。

                                          当然,通过分成两个子句可以使 3-set 条件更具可读性:

                                              # 3-sets of ones
                                              out += freqs[1]/3 * 1_000
                                              # 3-sets of others
                                              2.upto(6) { |i| out += freqs[i]/3 * i * 100 }
                                          

                                          但这主要是关于个人喜好的 IMO。

                                          【讨论】:

                                            【解决方案29】:

                                            来自 Perl,我的直觉是使用哈希:

                                            def score(dice)
                                              # You need to write this method
                                              score = 0
                                              count = Hash.new(0)
                                            
                                              for die in dice
                                                count[die] += 1
                                            
                                                is_triple = (count[die] % 3 == 0)
                                                if die == 1 then
                                                  score += is_triple ? 800 : 100
                                                elsif die == 5 then
                                                  score += is_triple ? 400 : 50
                                                elsif is_triple
                                                  score += 100 * die
                                                end
                                              end
                                            
                                              return score
                                            end
                                            

                                            这样做的好处是它只通过dice。我本可以使用 Array 代替 Hash。

                                            【讨论】:

                                              【解决方案30】:

                                              我按面将骰子分组,然后循环遍历这些组,首先得分三分,然后是单个骰子。如果我玩 IRL,这就是我在比赛中得分的方式

                                              def score(dice)
                                                  points = 0
                                                  dice.group_by {|face| face}.each do |face,group|
                                                      while group.size >= 3
                                                          if face == 1
                                                              # A set of three ones is 1000 points
                                                              points += 1000
                                                          else
                                                              # A set of three numbers (other than ones) is worth 100 times the number.
                                                              points += 100 * face
                                                          end
                                                          group.pop(3)
                                                      end
                                                      group.each do |x|
                                                           # A one (that is not part of a set of three) is worth 100 points.
                                                          points += 100 if x==1
                                                          # A five (that is not part of a set of three) is worth 50 points.
                                                          points += 50 if x==5 
                                                      end
                                                  end
                                                  return points
                                              end
                                              

                                              我就是这样滚动

                                              【讨论】:

                                                猜你喜欢
                                                • 1970-01-01
                                                • 1970-01-01
                                                • 2012-12-26
                                                • 2018-08-04
                                                • 2019-06-19
                                                • 2022-10-01
                                                • 1970-01-01
                                                • 2020-02-27
                                                • 1970-01-01
                                                相关资源
                                                最近更新 更多