8er-Puzzle
-
Hallo!
Ich habe ein Problem. Ich möchte ein sogenanntes 8er-Puzzle lösen.
Ich habe zwar ein Programm das funktioniert, dieses verwendet aber eine eigene Klasse als queue. Nun möchte ich aber eine priority_queue der STL verwenden. Kann mir jemand helfen, wie ich das anstellen kann??
Vielen Dank schon im Voraus!
mfgmain:
#include <iostream>
#include "puzzle.h"
#include <queue>
#include <deque>
#include <functional>using namespace std;
int main()
{cout << "Programm zur Loesung des 8er-Puzzle" << endl;
bool flag = true;
//Heuristik waehlen
cout << "Welche Heuristik?" << endl;
cout << "1 fuer Spielsteine" << endl;
cout << "2 fuer Manhattan" << endl;
cout << "3 zum Beenden des Programms" << endl;
int Eingabe;
cin >> Eingabe;if(Eingabe == 3)
return 0;//Startzustand
//int arrStart[3][3] = {{1,0,3},{8,2,4},{7,6,5}};
int arrStart[3][3];
cout << "Geben Sie den Startzustand ein:" << endl;
cout << "Zahlen von 0-8 in einer beliebigen Reihenfolge" << endl;for (int i = 0; i < 9; i++)
cin >> arrStart[i/3][i%3];//Endzustand
int arrZiel[3][3] = {{1,2,3},{8,0,4},{7,6,5}};cout << "Startzustand:" << endl;
for(int x = 0; x<3; x++){
for(int y = 0; y<3 ; y++)
cout << arrStart[x][y];
cout << endl;
}
cout << endl;//priority_queue<int,deque<int> > puzzle;
//puzzle.push(arrStart);
//puzzle.push(arrZiel);expsortqueue puzzle(arrStart, arrZiel);
knoten *best;//priority_queue<knoten *, deque<int> > OPEN;
list<knoten *> CLOSED;best = puzzle.pop();
if(Eingabe == 2){
while (best->manhattan() != 0 && flag){
puzzle.expand(best);
best = puzzle.pop();
best->printKnoten();
//Aktuellen Stand drucken?
flag = !puzzle.isemptyqueue();
}
}
else{
while (best->spielsteine() != 0 && flag){
puzzle.expand(best);
best = puzzle.pop();
best->printKnoten();
//Aktuellen Stand drucken?
flag = !puzzle.isemptyqueue();
}}
if (flag){
cout << "Solution found!" << endl;
cout << "The sequence to get to the goal is: ";
best->printWeg();
cout << "Zielzustand:" << endl;
best->printKnoten();
}
else
cout << "Problem has no solution, search tree exausted. Expanded " << best->level() << " levels" << endl;//cout << puzzle.nodesexpanded << " nodes expanded" << endl;
delete [] best;
return 0;
}puzzle.h:
#ifndef _PUZZLE_
#define _PUZZLE_#include <list>
#include <queue>
#include <cmath>
using namespace std;//moegliche Richtungen
enum richtung{UP, RIGHT, DOWN, LEFT, CENTER};//Zielzustand
int ziel[9];//ein Punkt auf dem Brett
struct punkt{
int x;
int y;
};class knoten {
private:
//int * puzzle; //Puzzle des Knotens
knoten *nextKnoten; //Nächster Knoten in der queue
int h,g; //Schätzwert Heuristik und Pfadkosten
punkt leer; //Position des leeren Steins (0)
richtung weg[2020]; //Speichert die Schritte der Leerstelle
//struct listenelement *wegende; //Zeiger auf letzten Wegknoten
//struct listenelement *weg; //Zeiger auf ersten Wegknoten
public:
knoten(knoten *vorgaenger, richtung dir); //Konstruktor
knoten(int brt[3][3]); //Konstruktor
int brett[3][3]; //8-puzzle brett
void insert(knoten *next); //Fügt knoten ein
knoten *getNext(); //Gibt adresse des nächsten Knoten zurück
int f(); //Gibt f(n) zurück
int manhattan(); //Gibt Manhattan-Distanz oder Spielsteine zurück
int spielsteine();
bool schieben(richtung dir); //Gibt an ob die Leerstelle in diese Richtung verschoben werden kann
int level(); //Gibt den Level zurück, basierend auf g(n)
richtung letzteDir(); //Gibt die Richtung an, in welche die Leerstelle als letztes verschoben wurde
void printWeg(); //Gibt den Loesungsweg des Puzzles aus
void printKnoten();
};//Prototypen
int position(knoten *square);
void change(int &n1, int &n2); //switch two items of a matrix
punkt copyboard(int src[3][3], int dest[3][3]); //copy a matrix representing a board and return the zero position
richtung invers(richtung dir);// Priority queue
class expsortqueue {
private:
knoten *first; //pointer to first node in queue (biggest f(n))
knoten *last; //pointer to last node in queue (smallest f(n))
int initial[3][3]; //initial state
char visits[45360]; //binary hash to store the states already used (positions = 9!/8bits)
public:
//int queuesize; //just for testing
//int nodesexpanded; //just for testing
expsortqueue(int init[3][3], int ending[3][3]); //constructor
~expsortqueue(); //destructor
knoten *pop(); //get node on top of the queue
void pushnsort(knoten *newnode); //put a new node in the queue
void expand(knoten *parent); //expands a node
bool isemptyqueue(); //determines if there are more states left in the queue
bool wasvisited(knoten *square);
void dovisit(knoten *square);
};//struct liste {
// struct listenelement *anfang;
// struct listenelement *ende;
//};//struct knoten V[
//Implementation der Klasse knoten
//Konstruktor fuer Startknoten
knoten::knoten(int brt[3][3])
{
g = 0;//copy brd into this node's board
leer = copyboard(brt, brett);h = manhattan(); //get manhatan distance
//setup linked list
weg[0]=CENTER;
weg[1]=CENTER;
nextKnoten = NULL;}
//Konstruktor fuer weitere Knoten
knoten::knoten(knoten *vorgaenger, richtung dir)
{
int i;
punkt lastblank;
g = vorgaenger->g + 1;//make a copY of the parent's board into this node's board
leer = copyboard(vorgaenger->brett, brett);//move positions according to direction dir
lastblank = leer;
switch(dir){
case UP: leer.y--; break;
case RIGHT: leer.x++; break;
case DOWN: leer.y++; break;
case LEFT: leer.x--; break;
}
change(brett[lastblank.y][lastblank.x], brett[leer.y][leer.x]);h = manhattan(); //get manhatan distance
//setup linked list
for (i=1; vorgaenger->weg[i] != CENTER; i++)
weg[i]=vorgaenger->weg[i];
weg[i] = dir;
weg[i+1] = CENTER;
nextKnoten = NULL;
}bool knoten::schieben(richtung dir)
{
switch(dir){
case UP: if (leer.y > 0) return true; break;
case RIGHT: if (leer.x < 2) return true; break;
case DOWN: if (leer.y < 2) return true; break;
case LEFT: if (leer.x > 0) return true; break;
}
return false;
}int knoten::manhattan()
{
int i, pos;
int result=0;
int x, y;//the goal is defined by putting the position (1 trhough 9)
//of the square at the array item with index equal to the
//face number of the square.
//smallnum ending[9] = {4,0,1,2,5,8,7,6,3}; //bonus = {8,0,1,2,3,4,5,6,7}for (i = 0; i < 9; i++){
y = i/3;
x = i%3;
pos = brett[y][x];
result+=abs(x - ziel[pos]%3); //addiere x distanz
result+=abs(y - ziel[pos]/3); //addiere y distanz
}
return result;
}int knoten::spielsteine()
{
int i, pos;
int result=0;
int x, y;//the goal is defined by putting the position (1 trhough 9)
//of the square at the array item with index equal to the
//face number of the square.
//smallnum ending[9] = {4,0,1,2,5,8,7,6,3}; //bonus = {8,0,1,2,3,4,5,6,7}for (i = 0; i < 9; i++){
y = i/3;
x = i%3;
pos = brett[y][x];
if((abs(x - ziel[pos]%3) + abs(y - ziel[pos]/3)) != 0)
result++;
//Addiere 1 fuer jeden Spielstein, der nicht an der richtigen Position liegt
}
return result;
}void knoten::printKnoten()
{
int i;for (i = 0; i < 9; i++){
cout << brett[i/3][i%3];
if (i%3 == 2)
cout << endl;
}
cout << endl;
}int knoten::level()
{
return g;
}richtung knoten::letzteDir()
{
return weg[g];
}void knoten::printWeg()
{
int i = 1;//Print solution using the history
while (weg[i] != CENTER){
switch(weg[i]){
case UP: cout << "up, "; break;
case DOWN: cout << "down, "; break;
case LEFT: cout << "left, "; break;
case RIGHT: cout << "right, "; break;
}
i++;
}
cout << endl;
}knoten *knoten::getNext()
{
return nextKnoten;
}void knoten::insert(knoten *next)
{
nextKnoten = next;
}int knoten::f()
{
return g + h;
}//Implementation der queue Klasse
expsortqueue::expsortqueue(int init[3][3], int ending[3][3]) //constructor
{
int i;//copy starting and ending states
for (i = 0; i < 9; i++){
ziel[ending[i/3][i%3]]=i;
initial[i/3][i%3] = init[i/3][i%3];
}//initialize visited states to 0
for (i = 0; i < 45360; i++)
visits[i] = 0;//initialize linked list
first = new knoten(initial);
last = first;
//queuesize = 1;
//nodesexpanded = 0;
}expsortqueue::~expsortqueue(){
knoten *i, *tmp;for (i = pop(); i!=NULL; i = pop())
delete [] i;
}// create the children for parent node
void expsortqueue::expand(knoten *vorgaenger)
{
richtung i;
knoten *newnode;
int h, g; //heuristics and path cost
int brett[3][3]; //8-puzzle board
punkt leer; //position of blank space (0)i = UP;
//make just the necessary objects
//avoid making imposible states and states coming from the state before de parent
if (invers(vorgaenger->letzteDir())!=i && vorgaenger->schieben(i)){
newnode = new knoten(vorgaenger, i);
//don't push new state if it was already used
if (!wasvisited(newnode)){//nodesexpanded++;
pushnsort (newnode);
}
else{
delete [] newnode;
}
}i = RIGHT;
//make just the necessary objects
//avoid making imposible states and states coming from the state before de parent
if (invers(vorgaenger->letzteDir())!=i && vorgaenger->schieben(i)){
newnode = new knoten(vorgaenger, i);
//don't push new state if it was already used
if (!wasvisited(newnode)){//nodesexpanded++;
pushnsort (newnode);
}
else{
delete [] newnode;
}
}
i = DOWN;
//make just the necessary objects
//avoid making imposible states and states coming from the state before de parent
if (invers(vorgaenger->letzteDir())!=i && vorgaenger->schieben(i)){
newnode = new knoten(vorgaenger, i);
//don't push new state if it was already used
if (!wasvisited(newnode)){//nodesexpanded++;
pushnsort (newnode);
}
else{
delete [] newnode;
}
}
i = LEFT;
//make just the necessary objects
//avoid making imposible states and states coming from the state before de parent
if (invers(vorgaenger->letzteDir())!=i && vorgaenger->schieben(i)){
newnode = new knoten(vorgaenger, i);
//don't push new state if it was already used
if (!wasvisited(newnode)){//nodesexpanded++;
pushnsort (newnode);
}
else{
delete [] newnode;
}
}//register use of state of parent node
dovisit(vorgaenger);delete [] vorgaenger;
}
void expsortqueue::dovisit(knoten *square)
{
int pos, i; //position number of a given configuration of the board
int power;//get position number of the board of state "square"
pos = position(square);//get 2^(pos%8)
power = 1;
power = ( pos%8 == 0)?power = 1:power << (pos%8);//mark position as visited
visits[pos/8] = visits[pos/8] | power;}
bool expsortqueue::wasvisited(knoten *square)
{
int pos; //position number of a given configuration of the board
int power;//get position number of the board of state "square"
pos = position(square);//get 2^(pos%8)
power = 1;
power = (pos%8 == 0)?power = 1:power << (pos%8);//determine if position has been visited
return ((visits[pos/8] & power) > 0);
}//return first node in priority queue (delete it from queue)
knoten *expsortqueue::pop()
{
knoten *oldfirst;oldfirst = first;
if (first != NULL){
first = first->getNext();
}//queuesize--;
return oldfirst;}
//push node to queue
void expsortqueue::pushnsort(knoten *newNode)
{
knoten *n, *prev;//in case the node is the first one to be pushed
if ((first == NULL) || (first->f() > newNode->f())){
newNode->insert(first);
first = newNode;
}
else{
//look for ordered place in queue
for (n = first->getNext(), prev = first; n != NULL; prev = n, n = n->getNext()){
if (newNode->f() < n->f()){
prev->insert(newNode);
newNode->insert(n);
n==NULL;
}
}
}
//in case the node is the last one to be pushed
if (newNode->getNext() == NULL){
last->insert(newNode);
last = newNode;
}
//queuesize++;}
bool expsortqueue::isemptyqueue()
{
return (first == NULL);
}//Hilfsfunktionen
punkt copyboard(int src[3][3], int dest[3][3])
{
int i;
punkt zero;//copy array src to dest
for (i = 0; i < 9; i++){
dest[i/3][i%3] = src[i/3][i%3];
if (src[i/3][i%3] == 0){
zero.x = i%3;
zero.y = i/3;
}
}return zero;
}//switch operation
void change(int &n1, int &n2)
{
int tmp;tmp = n1;
n1 = n2;
n2 = tmp;}
//return the opsosite direction to each possible direction
richtung invers(richtung dir)
{
switch(dir){
case UP: return DOWN;
case DOWN: return UP;
case LEFT: return RIGHT;
case RIGHT: return LEFT;
case CENTER: return CENTER;
}
}int position(knoten *square)
{
char i, j; //loop counters
char h=0; //unit count for a given position
int pos = 0; //position number of a given configuration of the board
int bases[] = {1, 9, 72, 504, 3024, 15120, 60480, 181440, 362880}; //bases to use to count number of possible positions in the board
int power, reg = 0; //register for numbers already used//for each position in the board
for (i=0; i < 9; i++){
//check if each number is used in the corresponding order...
for (j=0; j < 9; j++){
power = 1;
power = (j == 0)?power = 1:power << j;
//...skiping numbers that were already used
if ((reg & power) == 0){
if (square->brett[i/3][i%3] == j){
pos += h*(bases[i]); //increment position number
//reset counters
reg = reg | power;
h = 0;
j = 9;
}
else
h++; //increment to next usable number in sequence
}
}
}return pos;
}#endif
-
Kannst du das mal in cpp-Tags einrahmen, da blickt ja kein Schwein durch.
Ansonsten solltest du deine Zwischenpositionen in eine struct kapseln und dieser eine Vergleichfunktion (operator<) spendieren, danach kannst du sie in die priority_queue pushen.