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 C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lec13BandC
{
    public class Board
    {
        public int[] state;
        public int space;
        public int score;
        public int index;

        public Board()
        {
            state = new int[Program.N];
            index = 0;
        }

        public void NumberIn(int n)
        {
            if (n == 0) { space = index; state[index] = 0; }
            else { state[index] = n; }
            index++;
        }

        public void Copy(Board t)
        {
            t.space = this.space;
            t.score = this.score;
            for (int i = 0; i < Program.N; i++)
            {
                t.state[i] = this.state[i];
            }
        }
        
        public void ScoreCheck()
        {
            score = 0;
            for (int i = 0; i < Program.N; i++)
            {
                int  t = this.state[i]; if(t == 0) { continue; }
                score += Program.Ruler[i,t];
            }
        }
    }


    class Program
    {
        public static int NO = -999;
        public static int N;
        public static int[,] Ruler;
        public static int [] LIMIT_ARRAY= { 0,0,3,31,80};
        public static int ans;
        public static Board now;

        static void Main(string[] args)
        {
            string[] input = Console.ReadLine().Split(' ');
            NO = input.Length;
            N = NO * NO;
            Board start = new Board();

            foreach (var str in input)
            {
                start.NumberIn(int.Parse(str));
            }

            for (int i = 1; i < NO; i++)
            {
                input = Console.ReadLine().Split(' ');
                foreach (var str in input)
                { 
                    start.NumberIn(int.Parse(str));
                }
            }

            MakeOfRuler();
            start.ScoreCheck();
            now = new Board();
            start.Copy(now);

            for (ans = start.score; ans <= LIMIT_ARRAY[NO]; ans++)
            {
                start.Copy(now);
                if (PazzleSrearch(0 , 999) == true)
                {
                    Console.WriteLine(ans);
                    break;
                }

            }

            Console.ReadLine();
        }


        static bool PazzleSrearch(int dep ,int prej)
        {
            if (now.score == 0)
            {
                return true;
            }
            else if (now.score + dep > ans)
            {
                return false;
            }

            Board tmp = new Board();
            int z = now.space;

            for (int j = 0; j < 4; j++)
            {
                int v = -100;
                
                switch (j)
                {
                    case 0:
                        if (z < NO) { continue; }
                        v = z  - NO;
                        break;
                    case 1:
                        if ((z + 1) % NO == 0) { continue; }
                        v = z + 1;
                        break;
                    case 2:
                        if ((z + NO) >= N) { continue; }
                        v = z + NO;
                        break;
                    case 3:
                        if (z % NO == 0) { continue; }
                        v = z - 1;
                        break;
                }
                if (Math.Abs(prej - j) == 2) { continue; }

                now.Copy(tmp);

                now.score -= Ruler[v, now.state[v] ];
                now.score += Ruler[z, now.state[v] ];


                int t = now.state[v];
                now.state[v] = now.state[z];
                now.state[z] = t;

                now.space = v;

                if (PazzleSrearch(dep + 1 , j) == true)
                {
                    return true;
                }
                tmp.Copy(now);
            }

            return false;
        }
        
        static void MakeOfRuler()
        {
            Ruler = new int[N, N];
            for (int i = 0; i < N; i++)
            {
                for (int j =0; j< N; j++)
                {
                    int k  = Math.Abs(i / NO - j / NO) + Math.Abs(i % NO - j % NO);
                    int tj = j + 1;
                    if (tj == N) { tj = 0; }
                    Ruler[i, tj] = k;
                }
            }
        }

    }
}