【问题标题】:Ruby Koan 182 - Greed DiceRuby Koan 182 - 贪婪骰子
【发布时间】:2015-06-28 20:09:07
【问题描述】:

我很快就得出结论,我不能成为一名程序员。尽管在 Ruby Koans 中做了大量的笔记并练习了所有内容,除了三遍在 Codecademy 上的 Ruby 课程,并且目前正在阅读 Chris Pine 的书,平均每天学习 6 小时......这个当前的 Koan 是一个练习沮丧和意识到不是每个人都可以成为程序员。

练习如下

# Greed is a dice game where you roll up to five dice to accumulate
# points.  The following "score" function will be used to 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.

def score(dice)
end

所以乍一看,我假设测试将通过dice 提供随机 num 功能?还是我需要自己写?现在我必须限制掷骰子的范围?然后我所要做的就是获取数字并将它们放入一个数组中,但最多只能有 5 个位置(比如while array has 5 or less entries?,然后我需要定义点系统的工作方式。所以像score[0] = 100, score[2]= 200 这样的东西?但现在我'已经硬编码了分数,如果第一个位置不是 1 而是 5 怎么办?那么数字就是 50。那么 if/else 语句怎么样?类似于

if score[0] == 1
  point = 100
elsif score[0] == 5
  point = 50
else point = 0

然后我对位置 [1]-[4] 重复此操作?

尽管非常想要,但我不想简单地用谷歌搜索答案,我宁愿得到某种方向,因为没有更好的词。

希望这不是一个太笼统的问题,但您如何处理这样的问题?在解决这个问题之前,也许我应该先从头到尾看一遍 Pine 的书?

【问题讨论】:

  • 你想太多了。例如,您可能不需要检查输入对 koan 是否有效 - 尽管在实际业务情况下,您考虑检查值的方式(通常称为验证)将非常有用。我认为这个 koan 的演练设置在 Stack Overflow 上没有用。这对您的培训需求来说太个人化了。非常简短的提示:if-then 检查不是一个糟糕的起点,但不要考虑处理数组中的每个项目 - 将数组的内容作为一个组查看 - 检查 Array 的文档以获得好的方法
  • 不要放弃!我记得在本科时学习过真正的分析。我只是无法得到它。我以为我必须放弃成为数学家的梦想。然后有一天——实际上是一天——乌云散去,一切都变得清晰,甚至是显而易见的。我继续学习更高级的分析课程,发现它们很容易(但很有趣)。另一方面,大多数人不适合成为编码员。 (后记:我终于清醒过来,意识到我只是不够聪明,不能成为普通的数学家,这让我不感兴趣。)
  • 这是测试驱动开发可以帮助您的地方。我不会担心选择框架。一种基本方法是从公案中获取一个要求,并使其在脚本中工作,否则失败。也许从你有三个失败的情况开始('1,1,1,2,2 应该是 1,000),除非 score([1,1,1,2,2]) == 1,000。然后添加另一个要求并在三个数字不是数字时使分数起作用。继续添加要求,直到完成!可以在“Jim Weirich - Roman Numerals Kata”中找到有关这种技术的精彩视频 - youtu.be/983zk0eqYLY

标签: ruby tdd


【解决方案1】:

你可以写你的方法:

def score(d1,d2,d3,d4,d5)
  ...
end

您需要做的第一件事是确定五个值中的三个是否相同。如果三个相同,您需要知道它们是否都是1 或其他值,并且您需要知道其他两个值是什么。如果最多两个值相同,您也需要知道这一点。这确实是问题的症结所在。所以让我们写一个方法:

def partition(d1,d2,d3,d4,d5)
  ...
end

score 调用如下:

three_value, other_values = partition(d1,d2,d3,d4,d5)

地点:

  • three_value 等于三个相等值组的公共值 (1-6) 或(比方说)nil 如果不存在三个相等值组;和
  • other_values 是来自 [d1,d2,d3,d4,d5] 的两个值的数组,排除了三个相等的值(如果有一组三个相等的值)或 [d1,d2,d3,d4,d5](如果没有一组三个相等的值)。

例如,

three_value, other_values = partition(1,3,4,3,6)
  #=> [nil, [1, 3, 4, 3, 6]] 
three_value, other_values = partition(1,3,4,3,3)
  #=> [3, [1, 4]] 
three_value, other_values = partition(1,3,3,3,3)
  #=> [3, [1, 3]] 
three_value, other_values = partition(3,3,3,3,3)
  #=> [3, [3, 3]] 

一旦我们有了partition 方法,那么score 方法就很简单了:

def score(d1,d2,d3,d4,d5)
  three_value, other_values = partition(d1,d2,d3,d4,d5)

  total = case three_value
          when 1   then 1000
          when nil then    0
          else          three_value * 1000
          end

  other_values.each do |i|
    total += case i
             when ...
               ...
             when ...
               ...
             end
  end
end

在我们进入方法partition之前,我们可以将score简化如下:

def score(*d)
  three_value, other_values = partition(*d)

  total = case three_value
          when 1   then 1000
          when nil then    0
          else          three_value * 1000
          end

  other_values.each do |i|
    total += case i
             when ...
               ...
             when ...
               ...
             end
  end
end

使用“splat”运算符* 很方便,因为我们不关心骰子滚动的顺序。在调用scorepartition方法时,如果d = [1,3,4,3,3]score(*d)等同于:

score(1,3,4,3,3)    

(看看为什么* 被称为“splat”?)

在上面的方法score中,d(不是*d)是一个包含五个值的数组。

现在让我们看一下方法partition。我们需要计算每个结果 (1-6) 发生的次数。这对哈希来说是件好事:

def partition(*d)
  counts = {}
  d.each do |i|
    if counts.key?(i)
      counts[i] += 1
    else
      counts[i] = 1
    end
  end
  ...
end

假设d = [1,3,4,3,3]。那么

counts #=> {1=>1, 3=>3, 4=>1}

我们现在需要找到具有最大值的键。为此我们可以使用Enumerable#max_by:

k, v = counts.max_by { |k,v| v }
  #=> [3, 3]
k #=> 3
v #=> 3

然后我们可以像这样计算other_values

other_values = case v
               when 3
                 d - [k]
               when 4
                 (d - [k]) << k
               when 5
                 (d - [k]) << k << k
               else
                 d
               end

注意Array#-是数组差分法。

最后,

 three_value = (v >= 3) ? k : nil

partition 将返回:

 [three_value, other_values]

你能把所有这些放在一起吗?

[在你有工作代码之前,你可能不想阅读以下内容。]

一旦您获得了 Ruby 的使用经验,您将能够编写 partition,如下所示:

def partition(*d)
  k,v = d.each_with_object(Hash.new(0)) { |i,h| h[i]+=1 }.max_by(&:last)
  (v < 3)) ? [nil, d] : [k, d - [k] + [k]*(v-3)]
end                      

旁白:我想看一个核心方法Array#difference,我定义并详细说明了here。这将允许表达partition 正文的最后一行:

(v < 3)) ? [nil, d] : [k, d.difference([k,k,k])]

【讨论】:

  • 哦,哇,我已经放弃了试图弄清楚但你的帖子让我想再次解决它。我记下了所有内容,目前正在尝试分解逻辑。这是一个巨大的帮助!谢谢卡里!
猜你喜欢
  • 2011-12-19
  • 2013-06-05
  • 1970-01-01
  • 2020-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 2014-08-21
相关资源
最近更新 更多