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: Time Limit Exceeded)

class History
  def initialize
    @choice_history = []
  end

  def push(choice)
    @choice_history << choice
  end

  def pop
    @choice_history.pop
  end

  def size
    @choice_history.size
  end

  def is_previous?(choice)
    return false if @choice_history.empty?
    previous = @choice_history[-1]
    return (choice[0] == previous[1] && choice[1] == previous[0])
  end

  attr_reader :choice_history
end


class Observer
  def initialize
    @history = History.new
  end

  def calc_step_to_goal(current)
    steps = 0
    current.each_with_index do |v, i|
      next if v == 0
      goal_i = GOAL.index(v)
      steps += (goal_i%4 - i%4).abs
      steps += (goal_i/4 - i/4).abs
    end
    return steps
  end

  def can_goal?(current, limit)
    steps = calc_step_to_goal(current)
    return (steps <= limit)
  end

  attr_reader :history
end


def do_dfs(current, goal, limit, count, observer)
  return count + 1 if current == goal
  return count if !observer.can_goal?(current, limit)

  if observer.history.size < limit then
    choices = get_choice(current)
    choices.each do |choice|
      next if observer.history.is_previous?(choice)
      observer.history.push(choice)
      slide(current, choice[0], choice[1])
      count = do_dfs(current, goal, limit, count, observer)
      observer.history.pop
      slide(current, choice[1], choice[0])
    end
  end

  return count
end


SLIDE_CHOICE = [
  [1, 4], [0, 2, 5], [1, 3, 6], [2, 7],
  [0, 5, 8], [1, 4, 6, 9], [2, 5, 7, 10], [3, 6, 11],
  [4, 9, 12], [5, 8, 10, 13], [6, 9, 11, 14], [7, 10, 15],
  [8, 13], [9, 12, 14], [10, 13, 15], [11, 14]
]


def get_choice(puzzle)
  zero_pos = puzzle.index(0)
  choices = []
  SLIDE_CHOICE[zero_pos].each do |other_pos|
    choices << [zero_pos, other_pos]
  end
  return choices
end


def slide(puzzle, zero_pos, other_pos)
  puzzle[zero_pos], puzzle[other_pos] = puzzle[other_pos], puzzle[zero_pos]
end


def dfs(start, goal, max_limit)
  observer = Observer.new
  1.upto(max_limit) do |limit|
    count = do_dfs(start, goal, limit, 0, observer)
    return limit if count > 0
  end
  return -1
end


GOAL = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]

start = []
4.times do 
  start.concat(gets.chomp.split.map(&:to_i))
end

puts dfs(start, GOAL, 45)