N Puzzle
Difficulty: Hard

N Puzzle is a sliding blocks game that takes place on a k * k grid with ((k * k) - 1) tiles each numbered from 1 to N. Your task is to reposition the tiles to their proper order.

**Input Format**

The first line of the input contains an integer k, the size of the square grid. k * k lines follow each line containing an integer I on the tile starting from the top left to bottom right. The empty cell is represented by the number 0. 

N = (k * k) -1  
0 <= I <= N

**Constraints**

3 <= k <= 5

**Output Format**

The first line contains an integer, M, the number of moves your algorithm has taken to solve the N-Puzzle. M lines follow. Each line indicating the movement of the empty cell (0). 

A grid is considered solved if it is of the following configuration. 

    0 1 2
    3 4 5
    6 7 8

**Sample Input**

    3
    0
    3
    8
    4
    1
    7
    2
    6
    5


**Sample Output**

    70
    RIGHT
    DOWN
    ...
    ...
    ...

**Explanation**

The board given as input is 

    0 3 8
    4 1 7
    2 6 5

After RIGHT, the board's configuration is 

    3 0 8
    4 1 7
    2 6 5

**Task**

Print all the moves made from the given configuration to 
the final solved board configuration.

**Scoring**

On successfully solving the puzzle, your score will be k * k. 

Input Format:

Output Format:

Sample Input:

Sample Output:

Python 3 starter code:

Editorial: May 20-20 Hack Editorial: N - Puzzle
<style id="MathJax_SVG_styles">.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%}
.MathJax_SVG .MJX-monospace {font-family: monospace}
.MathJax_SVG .MJX-sans-serif {font-family: sans-serif}
.MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0}
.MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none}
.mjx-svg-href {fill: blue; stroke: blue}
</style><svg style="display: none;"><defs id="MathJax_SVG_glyphs"></defs></svg><p><strong><a href="https://www.hackerrank.com/contests/may13/challenges/n-puzzle">N Puzzle</a></strong></p>

<p>N Puzzle is a sliding blocks game that takes place on a k * k grid with k * k - 1 tiles
each numbered from 1 to N. Your task is to reposition the tiles in their proper order</p>

<p><strong>Difficulty Level</strong></p>

<p>Medium ( Implementation heavy )</p>

<p><strong>Problem Setter</strong></p>

<p><a href="https://www.hackerrank.com/dheeraj">Dheeraj M R</a></p>

<p><strong>Required Knowledge</strong></p>

<p>A* algorithm</p>

<p><strong>Approach</strong></p>

<p>N-Puzzle is a classic 1 player game that teaches the basics of heuristics in arriving at 
solutions in Artificial Intelligence. </p>

<p>Let us consider for the sake of simplicity, N = 8</p>

<p>The final configuration of an 8 - puzzle will look like</p>

<pre><code>0 1 2
3 4 5
6 7 8
</code></pre>

<p><a href="https://www.hackerrank.com/challenges/pacman-astar">A*</a> algorithm talks about a cost function
and a heuristic. </p>

<p>cost = heuristic_cost + #of steps taken to reach the current state.</p>

<p>the tiles are numbered. For a given unsolved 8 - puzzle configuration say</p>

<pre><code>0 3 8
4 1 7
2 6 5
</code></pre>

<p>We use 2 heuristics for every state and at every iteration</p>

<p>1 such heuristic is </p>

<p>h1 =&gt; The number of misplaced tiles.</p>

<p>In the above example, the number of misplaced tiles are 8</p>

<p>2<sup>nd</sup> heuristic we use is</p>

<p>h2 =&gt; The manahattan distance between a tile's original position to its current position.</p>

<p>In the above example, the manhattan distance for all tiles are as follows</p>

<p>a<sub>b</sub> =&gt; where a is the manhattan distance of tile <em>b</em>.</p>

<p>h2 = 2<sub>3</sub> + 2<sub>8</sub> + 1<sub>4</sub> + 1<sub>1</sub> + 2<sub>7</sub> + 4<sub>2</sub> + 1<sub>6</sub> + 1<sub>5</sub></p>

<p>h2 = 14</p>

<p>Given 2 heuristics, it is always advised to use the maximum as the maximum never underestimates the cost to reach the 
required end state ( initial configuration of 8 Puzzle )</p>

<p>If it took 10 moves to reach the current state as shown above, then the cost function of a given state of N - puzzle</p>

<p>is given as </p>

<pre><code>cost = max( h1, h2 ) + 10

cost = max( 14, 8 ) + 10 = 24
</code></pre>

<p>We can then implement a priority queue and record each of possible moves from a given initial state of the board
and then pop the state with the lowest cost function. This procedure is guaranteed to give us a solution.</p>

<p><strong>Problem Setter's code: C++</strong></p>

<p><a href="https://gist.github.com/dheerajrav/5748717">here</a></p>

Reference solution (C++):
    #include<iostream>
    #include<vector>
    #include<queue>
    #include<set>
    #include<map>
    #include<algorithm>

    #define INRANGE(i, a, b) (i >= a && i < b)

    using namespace std;


    class SlidingBlock
    {
        public:
            vector < int > disc;
            int n;
            int cost;
            int empty_slot;
            vector< string > record_move;
            SlidingBlock();
            SlidingBlock( int );
            SlidingBlock( vector < int >, vector < string > );
            vector < string > getMove();
            void makeMove( const string move = string() );
            bool solved();
            vector < SlidingBlock > branches();
            void setCost();
            void print();
            void readBlock();
            bool operator< ( const SlidingBlock& ) const;
            bool operator> ( const SlidingBlock& ) const;
    };

    SlidingBlock::SlidingBlock()
    {
        SlidingBlock( 3 );
    }

    SlidingBlock::SlidingBlock( int size )
    {
        n = size;
    }

    void SlidingBlock::readBlock()
    {
        int temp;
        for( int i = 0; i < n; i++ )
        {
            for( int j = 0; j < n; j++ )
            {
                cin >> temp;
                disc.push_back( temp );
            }
        }
        int pos = std::abs( std::distance( find( disc.begin(), disc.end(), 0 ), disc.begin()) );
        empty_slot = pos;
        setCost();

    }

    SlidingBlock::SlidingBlock( vector < int > node, vector < string > moves )
    {
        disc.clear();
        n = ( int )sqrt( node.size() );
        for( int i = 0; i < ( int )node.size(); ++i )
        {
            disc.push_back( node[ i ] );
            if( node[ i ] == 0 )
                empty_slot = i;
        }

        for( int i = 0; i < moves.size(); i++ )
            record_move.push_back( moves[ i ] );
        setCost();
    }

    void SlidingBlock::setCost()
    {
        int h1 = 0 , h2 = 0;
        //setting heuristic 1 => number of misplaced blocks
        //setting heuristic 2 => distance of the node to its block
        for( int i = 0; i < n; i++ )
        {
            for( int j = 0; j < n; j++ )
            {

                int val = disc[ n * i + j ];
                if( val != n * i + j && val != 0 )
                {
                    h1 += 1;
                    int exp_pos_x = ( val ) / n;
                    int exp_pos_y = ( val ) % n;
                    h2 += abs( i - exp_pos_x ) + abs( j - exp_pos_y );
                }
            }
        }
        cost = max( h1, h2) + this->record_move.size();
    }

    vector < string > SlidingBlock::getMove()
    {
        vector < string > movements;
        if( empty_slot/n > 0 )
            movements.push_back( "UP" );
        if( empty_slot%n > 0 )
            movements.push_back( "LEFT" );
        if( empty_slot/n < n - 1 )
            movements.push_back( "DOWN" );
        if( empty_slot%n < n - 1 )
            movements.push_back( "RIGHT" );

        return movements;
    }

    void SlidingBlock::makeMove( string move )
    {
        if( move.empty() )
        {
            vector < string > moves = getMove();
            int rand_point_index = rand() % moves.size();
            makeMove( moves[ rand_point_index ] );
        }
        else
        {
            record_move.push_back( move );
            int temp = empty_slot;
            if( move.compare("UP") == 0 )
                empty_slot -= n;
            if( move.compare("DOWN") == 0 )
                empty_slot += n;
            if( move.compare("LEFT") == 0 )
                empty_slot -= 1;
            if( move.compare("RIGHT") == 0 )
                empty_slot += 1;
            swap( disc[ temp ], disc[ empty_slot ] );
        }
        setCost();
    }

    bool SlidingBlock::solved()
    {
        bool answer = true;
        for( int i = 0; i < n; i++ )
        {
            for( int j = 0; j < n; j++ )
            {
                answer &= disc[ n * i + j ] == ( n * i + j );
            }
        }
        return answer;
    }

    vector < SlidingBlock > SlidingBlock::branches()
    {
        vector < string > moves = getMove();
        vector < SlidingBlock > valid_branches;
        for( int i = 0; i < ( int )moves.size(); ++i )
        {
            valid_branches.push_back( SlidingBlock( disc , record_move ) );
            valid_branches[ i ].makeMove( moves[ i ] );
        }
        return valid_branches;
    }

    void SlidingBlock::print()
    {
        for( int i = 0; i < n; i++ )
        {
            for( int j = 0; j < n; j++ )
            {
                cout << disc[ n*i + j ] << " ";
            }
            cout << endl;
        }
    }

    bool SlidingBlock::operator< ( const SlidingBlock& node ) const
    {
        for( int i = 0; i < ( int )node.disc.size(); i++ )
        {
            if( node.disc[ i ] < this->disc[ i ] )
            {
                return true;
            }
            else if( node.disc[ i ] > this->disc[ i ] )
            {
                return false;
            }
            else
            {
                continue;
            }
        }
        return false;
    }

    bool SlidingBlock::operator> ( const SlidingBlock& node ) const
    {
        for( int i = 0; i < ( int )node.disc.size(); i++ )
        {
            if( node.disc[ i ] > this->disc[ i ] )
            {
                return true;
            }
            else if( node.disc[ i ] < this->disc[ i ] )
            {
                return false;
            }
            else
            {
                continue;
            }
        }
        return false;
    }

    struct OrderByCost
    {
        bool operator() ( const SlidingBlock &a, const SlidingBlock &b ) const
        {
            return a.cost >= b.cost;
        }
    };

    class Search
    {
        public:
            SlidingBlock start;
            priority_queue< SlidingBlock, vector < SlidingBlock >, OrderByCost > pq;
            set< SlidingBlock > explored;
            vector < SlidingBlock > expanded;

            Search( int n )
            {
                start = SlidingBlock( n );
                start.readBlock();
                searchAndPrint();
            }

            void searchAndPrint()
            {
                pushNode( start );
                SlidingBlock node = SlidingBlock( start.disc, start.record_move );
                setExplored( node );
                while( !node.solved() )
                {
                    node = getNextNode();
                    expanded.push_back( node );
                    vector < SlidingBlock > valid_branches = node.branches();
                    //Iterate over neighbors
                    for( int i = 0; i < ( int ) valid_branches.size(); i++ )
                    {
                        if( !isExplored( valid_branches[ i ] ) )
                        {
                            pushNode( valid_branches[ i ] );
                            setExplored( node );
                        }
                    }
                }
                cout << node.record_move.size() << endl;

                for( auto i = node.record_move.begin(); i != node.record_move.end(); ++i )
                    cout << *i << endl;

            }

            void pushNode( SlidingBlock node )
            {
                pq.push( node );
            }

            void setExplored( SlidingBlock node )
            {
                explored.insert( node );
            }

            bool isExplored( SlidingBlock node )
            {
                return explored.count( node ) > 0;
            }

            SlidingBlock getNextNode()
            {
                SlidingBlock node = pq.top();
                pq.pop();
                return node;
            }
    };

    int main()
    {
        set< SlidingBlock > explored;
        int n;
        cin >> n;
        Search *game = new Search( n );
    }