Puzz.h
/*
* Puzzle.h
*
* Created on: 2011-9-15
* Author: brunie
*/
#ifndef PUZZLE_H_
#define PUZZLE_H_
#define R 3
#define G 0
#define H 1
#define Left 1
#define Right 2
#define Up 3
#define Down 4
#define Max 5000
#define STEP 500
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Node
{
struct Node *pcome_from;
int f_score;
int g_score;
int h_score;
char data[R*R + 1];
}Node;
typedef struct Set
{
int size;
struct Node *set[Max + 1];
}Set;
extern int PlayGame();
#endif /* PUZZLE_H_ */
Puzz.c
/*
* Puzzle.c
*
* Created on: 2011-9-15
* Author: brunie
*/
#include "Puzzle.h"
Node *goal;
Node *start;
Set *openset;
Set *closedset;
int step = 0;
Node *path[STEP];
extern Node* Get_Min_Node(Set *aset);
extern int Insert_Node(Set *aset, Node *node);
extern int Search_Node(Set *aset, Node *node);
extern int IsEqual(Node *a, Node *b);
void Swap(char *a, char *b)
{
char t = *a; *a = *b; *b = t;
}
int Get_H_Score(Node *current)
{
int i;
int len = R * R;
int h_score = 0;
for(i = 0; i < len ; i++)
{
if(i != current->data[len])
{
h_score += abs(current->data[i]/R - i/R);
h_score += abs(current->data[i]%R - i%R);
}
}
return h_score;
}
Node* GetNextNode(Node *cur, int flag)
{
Node *next = (Node*)malloc(sizeof(Node));
int i;
int len = R*R;
for(i = 0; i <= len; i++)
next->data[i] = cur->data[i];
int n = next->data[len];
switch(flag)
{
case Left:
if(n%R == 0)
return 0;
else
{Swap(next->data + n - 1, next->data + n); next->data[len]--;}
break;
case Right:
if((n+1)%R == 0)
return 0;
else
{Swap(next->data + n, next->data + n + 1);next->data[len]++;}
break;
case Up:
if(n/R == 0)
return 0;
else
{Swap(next->data + n, next->data + n - R);next->data[len] -= R;}
break;
case Down:
if(n/R == R - 1)
return 0;
else
{Swap(next->data + n, next->data + n + R);next->data[len] += R;}
break;
default:
return 0;
}
return next;
}
int InitSet()
{
openset = (Set*)malloc(sizeof(Set));
closedset = (Set*)malloc(sizeof(Set));
if(0 == openset || 0 == closedset)
return -1;
openset->size = 0;
closedset->size = 0;
return 0;
}
int IsFeasible(Node *start)
{
int i,j,t = 0;
int len = R*R;
for (i = 1; i < len; i++)
{
if(start->data[i] != 0)
{
for(j = 0; j < i; j++)
{
if(start->data[j] > start->data[i])
t++;
}
}
}
if (t % 2 == 0)
return 0;
return -1;
}
int GetRandStart()
{
int i,n;
int len = R * R;
start = (Node*)malloc(sizeof(Node));
if (start)
{
for (i = 0; i < len; i++)
start->data[i] = i;
}
else return -1;
while(1)
{
srand((unsigned)time(0));
for (i = 0; i < len; i++)
{
n = rand() % len;
Swap(start->data + i, start->data + n);
}
if(0 == IsFeasible(start))
break;
}
for (i = 0; i < len; i++)
{
if(start->data[i] == 0)
{
start->data[len] = i;break;
}
}
start->pcome_from = 0;
start->g_score = 0;
start->h_score = Get_H_Score(start);
start->f_score = start->h_score;
return 0;
}
int GetSpecStart()
{
int i;
int len = R * R;
start = (Node*)malloc(sizeof(Node));
if (start)
{
for (i = 0; i < len; i++)
start->data[i] = len - i -1;
}
else return -1;
start->pcome_from = 0;
start->g_score = 0;
start->h_score = Get_H_Score(start);
start->f_score = start->h_score;
return 0;
}
int Init()
{
if(-1 == InitSet()) return -1;
if(-1 == GetRandStart()) return -1;
//if(-1 == GetSpecStart()) return -1;
openset->set[1] = start;
openset->size++;
return 0;
}
int Output(Node *cur)
{
int i;
int len = R * R;
if (0 == cur) return -1;
printf("hscore: %d\n", cur->h_score);
for(i = 0; i < len; i++)
{
printf("%d ",cur->data[i]);
if (i % R == R - 1)
printf("\n");
}
printf("\n");
return 0;
}
int Get_Path(Node *goal)
{
Node *p = goal;
while(p)
{
path[step++] = p;
p = p->pcome_from;
}
step--;
return 0;
}
int AStar()
{
Node *cur = 0,*next;
int ng_score;
int i;
int modify, exist;
while (openset->size)
{
cur = Get_Min_Node(openset);
//Output(cur);
if(cur->h_score == 0)
{
goal = cur;
return Get_Path(goal);
}
if(-1 == Insert_Node(closedset, cur))
break;
for (i = 1; i <= 4; i++)
{
next = GetNextNode(cur, i);
if(0 == next)
continue;
next->h_score = Get_H_Score(next);
if(Search_Node(closedset, next) == 0)
continue;
ng_score = cur->g_score + 1;
if (Search_Node(openset, next) != 0)
{
modify = 1;
exist = 0;
}
else if (ng_score < next->g_score)
{
modify = 1;
exist = 1;
}
else
{
modify = 0;
exist = 1;
}
if (modify)
{
next->pcome_from = cur;
next->g_score = ng_score;
next->f_score = G * next->g_score + H * next->h_score;
if (!exist)
if( Insert_Node(openset, next)) break;
}
}
}
return -1;
}
int PrintPath()
{
int i;
for (i = step; i >= 0; i--)
{
if(Output(path[i]) == -1)
return -1;
}
printf("Total steps: %d\n",step);
return 0;
}
int PlayGame()
{
if(0 == Init())
{
if(0 == AStar())
{
return PrintPath();
}
else
printf("Memory not enough!\n");
}
else
printf("Init failure!\n");
return -1;
}
MinHeap.c
/*
* Minheap.c
*
* Created on: 2011-9-18
* Author: brunie
*/
#include "Puzzle.h"
Node* Get_Min_Node(Set *aset)
{
int set_size = aset->size;
Node **set = aset->set;
if (set_size == 0)
return 0;
Node *min = set[1];
Node *y = set[set_size--];
int i = 1, // current node of heap
ci = 2; // child of i
while (ci <= set_size)
{
if (ci < set_size && set[ci]->f_score > set[ci+1]->f_score)
ci++;
if (y->f_score <= set[ci]->f_score) break;
// no
set[i] = set[ci]; // move child up
i = ci; // move down a level
ci *= 2;
}
set[i] = y;
aset->size--;
return min;
}
int Insert_Node(Set *aset, Node *node)
{
int set_size = aset->size;
Node **set = aset->set;
if(set_size == Max)
return -1;
int i = ++set_size;
while (i != 1 && node->f_score < set[i/2]->f_score)
{
// cannot put x in heap[i]
set[i] = set[i/2]; // move element down
i /= 2; // move to parent
}
set[i] = node;
aset->size++;
return 0;
}
int IsEqual(Node *a, Node *b)
{
int i;
int len = R*R;
if(a->h_score != b->h_score)
return -1;
for (i = len; i >= 0; i--)
{
if(a->data[i] != b->data[i])
return -1;
}
return 0;
}
int Search_Node(Set *aset, Node *node)
{
int set_size = aset->size;
Node **set = aset->set;
int i;
for (i = 1; i <= set_size; i++)
{
if (IsEqual(set[i], node) == 0)
return 0;
}
return -1;
}
Main.c
/*
* Main.c
*
* Created on: 2011-9-15
* Author: brunie
*/
#include "Puzzle.h"
int main()
{
PlayGame();
return 0;
}