#include <stdio.h>
#include <string.h>
unsigned char level[5][5] = {
{ 1, 1, 1, 2, 0},
{ 3, 4, 5, 6, 6},
{ 7, 4, 5, 8, 9},
{15, 4,10,11,12},
{13,14,14,11,12}
};
int goal_x = 0, goal_y = 0;
int goal_c = 15;
int free_x, free_y;
char block_chr[16] = {' ','A','B','C','D','E','F','G','H','I','J','K','L','M','N','X'};
char block_dir[16];
unsigned char board[5][5];
unsigned char moves[60000];
unsigned int nmoves;
unsigned long lseq1, lseq2 = 0;
int init_block(int n) {
int i, j;
for(i=0; i<5; i++)
for(j=0; j<5; j++) {
if (board[i][j] != n) continue;
if (j > 0 && board[i][j-1] == n) return 1;
if (j < 4 && board[i][j+1] == n) return 1;
if (i > 0 && board[i-1][j] == n) return 2;
if (i < 4 && board[i+1][j] == n) return 2;
return 0;
}
return -1;
}
void init_board() {
int i, j;
for(i=0; i<5; i++)
for(j=0; j<5; j++) {
board[i][j] = level[i][j];
if (board[i][j] == 0) { free_x = j; free_y = i; }
}
for (i=0; i<16; i++) block_dir[i] = init_block(i);
}
void print_board() {
int i, j;
for(i=0; i<5; i++) {
for(j=0; j<5; j++)
printf(" %c", block_chr[board[i][j]]);
putchar('\n');
}
putchar('\n');
}
void print_moves() {
unsigned long i;
for (i=0; i < nmoves; i++)
if (moves[i]) printf("%c", block_chr[moves[i]]);
}
int check_goal() {
return board[goal_y][goal_x] == goal_c;
}
int check_move(int n) {
if (free_x > 0 && board[free_y][free_x-1] == n && block_dir[n] != 2) return 1;
if (free_x < 4 && board[free_y][free_x+1] == n && block_dir[n] != 2) return 2;
if (free_y > 0 && board[free_y-1][free_x] == n && block_dir[n] != 1) return 3;
if (free_y < 4 && board[free_y+1][free_x] == n && block_dir[n] != 1) return 4;
return 0;
}
int play_move(int n) {
int p = check_move(n);
if (!p) return 0;
board[free_y][free_x] = n;
switch (p) {
case 1:
while (free_x > 0 && board[free_y][free_x-1] == n) free_x--;
break;
case 2:
while (free_x < 4 && board[free_y][free_x+1] == n) free_x++;
break;
case 3:
while (free_y > 0 && board[free_y-1][free_x] == n) free_y--;
break;
case 4:
while (free_y < 4 && board[free_y+1][free_x] == n) free_y++;
break;
}
board[free_y][free_x] = 0;
return 1;
}
void load_next_board(unsigned long n) {
if (n) play_move(moves[n - 1]);
}
void load_board(void *buf) {
int i, j;
memcpy(board, buf, 25);
for(i=0; i<5; i++)
for(j=0; j<5; j++)
if (board[i][j] == 0) { free_x = j; free_y = i; }
}
void seqn(unsigned int n) {
lseq1 = n;
}
unsigned long seq() {
lseq1 += lseq2++;
lseq1 &= 0xffffffff;
lseq2 &= 0xffffffff;
return lseq1;
}
int solve_board() {
unsigned int s;
for (s=1; s < 60000; s++) {
nmoves = 0;
init_board();
seqn(s);
while (nmoves < 60000) {
int i = seq() % 15 + 1;
if (!play_move(i)) continue;
moves[nmoves++] = i;
if (check_goal()) return 1;
}
}
return 0;
}
void optimize_moves() {
char s1[25], s2[25];
unsigned long i, j, m;
init_board();
for (i=0; i < nmoves; i++) {
load_next_board(i);
memcpy(s1, board, 25);
m = 0;
for (j=i+1; j <= nmoves; j++) {
load_next_board(j);
memcpy(s2, board, 25);
if (!memcmp(s1, s2, 25)) m = j;
}
load_board(s1);
while (i < m) moves[i++] = 0;
}
load_board(s2);
}
int main() {
init_board();
print_board();
fprintf(stderr, "solving...\n");
if (solve_board()) {
fprintf(stderr, "optimizing...\n");
optimize_moves();
print_board();
print_moves();
}
return 0;
}