Что касается меня, то основная проблема с кодом заключается в его ненужной («случайной») сложности.
Да, решаемая вами задача может быть сведена к задаче обхода графа, но это не значит, что вы должны представлять граф явно . Для этой конкретной задачи - где все возможные перемещения из произвольной ячейки четко определены, а сама доска ограничена - вы можете легко вычислить края графа на лету (и без всего этого дополнительного механизма, который делает ваш код настолько трудным для рассуждения о - даже для вас). Явное представление платы также выглядит избыточным (опять же, для этой конкретной задачи).
Принимая все это во внимание, решение может быть таким простым:
class Knight
def initialize
@knight_moves = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]]
end
def move(start, stop)
visited = {}
queue = [[stop, nil]]
while queue.any?
current_cell, next_cell = queue.shift
next if visited.has_key?(current_cell)
visited[current_cell] = next_cell
return build_path(start, stop, visited) if current_cell == start
possible_moves(current_cell).each do |next_move|
queue << [next_move, current_cell] unless visited.has_key?(next_move)
end
end
end
private
def possible_moves(cell)
@knight_moves.
map { |x, y| [cell.first + x, cell.last + y] }.
select(&method(:valid_move?))
end
def build_path(start, stop, visited)
path = [start]
while next_cell = visited[path.last]
path << next_cell
end
path.last == stop ? path : nil
end
def valid_move?(cell)
cell.all? { |n| n >= 0 && n <= 7 }
end
end
knight = Knight.new
knight.move [0,0], [0,1] #=> [[0, 0], [2, 1], [1, 3], [0, 1]]