Ruby中的嵌入式循环
我想写一个程序来模拟骰子游戏。这个想法是掷五个骰子,得到尽可能低的分数——三的值为0。掷完五个骰子后,玩家/机器人必须从五个骰子中选择至少一个(或多个)骰子,然后掷出其余的骰子。这就是给我带来问题的原因。如果没有三,那么我推动机器人的骰子的“守护者”数组最终是空的,这就需要一个嵌入式循环。由于我对编码相当陌生,我真的无法找到一种方法来创建一个嵌入式循环,以确保至少有一个骰子被指定为保管者。为了你的理智起见,我要说,我现在介绍的这个程序的“beta”版本旨在做以下工作:创建一个机器人,尝试在一轮骨骼上获得最低分数。骰子掷一次。然后他试着选择尽可能低的分数。如果没有三个(等于0),他选择一个。我试图解决的问题是创建一个嵌入式循环,确保为keeper阵列选择至少一个骰子。代码主要是为了演示我的解决方案有多丑陋,并给出一个更好的解决方案Ruby中的嵌入式循环,ruby,Ruby,我想写一个程序来模拟骰子游戏。这个想法是掷五个骰子,得到尽可能低的分数——三的值为0。掷完五个骰子后,玩家/机器人必须从五个骰子中选择至少一个(或多个)骰子,然后掷出其余的骰子。这就是给我带来问题的原因。如果没有三,那么我推动机器人的骰子的“守护者”数组最终是空的,这就需要一个嵌入式循环。由于我对编码相当陌生,我真的无法找到一种方法来创建一个嵌入式循环,以确保至少有一个骰子被指定为保管者。为了你的理智起见,我要说,我现在介绍的这个程序的“beta”版本旨在做以下工作:创建一个机器人,尝试在一轮骨
#rolls dice
srand
dice = []
5.times do
dice.push(rand(6)+1)
end
puts dice
puts " "
#initialize keeper and roll again arrays
i = 0
keeper = []
roll_again = []
#select any 3s from the dice roll and put them in keeper
dice.each do |d|
if d == 3
keeper.push(d)
else
i +=1 #dummy operation to keep if statement functioning, tragically ugly code
end
end
#in the case that no threes were rolled, ones are selected
if keeper.length == 0
dice.each do |f|
if f == 1
keeper.push(f)
else
i+= 1
end
end
else
i += 1
end
puts "Keeper:"
puts keeper
puts "Roll Again:"
puts roll_again
对于初学者来说,你做得很好:-)我将向你展示一些可以帮助你做这个练习的东西,通过尝试不同的东西并试图理解它们,你会学到最好的东西
>> dice = [5,1,2,2,6,4] #=> [5, 1, 2, 2, 6, 4]
>> if (threes = dice.select { |d| d == 3 }).empty?
.. ones = dice.select { |d| d == 1 }
.. end #=> [1]
>> threes #=> []
>> ones #=> [1]
您可以做的另一件事是将骰子阵列分组:
>> dice.group_by { |d| d } #=> {5=>[5], 1=>[1], 2=>[2, 2], 6=>[6], 4=>[4]}
这样,您可以立即看到给定数字的数组是否为空。注意,在Ruby中很容易实现数组差异,这可能有助于移除骰子:
>> [3,1,3,5,1,7] - [3] #=> [1, 5, 1, 7]
事实上,数组相交也是查看某个元素是否是数组的一部分的一个好方法:
>> ([3,1,3,5,1,7] & [3]).empty? #=> false
>> ([4,1,2,5,1,7] & [3]).empty? #=> true
还有一些提示:您的
else
分支不需要伪语句,只需将它们省略即可。我还强烈建议浏览Array
和Enumerable
的文档,其中有很多有用的方法。当然有很多方法可以做到这一点。但是看一看:我做了一些一般性的修改,使它更。。。鲁比
# A custom helper method
class Array
def take_while_num # Modeled off take_while, but also pass in the length so far
arr = []
each do |e|
# Call the block with this element and the current length,
# and stop if it returns false
if yield(e, arr.length)
arr << e
else
break
end
end
arr
end
end
dice = Array.new(5) { rand(6)+1 } # 5 random numbers
puts "Original dice: #{dice.inspect}"
# Sort the dice by value (3s are worth 0), then take all 3s
# or if there are no 3s, take whatever is at the front
keep = dice.sort_by {|d| d == 3 ? 0 : d }.take_while_num {|d, n| n.zero? or d == 3 }
# Remove the ones we're keeping from the list of dice
dice -= keep
puts "Dice: #{dice.inspect}"
puts "Keep: #{keep.inspect}"
顺便说一句,迈克尔·科尔创造了methodfinder gem。因此:
$ sudo gem install methodfinder
现在我们可以找到我们需要的方法:
[2,3,2,3,4,3,2].find_method { |x| x.unknown(3) == [3,3,3] }
=> grep
所以我会这样写你的算法:
def keep dice
threes = dice.grep(3)
threes.empty? ? [dice.min] : threes
end
如果没有三个或一个呢?在这一点上,这并不重要。我会继续说:如果数组仍然为空,那么选择2,然后选择4等等。但是如果没有嵌入循环,我认为这段代码看起来会非常难看。除非无法使用嵌入式循环。基本上,为了回答您的问题,目前编写的程序并不是为了完整地模拟一轮。只要程序可以在数组中有三个或一个的时候进行测试,就足以满足我的目的——这仅仅是为了学习如何编写代码。那么
i
的用途是什么?你增加了它,但似乎没有使用它。这绝对是这段代码中最荒谬的部分。我所能想到的就是让if语句工作,在else语句中包含一些东西作为虚拟操作。所以我增加了一个我知道不会使用的变量。当然,这是一个糟糕的编码。Rubyists通常用2个空格缩进,而不是4个空格。我只是用“掷骰子”的方法写了一个回复,并使用了一点。选择以获得3。。。但是我认为Michael关于在控制台中使用Array和Enumerable API中的方法的建议是一个很好的建议。谢谢你的回答和鼓励。表情符号可以让人安心。我还不能完全理解你的答案,但我会在周一解决。在ruby-doc.com的帮助下,我相信它将阐明很多关于ruby和编码的一般知识,并帮助我走上正轨。@Bodidarma,你需要安装ruby Gems。以下是我的说明,如何使用Ruby Gems和Rails安装RVM:
def keep dice
threes = dice.grep(3)
threes.empty? ? [dice.min] : threes
end