⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 t1.c

📁 solve the 8-puzzle problem using A* algorithm. Definitely written by my self, also include BGI graph
💻 C
字号:
/*
Solution of the 8 puzzle.
*/

#include <stdio.h>
#include <string.h>
#include <iostream.h>
#include <math.h>
#include <stdlib.h>
#include <windows.h>
#include <stdio.h>

#include "graphics.h"
const int Height = 400;
const int Width  = 400;

#define DOWN 0
#define UP 1
#define LEFT 2
#define RIGHT 3
#define H2

struct element
{
  int state[9];
  char* str;
  int pathcost;
  int valid;
  int totalcost;
  element* next;
};

int heur(int state[]);
void prepend(element* newnode, element* oldnode, int operator1);
int goal(int* state);
int NotOnQueue(int state[]);
element* BestFromQueue();
void PrintState(int* state);
int apply (int* newstate, int* oldstate, int op);
element* newelement();
int op(char);
char to_char(int i);// convert to char to display
int to_int(int j);// convert to int to display at BGI windows

void swap (int &m, int &n);
void moveUp (int *state,int &count_state);
void moveDown (int *state,int &count_state);
void moveLeft (int *state,int &count_state);
void moveRight (int *state,int &count_state);

void update(int **board);// update to BGI windows

char rep[] = "dulr";
int notvalid1[4] = { 6, 0, 0, 2 };
int notvalid2[4] = { 7, 1, 3, 5 };
int notvalid3[4] = { 8, 2, 6, 8 };
int applyparam[4] = { +3, -3, -1, +1 };
int GoalState[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8}; //8 indicates no tile 
int maxdepth;
char choice;

element* top;

int main()
{
  int state[9];

  printf("\nThe Eight Puzzle Game!\n");
  printf("Have Fun!!\n");
  printf("\n************************************************\n"
         " Please Enter the initial state of the game \n"
         " The Number will be 1 to 8, use x for the blank space.\n"
         " Please start writing them from left to right for each row,\n" 
         " from the top row to the bottom row.\n"
         " For example, your string will look like this '1 3 4 8 x 5 7 2 6'.\n"
         " Do not forget the spaces in between the characters.\n"
         " **************************************************\n");

  int i = 0;
  while(i<9)
	{
	char chr;
	chr = fgetc(stdin);
	if (chr==32) continue;
	if (chr=='x') state[i] = 8;
	else if (chr >= '1' && chr <= '9') state[i] = chr- '1';
	else { printf("\n!!Invalid Input.\n "
	              "Please ensure you enter the correct number. Example of valid input...1 3 4 8 x 5 7 2 6.", chr); return 1; }
	i++;
	}

  fgetc(stdin); //flush out the end of line character

  PrintState(state);
  
  printf("\n Now Enter the Goal State in a similar way. (Typical. 1 2 3 8 x 4 7 6 5): \n");

  i = 0;
  while(i<9)
	{
	char chr;
	chr = fgetc(stdin);
	if (chr==32) continue;
	if (chr=='x') GoalState[i] = 8;
	else if (chr >= '1' && chr <= '9') GoalState[i] = chr-'1';
	else { printf("chr=%d. Invalid Input.\n"
	              "Please ensure you enter the correct number. Example of valid input...1 2 3 8 x 4 7 6 5.",(int) chr); return 1; }
	i++;
	}
  PrintState(GoalState);
  int count=0;
  while(1) {//while loop S
  printf("\nEnter an action:\n"); 
  printf("For swap move-up('u') move-down('d') move- right('r') move-left('l'):\n");
  printf("('q') exit to do A start algorithm.\n");
  getchar();
  scanf("%c", &choice);
  if ((choice == 'q')||(choice == 'Q' )) break;
  if ((choice == 'u')||(choice == 'U' )) { moveUp (state,count);}
  if ((choice == 'd')||(choice == 'D' )) { moveDown (state,count);}
  if ((choice == 'l')||(choice == 'L' )) { moveLeft (state,count);}
  if ((choice == 'r')||(choice == 'R' )) { moveRight (state,count);}
  printf("Count of State: %d",count);
  PrintState(state);
  }
       
  while(1) {//while loop A
  bool search_again;
  printf( "\nNow, starting the A algorithm, \n"
          "\nEnter the maximum depth you want to search, less than 25 is solved quickly: ");
  scanf("%d", &maxdepth);

  printf("\nWorking...");
//link list
  top = newelement();
  for(i=0; i<9; i++)
    top->state[i] = state[i];
  top->totalcost = heur(state);
  
  element* newnode = newelement();
  while (1)
    {// while loop B
      element* node = BestFromQueue();
      if (node == NULL) {
	printf("done!\n");
	printf("There is no solution to this of less than %d depth.\n", maxdepth);
	printf("Up to 35 will take more time, if there is no solution of that, the pattern is usually unsolvable.\n\n"); 
	search_again=true;
	break;
     }
      else if (goal(node->state)) {// if A
	char chr[15];
	search_again=false;
	printf("done. \nFound the solution of least number of steps (%d).", node->pathcost);
	printf("\nWant a graphical display of each step? (Y/N)?");
	scanf("%s", chr);
	if(chr[0] =='n' || chr[0]=='N') {
	  printf("\n (Move Blank u=up, d=down, l=left, r=right)\n");
	  printf(node->str);
	  printf("\n");
	  break;
	}
	
	int block2[9];
	for (i=0; i<node->pathcost; i++)
	  {
	    PrintState(state);
	    printf("\nPress any key at the WINBGI windows and see the solution.\n");
	    getch();
	    apply(block2, state, op(node->str[i]));
	    for(int j=0; j<=8; j++)
	      state[j] = block2[j];
	  }
	PrintState(state);
	
	printf("\nGraphical Display Complete.\nThe steps taken were: (Move blank u=up, d=down, l-left, r=right)\n");
	printf(node->str);
	printf("\n");
	break;
      }//end of if A

      if (node->totalcost > maxdepth) continue;

      for(i=0; i<=3; i++) {// for A
	if (apply(newnode->state, node->state, i) == -1)
	  continue;

	if (NotOnQueue(newnode->state)) {// if B
	  prepend(newnode, node, i);
	  newnode = newelement();
	  if (newnode==NULL) { printf ("ERROR!! insufficient memory!! Try decreasing depth!"); return 1; }
	     }//end of if B
      }//end of for A
	  }//end of while loop B
	if (!search_again) break;
	}//end of while loop A
	return 0;
}

int heur(int* state)
{
#ifdef H2
  int to_return = 0;

  for(int i=0; i<9; i++)
    {
    to_return += abs((i/3) - (state[i]/3));
    to_return += abs((i%3) - (state[i]%3));
    }
  return to_return;
  
#else
  int to_return = 0;

  for(int i=0; i<9; i++)
    {
      if (state[i] != i) to_return++;
    }
  return to_return;
  

#endif

}


void prepend(element* newnode, element* oldnode, int op)
{
  newnode->next = top;
  top = newnode;

  strcpy(newnode->str, oldnode->str);
  newnode->str[oldnode->pathcost] = rep[op];
  newnode->str[oldnode->pathcost+1] = 0;

  newnode->pathcost = oldnode->pathcost+1;
  newnode->totalcost = newnode->pathcost + heur(newnode->state);
  if (newnode->totalcost < oldnode->totalcost) newnode->totalcost = oldnode->totalcost;
}


int goal(int* state)
{
  int* g_block = GoalState;

  for(int i=0; i<9; i++)
    if ((*(state++))!=(*(g_block++)))
      return 0;

  return 1;
}

int NotOnQueue(int* state)
{
  int i,j;
  element* t = top;
  
  while (t!=NULL)
    {
      for(i=0; i<9; i++)
	if (t->state[i] != state[i]) break;
      if (i==9) return 0;
      
      t = t->next;
    }
  return 1;
}

element* BestFromQueue()
{
  element* t = top;
  int min_totalpathcost = 1000;
  int totalpathcost;
  element* to_return = NULL;

  while (t != NULL)
    {
	  if (t->valid==1 && t->totalcost < min_totalpathcost)
	{
	min_totalpathcost = t->totalcost;
	to_return = t;
	}
      t = t->next;
    }
  
  if (to_return != NULL) to_return->valid = 0;

  return to_return;
}


int apply (int* newstate, int* oldstate, int op)
{
  int j;
  int blank;

  for (j=0; j<9; j++)
	if (oldstate[j]==8) { blank=j; break; }

  if (blank==notvalid1[op] || blank==notvalid2[op] || blank==notvalid3[op])
    return -1;

  for (j=0; j<9; j++)  
    newstate[j] = oldstate[j];

  newstate[blank] = newstate[blank+applyparam[op]];
  newstate[blank+applyparam[op]] = 8;

  return 1;
}

element* newelement()
{
  element* t = new element;
  if (t==NULL) return NULL;
  t->valid = 1;
  t->str = new char[maxdepth+1];
  if (t->str ==NULL) return NULL;
  t->str[0] = 0;
  t->pathcost = t->totalcost = 0;
  t->next = NULL;
  return t;
}

void PrintState(int* state)
{  
  int **matrix = new int*[3];//initilize matrix
	matrix[0]=new int[3];
	matrix[1]=new int[3];
	matrix[2]=new int[3];
   int k=0;
	for(int i=0;i<3;i++){
		 for (int j=0;j<3;j++){
		     matrix[i][j]=to_int(state[k]);//convert the queue to matrix,ready to display at BGI
		     k++;
	   }
	 }
	 update(matrix);
return 0;
}

char to_char(int i)
{
  if (i>=0 &&i<=7) return i+'1';
  else if (i==8) return 'x';
  else { printf("ERROR in Program!"); return -1; }

}

int to_int(int j)
{
	if (j>=0 && j<=7) return j+1;
	else if (j==8) return 0;
	else {printf("ERROR in Program!");return -1;}
	}
	
int op(char i)
{
switch (i)
  {
  case 'd': return 0;
  case 'u': return 1;
  case 'l': return 2;
  case 'r': return 3;
  default: printf("ERROR!"); return -1;
  }
}

void swap (int &m, int &n){
	int temp = m;
	m=n;
	n=temp;
}

void moveUp (int *state, int &count_state){
	       for (int q=0;q<9;q++){
	          if(state[q]==8){//move down
			       if ((q!=0)&&(q!=1)&&(q!=2)){//not in 0,1,2
				       swap(state[q],state[q-3]);
				       count_state++;
                   break;
				 }
				    else printf("Always be in position %d, you can't move up.",q);
			  }
		  }//finished
	
}

void moveDown (int *state,int &count_state) {
	       for (int q=0;q<9;q++){
	          if(state[q]==8){//move down
			       if ((q!=6)&&(q!=7)&&(q!=8)){//not in 6,7,8
				       swap(state[q],state[q+3]);
				       count_state++;
                   break;
               }
               else printf("Always be in position %d, you can't move down.",q);
				 }
	}//finished
}

void moveLeft (int *state,int &count_state){
	       for (int q=0;q<9;q++){
	          if(state[q]==8){//move left
			       if ((q!=0)&&(q!=3)&&(q!=6)){//not in 0.3.6
				       swap(state[q],state[q-1]);
				       count_state++;
				       break;
				 }
				 else printf("Always be in position %d, you can't move left.",q);
			  }
		  }//finished
}

void moveRight (int *state,int &count_state){
	       for (int q=0;q<9;q++){
	          if(state[q]==8){//move right
			       if ((q!=2)&&(q!=5)&&(q!=8)){//not in 2,5,8
				       swap(state[q],state[q+1]);
				       count_state++;
                  break;
				 }
				 else printf("Always be in position %d, you can't move right.",q);
			  }
		  }//finished
}

void update(int **board) {
	//Daniel's flicker-free function to draw out an 8-puzzle board
	//Takes a 3x3 array as input, 0 indicates the empty space
	
	//Setting up the Graphics
	static bool setup=false;
	if(!setup) {
   	int GraphDriver=0,GraphMode=0;
   	initgraph(&GraphDriver,&GraphMode,"", Width, Height );
   	setup = true;
	}

	//Variables for the function
	int XIncrement = (Width-40)/3;
	int YIncrement = ((Height-6)-40)/3;
	int x=0;
	int y=0;
	char s[2];
	static bool visual;
	
	//Initalising the variables
	s[1]='\0';
	setactivepage(visual);
	setbkcolor(BLACK);
	cleardevice();
	setfillstyle (SOLID_FILL, WHITE); 
	settextstyle(GOTHIC_FONT, HORIZ_DIR, 6);
	settextjustify(CENTER_TEXT, CENTER_TEXT);
	
	//Display different coloured squares for different numbers
	y=10;
	for(int i=0; i<3; i++) {
		x=10;
		for(int n=0; n<3; n++) {
			if(board[i][n]!=0) {
				setcolor(board[i][n]);
				bar(x,y,x+XIncrement,y+YIncrement);
			}
      	x+=10;
      	x+=XIncrement;
		}
		y+=10;
		y+=YIncrement;
	}
	
	//Display the actual numbers
	y=8*Height/40;
	for(int i=0; i<3; i++) {
		x=Width/6;
		for(int n=0; n<3; n++) {
			setcolor(WHITE);
			setbkcolor(board[i][n]);
			if(board[i][n]!=0) {
         	s[0] = board[i][n]+'0';
         	outtextxy(x, y, s);
         	moveto(0,0);
      	}
      	x+=2*(Width/6);
      }
      y+=13*Height/40;
   }
   
   //Set the page to display
   setvisualpage(visual);
   visual=!visual;
   
	delay(1000);
}




⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -