您的位置:首页 > 其它

A*算法解决八数码问题

2013-11-18 22:21 295 查看
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <conio.h>
#include <cstdlib>
#include <algorithm>
#include <windows.h>
using namespace std;

#define DIRECTION int

const char TEST_END = '0';
const int BOARDSIZE = 3;
const int TABLESIZE = 370000;
const int DIRECTION_SIZE = 4;
const int INIT_POS_IN_HASH = -1;
const int INIT_PARENT = -1;
const int INIT_START = -1;
const int INIT_G = 1;
const int G_GROW = 1;
const char BLANK = 'X';

enum VISITESTATE{ NOTFOUND, INOPEN, INCLOSE };
const int hashArr[9] = { 7, 17, 47, 117, 217, 977, 1299, 5971, 7779 };
const int dir_x[DIRECTION_SIZE] = { -1, 1, 0, 0 };
const int dir_y[DIRECTION_SIZE] = { 0, 0, -1, 1 }; //Up Down Left Right

struct position{

position(){}
position( int xx, int yy ):x( xx ), y( yy ){}

int x;
int y;

};

position finalPosition[BOARDSIZE * BOARDSIZE];

struct ChessBoard{

ChessBoard(){

visitState = NOTFOUND;
posInHashTable = INIT_POS_IN_HASH;

}

ChessBoard& operator = ( const ChessBoard& cb ){

for( int i = 0; i < BOARDSIZE; ++i ){
for( int j = 0; j < BOARDSIZE; ++j ){
this->ChessState[i][j] = cb.ChessState[i][j];
}
}

this->blankX = cb.blankX;
this->blankY = cb.blankY;
this->g = cb.g;
this->h = cb.h;
this->direction = cb.direction;
this->parent = cb.parent;
this->posInHashTable = cb.posInHashTable;

return *this;

}

friend bool operator < ( const ChessBoard& a, const ChessBoard& b ){
return ( a.g + a.h ) > ( b.g + b.h );
}

char ChessState[BOARDSIZE][BOARDSIZE];

VISITESTATE visitState;
int blankX;
int blankY;
int g;
int h;
int direction;
int posInHashTable;
int parent;

};

ChessBoard hashTable[TABLESIZE];

class AStarAlg{

public:

AStarAlg(){

finalState.ChessState = {
{ '1', '2', '3' },
{ '4', '5', '6' },
{ '7', '8', BLANK }
};

initChessBoard();

}

void initChessBoard();
void AStar();
void printPath( ChessBoard );
void showChessBoard( const ChessBoard& ) const;

const ChessBoard& getChessBoard( int index ){ return hashTable[index]; };
const ChessBoard& getInitalChessBoard(){ return initState; };

private:

bool isSolvable( const ChessBoard& );
bool getNextChessBoard( ChessBoard& nextState, const ChessBoard& parentState, const DIRECTION& );
int hashCal( ChessBoard& );
void setInOpen( ChessBoard& );
void updateOpen( const ChessBoard& );
bool isInOpen( const ChessBoard& ) const;
void setInClose( ChessBoard& );
bool isNotFound( const ChessBoard& ) const;
bool isInClose( const ChessBoard& ) const;
void calHeuristic( ChessBoard& );
void calG( ChessBoard& );
void calFun( ChessBoard& );
bool isEqual( const ChessBoard&, const ChessBoard& );

vector< ChessBoard >openTable;

ChessBoard initState;
ChessBoard finalState;

};

bool AStarAlg::isSolvable( const ChessBoard& cb ){

char* tempArr = new char[BOARDSIZE * BOARDSIZE + 1];
const int length = BOARDSIZE * BOARDSIZE;
int count = 0;
int countNum = 0;

for( int i = 0; i < BOARDSIZE; ++i ){
for( int j = 0; j < BOARDSIZE; ++j ){

if( initState.ChessState[i][j] == BLANK )
tempArr[count] = '9';
else
tempArr[count] = initState.ChessState[i][j];

count++;

}
}

for( int i = 0; i < length; ++i ){

const int base = tempArr[i] - '0';

for( int j = 0; j < i; ++j ){

const int cmp = tempArr[j] - '0';

if( cmp > base )
countNum++;

}
}

delete tempArr;

if( countNum % 2 != 0 )
return false;

return true;
}

void AStarAlg::setInOpen( ChessBoard& cb ){

cb.visitState = INOPEN;
hashTable[cb.posInHashTable].visitState = INOPEN;

openTable.push_back( cb );
push_heap( openTable.begin(), openTable.end() );

}

void AStarAlg::printPath( ChessBoard cb ){

if( cb.parent == INIT_PARENT ){

cout<<"Finsh."<<endl;
return;

}

vector< ChessBoard >path;

while( true ){

path.push_back( cb );
if( cb.parent == INIT_PARENT )
break;
cb = hashTable[cb.parent];

}

for( int i = path.size() - 1; i >= 0; --i ){
showChessBoard( path[i] );
}
}

void AStarAlg::updateOpen( const ChessBoard& cb ){

for( int i = 0; i < openTable.size(); ++i ){
if( isEqual( openTable[i], cb ) ){

openTable[i] = cb;
break;

}
}

make_heap( openTable.begin(), openTable.end() );

}

void AStarAlg::setInClose( ChessBoard& cb ){

hashTable[cb.posInHashTable].visitState = INCLOSE;
cb.visitState = INCLOSE;

}

bool AStarAlg::isInClose( const ChessBoard& cb ) const{
return ( hashTable[cb.posInHashTable].visitState == INCLOSE ) ? true : false;
}

bool AStarAlg::isInOpen( const ChessBoard& cb ) const{
return ( hashTable[cb.posInHashTable].visitState == INOPEN ) ? true : false;
}

bool AStarAlg::isNotFound( const ChessBoard& cb ) const{
return ( hashTable[cb.posInHashTable].visitState == NOTFOUND ) ? true : false;
}

void AStarAlg::calHeuristic( ChessBoard& cb ){

int h = 0;

for( int i = 0; i < BOARDSIZE; ++i ){
for( int j = 0; j < BOARDSIZE; ++j ){

int val = cb.ChessState[i][j] - '0';
int x = finalPosition[val - 1].x;
int y = finalPosition[val - 1].y;
h += abs( i - x ) + abs( j - y );

}
}

cb.h = h;

}

void AStarAlg::calG( ChessBoard& cb ){

if( cb.parent == INIT_PARENT )
cb.g = INIT_G;
else
cb.g = hashTable[cb.parent].g + G_GROW;

}

void AStarAlg::calFun( ChessBoard& cb ){

calHeuristic( cb );
calG( cb );

}

void AStarAlg::initChessBoard(){

string str;

cout << "Enter inital State : ";
getline( cin, str );

int count = 0;

for( int i = 0; i < str.length(); ++i ){
if( str[i] != ' ' ){

initState.ChessState[count / BOARDSIZE][count % BOARDSIZE] = str[i];

if( str[i] == 'x' ){

initState.ChessState[count / BOARDSIZE][count % BOARDSIZE] = BLANK;
initState.blankX = count / BOARDSIZE;
initState.blankY = count % BOARDSIZE;

}

++count;

}
}

initState.direction = INIT_START;
initState.parent = INIT_PARENT;
calFun( initState );
int pos = hashCal( initState );
openTable.push_back( initState );
make_heap( openTable.begin(), openTable.end() );

}

bool AStarAlg::isEqual( const ChessBoard& cbA, const ChessBoard& cbB ){

for( int i = 0; i < BOARDSIZE; ++i ){
for( int j = 0; j < BOARDSIZE; ++j ){
if( cbA.ChessState[i][j] != cbB.ChessState[i][j] )
return false;
}
}

return true;

}

int AStarAlg::hashCal( ChessBoard& cb ){

/* function: calculate the position of the state of chessboard in hashTable
if the state has been existing ( INOPEN , INCLOSE ) then return its position is hashTble
else set the state in hashTable and then return its position
PS: must after all operation ( my drawback ) */

int pos = 0;

for( int i = 0; i < BOARDSIZE; ++i ){
for( int j = 0; j < BOARDSIZE; ++j ){

int val = cb.ChessState[i][j] - '0';
pos += val * hashArr[ BOARDSIZE * i + j ];

}
}

pos = pos % TABLESIZE;

while( hashTable[pos].visitState != NOTFOUND ){

if( isEqual( hashTable[pos], cb ) ){

cb.posInHashTable = pos;

return pos;

}

pos = ( pos + 1 ) % TABLESIZE;

}

cb.posInHashTable = pos;
hashTable[pos] = cb;

return pos;

}

bool AStarAlg::getNextChessBoard( ChessBoard& tempNextState,
const ChessBoard& parentState,
const DIRECTION& dir ){
//Get temp next chess board blank_x and blank_y
int tempNextBlankX = parentState.blankX + dir_x[dir];
int tempNextBlankY = parentState.blankY + dir_y[dir];

if( tempNextBlankX < 0 || tempNextBlankX > BOARDSIZE - 1
|| tempNextBlankY < 0 || tempNextBlankY > BOARDSIZE - 1 )
return false;

tempNextState.blankX = tempNextBlankX;
tempNextState.blankY = tempNextBlankY;
tempNextState.direction = dir;

//Get temp next chess board state
for( int i = 0; i < BOARDSIZE; ++i ){
for( int j = 0; j < BOARDSIZE; ++j ){
tempNextState.ChessState[i][j] = parentState.ChessState[i][j];
}
}

char change = tempNextState.ChessState[tempNextState.blankX][tempNextState.blankY];
tempNextState.ChessState[parentState.blankX][parentState.blankY] = change;
tempNextState.ChessState[tempNextState.blankX][tempNextState.blankY] = BLANK;

//Get temp next chess board parent position
tempNextState.parent = parentState.posInHashTable;

//Get temp next chess board g and h, its parent state has got
calFun( tempNextState );

//Hash Cal
hashCal( tempNextState );

return true;

}

void AStarAlg::AStar(){

char c;

while( !openTable.empty() ){

pop_heap( openTable.begin(), openTable.end() );
ChessBoard parent = openTable.back();

if( !isSolvable( parent ) ){

cout<<"unsolvable"<<endl;

return;

}

openTable.erase( openTable.end() - 1 );
setInClose( parent );

if( isEqual( parent, finalState ) ){

printPath( parent );

return;

}

for( int i = 0; i < DIRECTION_SIZE; ++i ){

ChessBoard tempNextState;

if( !getNextChessBoard( tempNextState, parent, i ) )
continue;

if( isNotFound( tempNextState ) ){

setInOpen( tempNextState );

continue;

}

if( isInOpen( tempNextState ) ){

int f = tempNextState.g + tempNextState.h;

if( f < hashTable[tempNextState.posInHashTable].g + hashTable[tempNextState.posInHashTable].h ){

hashTable[tempNextState.posInHashTable] = tempNextState;
updateOpen( tempNextState );

continue;
}
}

if( isInClose( tempNextState ) ){

int f = tempNextState.g + tempNextState.h;

if( f < hashTable[tempNextState.posInHashTable].g + hashTable[tempNextState.posInHashTable].h ){

hashTable[tempNextState.posInHashTable] = tempNextState;
setInOpen( tempNextState );

continue;
}
}
}
}

cout << "unsolveable" << endl;

}

void AStarAlg::showChessBoard( const ChessBoard& cb ) const{

cout << endl;
cout << "<<<<<<<<<<<<<<<<<<<<<< Pandora >>>>>>>>>>>>>>>>>>>>>" << endl;
cout << "ChessBoard State : " << endl;

for( int i = 0; i < BOARDSIZE; ++i ){

for( int j = 0; j < BOARDSIZE; ++j )
cout<<cb.ChessState[i][j]<<" ";

cout<<endl;

}

cout << "Blank_X : " << cb.blankX << " " << "Blank_Y : " << cb.blankY << endl;
cout << "Position is HashTable : " << cb.posInHashTable << endl;
cout << "Parent : " << cb.parent << endl;
cout << "G : " << cb.g << " " << "H : " << cb.h << " " << "F : " << cb.h + cb.g << endl;

switch( cb.visitState ){

case NOTFOUND:{

cout << "Now my state : Not be found." << endl;
break;

}
case INOPEN:{

cout << "Now my state : In open table." << endl;
break;

}
case INCLOSE:{

cout << "Now my state : In close" << endl;
break;

}
default:{

cout << "Error state!" << endl;
break;

}
}

cout << "<<<<<<<<<<<<<<<<<<<<<< Pandora >>>>>>>>>>>>>>>>>>>>>" << '\n\n';
}

void preWork(){

int count = 0;

for( int i = 0; i < BOARDSIZE; ++i ){
for( int j = 0; j < BOARDSIZE; ++j ){

position temp;
temp.x = i;
temp.y = j;
finalPosition[count] = temp;
count++;

}
}
}

int main(){

AStarAlg a;

preWork();
a.AStar();

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: