Chris Pine Ruby ch 10,递归

时间:2013-05-31 02:00:37

标签: ruby recursion

我一直在尝试使用Chris Pine的“学习编程”一书来学习红宝石。实际上,在阅读第10章和使用的例子之前,我真的很兴奋。现在这一章和它的例子完全扼杀了我继续阅读这本书的所有兴奋。在这个例子中,我完全不知道它是如何计算瓦片的,或者为什么当使用continent_size world,x,y的属性定义方法时,他使用world [y],[x]?我不知道这个例子中的递归是如何工作的。有人可以对这个例子说明作者实际上在做什么吗?

M = 'land'
o = 'water'

world = [
  [o,o,o,o,o,M,o,o,o,o,o],
  [o,o,o,o,M,M,o,o,o,o,o],
  [o,o,o,o,o,M,o,o,M,M,o],
  [o,o,o,M,o,M,o,o,o,M,o],
  [o,o,o,o,o,M,M,o,o,o,o],
  [o,o,o,o,M,M,M,M,o,o,o],
  [M,M,M,M,M,M,M,M,M,M,M],
  [o,o,o,M,M,o,M,M,M,o,o],
  [o,o,o,o,o,o,M,M,o,o,o],
  [o,M,o,o,o,M,M,o,o,o,o],
  [o,o,o,o,o,M,o,o,o,o,o]]

def continent_size world, x ,y

  if x < 0 or x > 10 or y < 0 or y > 10
    return 0
  end

  if world[y][x] != 'land'
    return 0
  end

  size = 1
  world [y][x] = 'counted land'

  size = size + continent_size(world, x-1, y-1)
  size = size + continent_size(world, x , y-1)
  size = size + continent_size(world, x+1, y-1)
  size = size + continent_size(world, x-1, y )
  size = size + continent_size(world, x+1, y )
  size = size + continent_size(world, x-1, y+1)
  size = size + continent_size(world, x , y+1)
  size = size + continent_size(world, x+1, y+1)
  size

end

puts continent_size(world, 5, 5)

7 个答案:

答案 0 :(得分:2)

这称为洪水填充。它正在做的是计算连接到初始起点的所有“土地”的大小。请注意,它不会计算所有“土地”符号,只会计算由于水而无法到达的符号。

洪水填充是一种称为深度优先搜索的形式,它是一种遍历图形的方式(此处为离散的“地图”)。可以总结如下:

  1. 访问当前位置/图表节点,对其进行计数并将其标记为已访问
  2. 检查所有已连接的节点(此处,上下,左侧或右侧),如果未访问它们并且它们已着陆,则以递归方式访问它们
  3. 他可能正在执行y,x,原因如下:2D数组的逻辑格式首先按行排列,然后按列排列。该行可以被认为是y轴,而列可以被认为是x。

答案 1 :(得分:1)

当我在书中解决这个问题时,我还注意到了x&amp;的转换。当世界被召唤时我查看了Pragmatic Programmer的网站,看看它是否列在勘误表中,但事实并非如此。

我认为这是拼写错误并将它们翻到x,y。代码以任何一种方式工作。

这并不重要,因为5,5的起点是任意的,代码将检查围绕x,y(或y,x)的所有八个瓦片,无论它是否到达阵列的“边缘”/世界。

答案 2 :(得分:0)

从其他答案中退了几步,这里的递归是continent_sizecontinent_size内被调用八次。

因此该方法本身被调用了八次。

但是......这八种内部方法中的每一种都会再次召唤continent_size八次。

依此类推,等等。

让你头脑发热是疯狂的,但是当你这样做时,感觉你可以看到黑客帝国。虽然非常简短。

我偶然发现了这个问题,寻找一些关于任务扩展位的帮助(如果你的一个'探险家'脱离了世界的边缘,如何避免错误。)

我最终解决了这个问题:

# If it's off the edge of the world, it's as good as water
square = world[y][x] rescue 'o'

if square != 'Land'
  return 0
end

我不知道这是不是最好的方法,但对我来说这似乎很优雅。

答案 3 :(得分:0)

我觉得我解决它的方式很脏,我在这里寻找更好的答案。我创建了一个新变量,E =&#39; edge&#39;,并将触及地图边缘的任何字符更改为E.然后我将此代码添加到continent_size方法的顶部:

if world[y][x] == 'edge'
        return 1
    end

有效。 :/

答案 4 :(得分:0)

当世界的最高边缘都是'o'时,看起来救援方法仍然崩溃。解决此问题的一种简单方法是编写一个条件,检查坐标(x,y)是否在边界之外(即在0或world.length-1之外),如果满足该条件则返回0。

答案 5 :(得分:0)

我也注意到Pine代码中x和y的换位    我认为推理可能是因为他安排了这个世界&#34;数组,以便每行有一个子数组。方括号中的第一个数字跟随&#34; world&#34; (world [0])指的是世界中元素(子数组)的索引。由于它们是垂直堆叠的,因此它是您的y轴。第二个括号内的数字(world [0] [5])指的是子数组中的元素。它们水平运行,因此第二个数字指的是您的x轴。编写方法以获取参数x然后参数y允许您以常规(x,y)格式输入凝视位置,而在方法中,变量被转置以完成任务。我认为。我虽然对此完全陌生。

此外,如果任何人对此练习的扩展版本有一个干净的解决方案,其中大陆&#34;接壤世界的边缘&#34;我很乐意看到它

答案 6 :(得分:0)

我花了一些时间来了解这个例子。我试图解决这样的任务,首先:

<div>
  <p>Let us not talk falsely now</p>
</div>

但是我不断收到“未定义方法”&gt;“for a array”

的错误

然后我意识到解决方案可以在条件“x”和“y”中,如果它们不仅仅是数组(10)或低于(0):

  if ( world[y] > world[y].length  || world[x] > world[x].length ) || ( world[y] < world[y].length || world[x] < world[x].length )
    return 0 
  end

这里的问题是它适用于这个特定大小的数组...如果世界大于10 - 程序会将它遇到的每个“土地”计为0。

所以我猜这只是半解决方案......