Ruby 公案 182 - 贪婪骰子
Ruby Koan 182 - Greed Dice
我很快得出结论,我不能成为一名程序员。尽管在 Ruby Koans 中记下了足够的笔记并练习了所有内容,但在完成 Codecademy 上的 Ruby 课程三遍以及目前平均每天学习 6 小时的 Chris Pine 的书的过程中…… .当前的 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
提供随机数功能?还是需要我自己写?现在我必须限制掷骰子的范围?然后我所要做的就是获取数字并将它们放入一个数组中,但最多只能有 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] 重复这个?
尽管非常想要,但我不想简单地 google 答案,我宁愿得到一些指导,因为找不到更好的词。
希望这不是一个太笼统的问题,但你是如何处理这样的问题的?在解决这个问题之前,也许我应该先从头到尾通读一下 Pine 的书?
你可以写你的方法:
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" 运算符 *
很方便,因为我们不关心掷骰子的顺序。在调用方法score
或partition
时,如果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
将return:
[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])]
我很快得出结论,我不能成为一名程序员。尽管在 Ruby Koans 中记下了足够的笔记并练习了所有内容,但在完成 Codecademy 上的 Ruby 课程三遍以及目前平均每天学习 6 小时的 Chris Pine 的书的过程中…… .当前的 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
提供随机数功能?还是需要我自己写?现在我必须限制掷骰子的范围?然后我所要做的就是获取数字并将它们放入一个数组中,但最多只能有 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] 重复这个?
尽管非常想要,但我不想简单地 google 答案,我宁愿得到一些指导,因为找不到更好的词。
希望这不是一个太笼统的问题,但你是如何处理这样的问题的?在解决这个问题之前,也许我应该先从头到尾通读一下 Pine 的书?
你可以写你的方法:
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" 运算符 *
很方便,因为我们不关心掷骰子的顺序。在调用方法score
或partition
时,如果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
将return:
[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])]