mja

2018-08-19 12:50

雑だけど解けたから転職するか〜。

require 'set'

MAP = <<-EOL
**************************
*S* *                    *
* * *  *  *************  *
* *   *    ************  *
*    *                   *
************** ***********
*                        *
** ***********************
*      *              G  *
*  *      *********** *  *
*    *        ******* *  *
*       *                *
**************************
EOL

START = 'S'
GOAL  = 'G'
BLOCK = '*'
SPACE = ' '
ROUTE = '$'

data = MAP.split("\n").map { |line| line.chars }

start = nil
goal  = nil
edges = []

data.each_with_index do |line, y|
  line.each_with_index do |char, x|
    point = [x, y]
    case char
    when START
      start = point
      edges << point
    when GOAL
      goal = point
      edges << point
    when SPACE
      edges << point
    end
  end
end

paths = {}
edges.each do |edge|
  x, y = edge
  neighbors = [
    [x + 1, y],
    [x - 1, y],
    [x, y + 1],
    [x, y - 1]
  ].find_all { |e| edges.include?(e) }
  paths[edge] = neighbors
end

found = nil
history = Set.new
candidates = []

candidates << [start]

while !found
  new_candidates = []
  candidates.each do |route|
    edge = route.last
    if edge == goal
      found = route
      break
    end

    neighbors = paths[edge]
    neighbors.each do |e|
      next if history.include?(e)
      new_route = route + [e]
      new_candidates << new_route
    end

    history << edge
  end

  break if new_candidates.empty?
  candidates = new_candidates
end

if found
  found.each do |x, y|
    edge = data[y][x]
    data[y][x] = ROUTE if edge == SPACE
  end

  result = data.map { |line| line.join }.join("\n")
  puts result
else
  puts 'route not found.'
end