0

我有一个关于在矩阵中识别给定单元格或一组单元格旁边的所有点的问题(请参阅Need a Ruby way to determine the elements of a matrix "touching" another element)。由于没有提出合适的想法,我决定通过蛮力进行。

下面的代码成功地完成了我想要做的事情。数组 tmpl(模板)包含如何从给定坐标(由亚特兰蒂斯提供)到它周围的 8 个单元格的地图。然后,我通过将亚特兰蒂斯的每个元素与 tmpl 的所有元素相加,构造一个数组 sl(海岸线),其中包含所有接触亚特兰蒂斯海岸线的“水下”陆地。

# create method to determine elements contiguous to atlantis
require 'matrix'            
atlantis = [[2,3],[3,4]]
tmpl = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]

ln = 0
sl = []
while ln < atlantis.length
  n = 0
  tsl = []
  while n < 8
    tsl[n] = [atlantis[ln], tmpl[n]].transpose.map { |x| x.reduce(:+) }
    n = n+ 1
  end
  sl = sl + tsl
  ln = ln + 1
end
sl = sl - atlantis
sl.uniq!
sl.to_a.each { |r| puts r.inspect }

但是我有一个问题(剩下的许多之一),我仍然需要比这里显示的多 2 级循环(一个继续向亚特兰蒂斯添加土地,直到它达到设定的大小,另一个用于建造额外的岛屿、百慕大、卡塔利娜等.) 而且这已经变得难以阅读和理解。我对面向对象编程的模糊理解表明,通过将其中一些循环转换为方法来改善这种冷漠。然而,我在 35 年前学习了基础编程,并且正在努力学习 Ruby。所以我的要求是:

  1. 实际上将这些变成方法更好吗?

  2. 如果是这样,是否有人愿意通过将某些内容更改为方法来向我展示这是如何完成的?

  3. 当您添加其他级别并发现您需要以较低的方法更改某些内容时,您会怎么做?(例如,在弄清楚如何sl仅使用 中的一个值进行创建的简单案例之后atlantis,我不得不返回并对其进行重新设计以获得更长的值。)

我希望通过以这种方式提出问题,它对其他小伙伴也有用。

顺便说一句,.transpose.map { |x| x.reduce(:+) }我在 Stack Overflow 上找到了这一点(经过数小时的尝试,因为它应该很简单,如果我做不到,我一定会遗漏一些明显的东西。是的,我打赌你也知道。)让你添加两个数组元素一个元素,我不知道它是如何工作的。)

4

1 回答 1

0

这已经变得难以阅读和遵循

一种降低阅读和遵循难度的方法是尝试使代码“自我记录”,通过使用可读的变量名和 Ruby 习惯用法来减少混乱。

您的代码的快速重构给出了这个:

require 'matrix'            
atlantis = [[2,3],[3,4]]
template = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]

shoreline = []
atlantis.each do |atlantum|
  shoreline += template.inject([]) do |memo, element|
    memo << [atlantum, element].transpose.map { |x| x.reduce(:+) }
    memo
  end
end

shoreline = shoreline - atlantis
shoreline.uniq!
shoreline.each { |r| puts r.inspect }

主处理块的大小只有一半,并且(希望)更具可读性,如果您仍然需要/想要的话,您可以从这里使用extract 方法重构来进一步整理它。

于 2012-07-30T07:27:00.400 回答