Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

15 Puzzle

The goal of the 15 puzzle problem is to complete pieces on $4 \times 4$ cells where one of the cells is empty space.

In this problem, the space is represented by 0 and pieces are represented by integers from 1 to 15 as shown below.

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15

You can move a piece toward the empty space at one step. Your goal is to make the pieces the following configuration in the shortest move (fewest steps).

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 0

Write a program which reads an initial state of the puzzle and prints the fewest steps to solve the puzzle.

Input

The $4 \times 4$ integers denoting the pieces or space are given.

Output

Print the fewest steps in a line.

Constraints

The given puzzle is solvable in at most 45 steps.

Sample Input

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15

Sample Output

8

Solution in Ruby (judge verdict: Memory Limit Exceeded)

end_panels = []
4.times do |i|
  end_panels << STDIN.gets.chomp.split(' ').map(&:to_i)
end
end_panels.flatten!
 
start_panels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]
width = 4
height = 4
$queue = [[true, []], [false, []]]
forward_cache = {}
backward_cache = {}
 
def add_queue(is_forward, dicts, dict)
  dicts2 = dicts.dup
  dicts2 << dict
  $queue << [is_forward, dicts2]
end
 
while true do
  q = $queue.shift
  is_forward, dicts = q[0], q[1]
  if is_forward
    panels = start_panels.dup
  else
    panels = end_panels.dup
  end
  z = panels.index(0)
  dicts.each do |d|
    case d
    when :u then panels[z], panels[z-4] = panels[z-4], panels[z]
    when :d then panels[z], panels[z+4] = panels[z+4], panels[z]
    when :l then panels[z], panels[z-1] = panels[z-1], panels[z]
    when :r then panels[z], panels[z+1] = panels[z+1], panels[z]
    end
    z = panels.index(0)
  end
  
  if is_forward && backward_cache.key?(panels)
    puts dicts.size + backward_cache[panels].size
    break
  elsif !is_forward && forward_cache.key?(panels)
    puts dicts.size + forward_cache[panels].size
    break
  end
  if is_forward
    if !forward_cache.key?(panels) || forward_cache[panels].size > dicts.size
      forward_cache[panels] = dicts
    end
  else
    if !backward_cache.key?(panels) || backward_cache[panels].size > dicts.size
      backward_cache[panels] = dicts
    end
  end
  
  if z / width != 0 \
     && dicts[-1] != :d
    add_queue(is_forward, dicts, :u)
  end
  if z / width != height - 1 \
     && dicts[-1] != :u
    add_queue(is_forward, dicts, :d)
  end
  if z % width != 0 \
     && dicts[-1] != :r
    add_queue(is_forward, dicts, :l)
  end
  if z % width != width - 1 \
     && dicts[-1] != :l
    add_queue(is_forward, dicts, :r)
  end
end