---
# System prepended metadata

title: 12819 - 15 Puzzle
tags: [Heuristic]

---

# 	12819 - 15 Puzzle
>author: Utin
###### tags: `Heuristic`

---

## Brief
See the code below

## Solution 0

```cpp=
#include <bits/stdc++.h>

enum dir {
    DOWN, UP, LEFT, RIGHT, NA
};

class State {
    public:
        int puzzle[4][4];
        int past;
        int score;
        int ex, ey;
        dir pre_move;

        State(int pu[4][4], dir p, int x, int y);
        bool operator< (const State &rhs) const;
        void setScore();
        void Update(int newX, int newY, dir preMove);
};

const int GoalX[16] = {3, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3};
const int GoalY[16] = {3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2};
const int ns[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

std::priority_queue<State> process;

int main() {
    int init[4][4], e_x, e_y;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            std::cin >> init[i][j];
            if (init[i][j] == 0) {
                e_x = i;
                e_y = j;
            }
        }
    }

    // initial state
    process.push(State(init, NA, e_x, e_y));

    while (process.size()) {
        State curr = process.top();
        if (curr.score == 0) {
            std::cout << curr.past << '\n';
            return 0;
        }
        process.pop();
        for (int i = 0; i < 4; i++) {

            // next empty position
            int newX = curr.ex + ns[i][0];
            int newY = curr.ey + ns[i][1];

            // outside the map
            if (newX < 0 || newX > 3 || newY < 0 || newY > 3) continue;

            // prevent from moving backward
            if (i == DOWN && curr.pre_move == UP) continue;
            if (i == UP && curr.pre_move == DOWN) continue;
            if (i == LEFT && curr.pre_move == RIGHT) continue;
            if (i == RIGHT && curr.pre_move == LEFT) continue;

            // construct the next State
            State nextState = curr;
            nextState.Update(newX, newY, (dir)i);
            process.push(nextState);
        }
    }
    std::cout << -1 << '\n';
}

// construct a new State
State::State(int pu[4][4], dir p, int x, int y)
: puzzle(), pre_move(p), past(), score(), ex(x), ey(y) {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            puzzle[i][j] = pu[i][j];
        }
    }
    setScore();
}

// sort from the largest to the smallest
bool State::operator< (const State &rhs) const {
    return this->score + this->past > rhs.score + rhs.past;
}

void State::setScore() {
    int s = 0;
    int goalX, goalY;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {

            // empty
            if (puzzle[i][j] == 0) continue;

            // future path
            goalX = GoalX[puzzle[i][j]];
            goalY = GoalY[puzzle[i][j]];
            s += abs(i - goalX) + abs(j - goalY);

            // linear conflict
            if (i == goalX) {
                for (int k = j; k < 4; k++) {
                    if (puzzle[i][k] > 0 && GoalX[puzzle[i][k]] == i && puzzle[i][j] > puzzle[i][k]) {
                        s += 2;
                    }
                }
            }
            if (j == goalY) {
                for (int k = i; k < 4; k++) {
                    if (puzzle[k][j] > 0 && GoalY[puzzle[k][j]] == j && puzzle[i][j] > puzzle[k][j]) {
                        s += 2;
                    }
                }
            }
        }
    }
    this->score = s;
}

void State::Update(int newX, int newY, dir preMove) {
    pre_move = preMove;
    puzzle[ex][ey] = puzzle[newX][newY];
    puzzle[newX][newY] = 0;
    ex = newX, ey = newY;
    past++;
    setScore();
}

// By Utin
```

## Reference