#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <time.h>
int cnt = 0;
int puz_state[1000000][16];
int p_state[1000000];
struct state { int puzzle[16]; int depth; int f_n; int id;
bool operator>(const state &s) const {
return f_n > s.f_n;
}
};
state start = { {5, 3, 4, 13, 2, 0, 1, 6, 10, 11, 8, 7, 9, 12, 15, 14}, 0, 0, 0};
state goal = { {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0}, 0, 0, 0}; // evaluation
std::priority_queue <state, std::vector<state>, std::greater<state> > open;
std::vector<state> closed;
bool IsFinished(state s){
for (int i = 0; i < 15; i++) {
if (s.puzzle[i] != goal.puzzle[i]) return false;
}
return true;
}
int ManhattanOne(int n, int place){
if (goal.puzzle[n] == 0) return 0;
int q, r;
q = abs(place / 4 - n / 4);
r = abs(place % 4 - n % 4);
return q + r;
}
int manhattan(state s){
int eval = 0;
std::map<int, int> goalplace;
for (int i = 0; i < 16; i++) goalplace[goal.puzzle[i]] = i;
for (int i = 0; i < 16; i++) eval += ManhattanOne(goalplace[s.puzzle[i]], i);
return eval;
}
bool IsSamePuzzle(state s1, state s2){
for (int i = 0; i < 16; i++) {
if (s1.puzzle[i] != s2.puzzle[i]) return false;
}
return true;
}
bool InClosed(state s){
for (int i = 0; i < closed.size(); i++) {
if (IsSamePuzzle(s, closed[i])) return true;
}
return false;
}
void print_ans(int n){
if(n != 0) print_ans(p_state[n]);
for(int i = 0; i < 4; i++){
for(int j = 0; j < 4; j++){
printf("%d ", puz_state[n][i*4 + j] );
}
printf("\n");
}
printf("\n");
}
void AStar(){
state now = open.top();
open.pop();
closed.push_back(now);
if (IsFinished(now)){
print_ans(now.id);
printf("\ndepth = %d\n", now.depth);
return;
}
state s = now;
int zero;
for (int i = 0; i < 16; i++) {
if (now.puzzle[i] == 0) zero = i;
}
if (zero - 4 >= 0) {
std::swap(s.puzzle[zero - 4], s.puzzle[zero]);
if (!InClosed(s)) {
cnt++; s.id = cnt;
p_state[cnt] = now.id;
for(int i = 0; i < 16; i++) puz_state[cnt][i] = s.puzzle[i];
s.depth++;
s.f_n = manhattan(s) + s.depth;
open.push(s);
}
s = now;
}
if (zero % 4 != 0) {
std::swap(s.puzzle[zero - 1], s.puzzle[zero]);
if (!InClosed(s)) {
cnt++; s.id = cnt;
p_state[cnt] = now.id;
for(int i = 0; i < 16; i++) puz_state[cnt][i] = s.puzzle[i];
s.depth++;
s.f_n = manhattan(s) + s.depth;
open.push(s);
}
s = now;
}
if (zero % 4 != 3) {
std::swap(s.puzzle[zero + 1], s.puzzle[zero]);
if (!InClosed(s)) {
cnt++; s.id = cnt;
p_state[cnt] = now.id;
for(int i = 0; i < 16; i++) puz_state[cnt][i] = s.puzzle[i];
s.depth++;
s.f_n = manhattan(s) + s.depth;
open.push(s);
}
s = now;
}
if (zero + 4 < 16) {
std::swap(s.puzzle[zero + 4], s.puzzle[zero]);
if (!InClosed(s)) {
cnt++; s.id = cnt;
p_state[cnt] = now.id;
for(int i = 0; i < 16; i++) puz_state[cnt][i] = s.puzzle[i];
s.depth++;
s.f_n = manhattan(s) + s.depth;
open.push(s);
}
}
AStar();
return;
}
int main(){
clock_t s = clock();
start.f_n = manhattan(start);
open.push(start);
for(int i = 0; i < 16; i++) puz_state[0][i] = start.puzzle[i];
AStar();
clock_t e = clock();
std::cout << (double)(e-s)/CLOCKS_PER_SEC << std::endl;
return 0;
}