/*
*Developed by E^iπ
*Copy and edit if you like
*Free for any use
*/
#define WINDOWS 1
#ifdef WINDOWS
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <conio.h>
/* I decided to use C, not C++, at first, but I find that I don't want to make
a set myself... */
#include <set>
using namespace std;
#define U64 unsigned long long
/* To get bits */
const U64 base[16] = { 0xf, 0xf0, 0xf00,
0xf000, 0xf0000, 0xf00000,
0xf000000, 0xf0000000,
0xf00000000llu, 0xf000000000llu,
0xf0000000000llu, 0xf00000000000llu,
0xf000000000000llu,
0xf0000000000000llu,
0xf00000000000000llu,
0xf000000000000000llu
};
U64 *makerbase() {
U64 *rb = new U64[16];
for (int i = 0; i < 16; ++i) {
rb[i] = ~base[i];
}
return rb;
}
const U64 *rbase = makerbase();
/* Use a U64 to record the field. each 4bits refers to a number. *Notice that:
*Storage:(in 4 radix)
*00 01 02 03
*10 11 12 13
*20 21 22 23
*30 31 32 33
*Players see:
*01 02 03 04
*05 06 07 08
*09 10 11 12
*13 14 15 00(in Windows, 0 is blank) */
const U64 ac = 0xfedcba9876543210llu;
U64 now;
const char U_ = 0, D_ = 1, L_ = 2, IMPORT = 19,
R_ = 3, RANDF = 17, AC = 33, FAIL = -2, NEXTI = 18, ILLACT = -1;
// reverse direction
#define REV(DR) ((DR)^1)
// P means the place of '0'(seen) or 0xf(stored) in field, which can be moved.
char nowp;
#define U_ABLE(P) ((P)>3)
#define U_P(P) ((P)-4)
#define D_ABLE(P) ((P)<12)
#define D_P(P) ((P)+4)
#define L_ABLE(P) ((P)&3)
#define L_P(P) ((P)-1)
#define R_ABLE(P) (((P)&3)^3)
#define R_P(P) ((P)+1)
#define up(F,P) (F&rbase[P]&rbase[P - 4] | ((F&base[P]) >> 16) |((F&base[P- 4]) << 16))
#define down(F,P) (F&rbase[P]&rbase[P+ 4] | ((F&base[P])<<16) |((F&base[P+ 4]) >> 16))
#define left(F,P) (F&rbase[P]&rbase[P - 1] | ((F&base[P]) >>4) |((F&base[P- 1]) << 4))
#define right(F,P) (F&rbase[P]&rbase[P+ 1] | ((F&base[P])<<4) |((F&base[P+ 1]) >> 4))
void output(U64 o) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
printf("%02llu ", o + 1 & 15);
o >>= 4;
}
printf("\n\n");
}
}
inline char conv(char act) {
if (act == '2' || act == 'w')
return U_;
if (act == '8' || act == 's')
return D_;
if (act == '4' || act == 'a')
return L_;
if (act == '6' || act == 'd')
return R_;
if (act == 'r' || act == '0')
return RANDF;
if (act == 'h' || act == '1')
return NEXTI;
if (act == 'i' || act == '3')
return IMPORT;
return ILLACT;
}
inline bool act(U64 & f, char &p, char act) {
if (act == ILLACT) {
return false;
} else if (act == U_) {
if (U_ABLE(p)) {
f = up(f, p);
p = U_P(p);
} else {
return false;
}
} else if (act == D_) {
if (D_ABLE(p)) {
f = down(f, p);
p = D_P(p);
} else {
return false;
}
} else if (act == L_) {
if (L_ABLE(p)) {
f = left(f, p);
p = L_P(p);
} else {
return false;
}
} else if (act == R_) {
if (R_ABLE(p)) {
f = right(f, p);
p = R_P(p);
} else {
return false;
}
}
return true;
}
int xtime() {
#ifdef LINUX
static int t;
static struct timeval tmv;
gettimeofday(&tmv, NULL);
t = 1000 * tmv.tv_sec + tmv.tv_usec/1000;
return t;
#elifdef WINDOWS
return GetTickCount();
#endif
}
void randmove(U64 & f, char &p, int step) {
while (step--) {
act(f, p, rand() & 3);
}
}
/* Aid function for solve */
int getU(U64 F) {
int r = 0;
U64 comp = ac;
for (int i = 32; i--;) {
// the distant to ac.
r += abs((int)(F & 3) - (comp & 3));
F >>= 2;
comp >>= 2;
}
return r;
}
/* Balance between least cost and shortest answer */
int factor;
// To use std::set, we need a class.
class site {
friend bool operator <(const site & a, const site & b);
public:
U64 f;
unsigned short depth, U;
char op, p;
site() {
} site(U64 gf, int gp, int dpth, char o) {
f = gf, p = gp;
op = o; // last operate.
depth = dpth;
}
site(const site & g) {
(*this) = g;
}
inline site & operator =(const site & g) {
f = g.f, p = g.p;
depth = g.depth;
op = g.op;
U = g.U;
return *this;
}
inline int gU() {
return U = getU(f) + (depth>>factor);
}
};
inline bool operator <(const site & a, const site & b) {
return a.U < b.U ? true : (a.U == b.U && a.f < b.f);
}
set <site> doing, done;
/*
MAIN ALGORITHM: A* algorithm, a way between Brute-Force and BFS, search the
node with least U each time. */
int solve(U64 f, int p, char *r) {
int t = time(0);
doing.clear();
done.clear();
site n(f, p, 0, 5), k;
k.depth = 0;
n.gU();
doing.insert(n);
while (!doing.empty()) {
if(time(0)-t>4) {
return -10;
}
n = *doing.begin();
doing.erase(doing.begin());
done.insert(n);
if(n.depth>100) continue;
k.depth = n.depth + 1;
if (n.f == ac)
break;
/* n.op!=1 stop us from go back, not necessary, but save time. */
if (n.op != 1 && U_ABLE(n.p)) {
k.f = up(n.f, n.p);
k.p = U_P(n.p), k.op = 0;
k.gU();
if (done.find(k) == done.end()) {
doing.insert(k);
}
}
if (n.op != 0 && D_ABLE(n.p)) {
k.f = down(n.f, n.p);
k.p = D_P(n.p);
k.gU();
k.op = 1;
if (done.find(k) == done.end()) {
doing.insert(k);
}
}
if (n.op != 3 && L_ABLE(n.p)) {
k.f = left(n.f, n.p);
k.p = L_P(n.p);
k.gU();
k.op = 2;
if (done.find(k) == done.end()) {
doing.insert(k);
}
}
if (n.op != 2 && R_ABLE(n.p)) {
k.f = right(n.f, n.p);
k.p = R_P(n.p);
k.gU();
k.op = 3;
if (done.find(k) == done.end()) {
doing.insert(k);
}
}
}
/* The answer is REVERSED!!! This function will return the index of last
move(stored in r). */
int i = 0;
while (n.op != 5) {
// arrived beginning
r[i++] = (n.op);
n.depth--;
// go back
act(n.f, n.p, REV(n.op));
n.gU();
n = *done.find(n);
}
printf("\n%d,%d\n",doing.size(),done.size());
fflush(stdout);
getche();
return i - 1;
}
#ifdef WINDOWS
#define CLEAR system("cls")
#else
#define CLEAR clrscr();
#endif
int main() {
srand(time(0)^19260817);
now = ac;
nowp = 15;
bool aid=false;
int step = 0, i, in;
char *s = new char[1024],move;
const char op[4][4]{"↓ ","↑ ","→ ","← "};
while (1) {
CLEAR;
output(now);
printf("%d", step);
if(aid){
aid=false;
printf("step required:%d\n", i);
while(i>=0) {
printf("%s",op[s[i--]]);
if(i%5==0) printf("\n");
}
fflush(stdout);
}
fflush(stdout);
move = conv(getche());
if (move == RANDF) {
step = 0;
randmove(now, nowp, 666233);
} else if (move == NEXTI && now != ac) {
// If cant get short answer, add factor to get a longer one.
for (factor = 0; (i = solve(now, nowp, s))
< -1; factor++);
act(now, nowp, s[i]);
step++;
aid=true;
} else if(move==IMPORT){
now=0;
for(i=0;i<16;++i){
scanf("%d",&in);
CLEAR;
if(in==0) nowp=i;
now|=(((U64)(in-1)&15)<<i*4);
output(now);
fflush(stdout);
}
} else {
if (act(now, nowp, move))
step++;
}
}
}