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)

class FifteenPuzzle
  N = 4
  N2 = N * N
  DX = [ 0, 1, 0, -1 ]
  DY = [ 1, 0, -1, 0 ]
  DIR = [ 'u', 'r', 'd', 'l' ]
  MDTable = Array.new(N2).map { Array.new(N2) }

  class Puzzle
    attr_accessor :cost, :space, :f, :md

    def initialize
      @f = []
    end

    # get current md
    def calc_all_md
      sum = 0
      (0...N2).each do |i|
        sum += MDTable[i][@f[i] - 1] if @f[i] != N2
      end
      @md = sum
    end

    def initialize_copy(obj)
      @f = obj.f.dup
      @space = obj.space
      @cost = obj.cost
      @md = obj.md
    end
  end

  class State
    attr_accessor :estimate, :puzzle

    def initialize
      @puzzle = Array.new(N2)
    end

  end

  def initialize
    # init MDtable
    (0...N2).each do |i|
      (0...N2).each do |j|
        MDTable[i][j] = get_manhattan_distance(i % N, i / N, j % N, j / N)
      end
    end

    @puzzle = Puzzle.new
    4.times do
      @puzzle.f << gets.split.map(&:to_i)
      @puzzle.f.flatten!
    end

    (0...N2).each do |i|
      if @puzzle.f[i] == 0
        @puzzle.f[i] = N2
        @puzzle.space = i
      end
    end
  end

  def astar
    q = []
    @puzzle.calc_all_md
    @puzzle.cost = 0
    ex = {}
    initial_state = State.new
    initial_state.puzzle = @puzzle
    initial_state.estimate = @puzzle.md
    q.push initial_state

    while !q.empty?
      st = q.shift
      u = st.puzzle

      return u.cost if u.md == 0
      ex[u.f] = true

      sx = u.space / N
      sy = u.space % N

      (0..3).each do |i|
        tx = sx + DX[i]
        ty = sy + DY[i]
        next if tx < 0 || N <= tx || ty < 0 || N <= ty
        v = u.dup
        v.md -= MDTable[tx * N + ty][v.f[tx * N + ty] - 1]
        v.md += MDTable[sx * N + sy][v.f[tx * N + ty] - 1]
        # swap
        v.f[sx * N + sy], v.f[tx * N + ty] = v.f[tx * N + ty], v.f[sx * N + sy]
        v.space = tx * N + ty
        unless ex[v]
          v.cost += 1
          new_state = State.new
          new_state.puzzle = v
          new_state.estimate = v.cost + v.md
          q.push new_state
        end
      end
    end
    return -1
  end

  def get_manhattan_distance(x1, y1, x2, y2)
    return (x1 - x2).abs + (y1 - y2).abs
  end

end

fp = FifteenPuzzle.new
puts fp.astar