在二维数组红宝石中搜索时出错

时间:2019-05-05 23:05:53

标签: ruby

我有以下网格(连接四个网格)

grid1 = [
  [nil, nil, nil],
  [1, nil, nil],
  [1, nil, nil],
  [1, nil, nil]
]
grid2 = [
  [nil, nil, nil],
  [nil, nil, 1],
  [nil, nil, 1],
  [nil, nil, 1]
]

grid3 = [
  [nil, nil, nil],
  [nil, nil, nil],
  [nil, nil, nil],
  [1, 1, 1]
]

这是我创建的方法,用于在垂直行中找到三个1,然后返回上方的下一个可用插槽

def searchArray(array)
  array.each_with_index do |y, yi|
    y.each_with_index do |x, xi|
      if array[yi][xi] != nil && array[yi][xi] == array[yi+1][xi] && array[yi][xi] == array[yi+2][xi]
        return v = [yi-1, xi]
      end
    end
  end
end


searchArray(grid2)

当我在grid1和grid 2上调用该方法时,效果很好,但是当我在Grid 3上将其1放在最下面的网格上调用它时,会出现此错误

undefined method `[]' for nil:NilClass
(repl):28:in `block (2 levels) in searchArray'
(repl):27:in `each'
(repl):27:in `each_with_index'
(repl):27:in `block in searchArray'
(repl):26:in `each'
(repl):26:in `each_with_index'
(repl):26:in `searchArray'
(repl):36:in `<main>'

不确定发生了什么 谢谢

3 个答案:

答案 0 :(得分:1)

您可以通过使用dig简化此代码来解决很多问题:

def search_array(array)
  array.each_with_index do |y, yi|
    y.each_with_index do |x, xi|
      stack = (0..2).map { |o| array.dig(yi + o, xi) }

      if (stack == [ 1, 1, 1 ])
        return [ yi - 1, xi ]
      end
    end
  end
end

dig可以在其中徘徊并且不会错过数组结尾的情况而不会引起异常。这里的map用于快速取出 N 个高堆栈。您可以执行1..20..4或其他任何必要的操作。

答案 1 :(得分:0)

让我们看一下您的代码,稍微简化一下 1

def search_array(array)
  array.each_with_index do |y, yi|
    y.each_with_index do |x, xi|
      return [yi-1, xi] if x != nil && x == array[yi+1][xi] && x == array[yi+2][xi]
    end
  end
end

您一次转到一行,然后针对该行中的每个元素检查该元素是否不是nil,如果是,请确定其下面的两个元素是否具有相同的non-nil值。如果到达倒数第二行(倒数第二行)yi = array.size - 2,您将比较xarray[yi+2][xi],等于array[array.size][xi],后者等于{{1 }}。但是,nil[xi]没有方法nil,因此会引发未定义的方法异常。密切注意那些错误消息;通常,就像这里一样,它们会引导您发现错误。

另一个问题是,如果您发现[]位于列1的前三行中,则会返回索引j,其中[-1, j]为{{1 }}。你也不想要。

我了解您还希望确定将硬币丢入一列中是否会导致水平四合一。您可以按以下方式进行垂直和水平检查。

-1

0-1

def search_array(arr)
  arr.first.each_index do |j|
    r = arr.each_index.find { |i| arr[i][j] == 1 }
    next if r == 0
    r = r.nil? ? arr.size-1 : r-1
    return [r,j] if below?(arr,r,j) || left?(arr,r,j) || right?(arr,r,j)
  end
  nil
end

def below?(arr,r,j)
  r < arr.size-3 && (1..3).all? { |i| arr[r+i][j] == 1 }
end

def right?(arr,r,j)
  j < arr.first.size-3 && (1..3).all? { |i| arr[r][j+i] == 1 }
end

def left?(arr,r,j)
  j >= 3 && (1..3).all? { |i| arr[r][j-i] == 1 }
end

请注意,如果您还希望检查四行对角线,则可以更改:

grid4 = [
  [nil, nil, nil, nil, nil],
  [nil, nil, nil, nil, nil],
  [nil, nil,   1, nil, nil],
  [nil, nil,   1,   1,   1],
  [  1,   1,   1, nil,   1]
]

grid5 = [
  [nil, nil, nil, nil, nil],
  [nil, nil, nil, nil, nil],
  [nil, nil,   1, nil, nil],
  [nil,   1,   1, nil, nil],
  [nil,   1,   1, nil,   1]
]

search_array grid1 #=> [0, 0] (vertical)
search_array grid2 #=> [0, 2] (vertical)
search_array grid3 #=> nil
search_array grid4 #=> [3, 1] (horizontal)
search_array grid5 #=> [1, 2] (vertical)

并添加其他方法return [r,j] if below?(arr,r,j) || left?(arr,r,j) || right?(arr,r,j) return [r,j] if below?(arr,r,j) || left?(arr,r,j) || right?(arr,r,j) || top_left_to_bottom_right?(arr,r,j) || bottom_left_to_top_right?(arr,r,j)

1。我将您的方法名称更改为top_left_to_bottom_right?,因为Ruby约定使用snake case来命名变量和方法。您不必采用该约定,但99%以上的Rubiesst可以采用。

答案 2 :(得分:0)

我可以建议一种稍微不同的方法,这不是一个完整的解决方案,只是一个开始。它也应该有助于抓住这四个方面。

首先映射网格的非nil索引,让我们考虑grid3

mapping = grid3.flat_map.with_index{ |y, yi| y.map.with_index { |x, xi| [xi, yi] if x }.compact }
#=> [[0, 3], [1, 3], [2, 3]]

然后按第一个和第二个元素分组以获取列和行:

cols = mapping.group_by(&:first) #=> {0=>[[0, 3]], 1=>[[1, 3]], 2=>[[2, 3]]}
rows = mapping.group_by(&:last) #=> {3=>[[0, 3], [1, 3], [2, 3]]}

现在,如果要在一行或一列中查找三个元素:

cols.keep_if { |_,v| v.size == 3 } #=> {}
rows.keep_if { |_,v| v.size == 3 } #=> {3=>[[0, 3], [1, 3], [2, 3]]}

第一行说没有三个元素对齐的列。 第二行说,索引为3的行具有三个对齐的元素,索引为[[0, 3], [1, 3], [2, 3]]


下一步,检查元素之间是否没有间隙。例如,在4x4网格中,您还可以获得[[0, 3], [1, 3], [3, 3]]这是三个元素,但是[2, 3]中有一个空白,