ошибка при поиске в 2d массиве ruby - PullRequest
0 голосов
/ 06 мая 2019

У меня есть следующие сетки (подключите четыре)

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, сетка, в которой единицы расположены в нижнем ряду, я получаю эту ошибку

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 ]

1 голос
/ 06 мая 2019

Вы можете решить множество проблем здесь, упростив этот код, используя 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..2 или 0..4 или что угодно.

0 голосов
/ 06 мая 2019

Я мог бы предложить немного другой подход, это не полное решение, просто начало. Это также должно помочь поймать четверых.

Сначала отобразим не 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], есть пробел
0 голосов
/ 06 мая 2019

Давайте посмотрим на ваш код, слегка упрощенный 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, и если так, определите, имеют ли два элемента ниже него одинаковое ненулевое значение. Если вы достигнете предпоследней (следующей за последней) строки, yi = array.size - 2, вы сравните x с array[yi+2][xi], что равно array[array.size][xi], что, в свою очередь, равно nil[xi]. Однако nil не имеет метода [], поэтому возникает исключение undefined method . Обратите особое внимание на эти сообщения об ошибках; часто, как здесь, они приводят вас к ошибке.

Другая проблема заключается в том, что если вы найдете 1 в первых трех строках столбца j, вы вернете индекс [-1, j], -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)

и добавьте дополнительные методы top_left_to_bottom_right? и bottom_left_to_top_right?.

1. Я изменил имя вашего метода на search_array, потому что в Ruby существует соглашение, согласно которому case-snake используется для именования переменных и методов. Вам не нужно принимать это соглашение, но 99% + Rubiests делают.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...