Поиск в лабиринте
Поиск в лабиринте
Курсовая работа по программированию "Поиск в лабиринте" Поиск в глубину: Алгоритм Реализация алгоритма поиска: Поиск в лабиринте реализован поиском в глубину (рекурсивно) Данная реализация представлена в программе классом tLabirint. Условно реализацию данного алгоритма можно разбить на несколько составляющих: Считывание матрицы лабиринта из файла Нахождение доступных (смежных) позиций в лабиринте (тех мест, куда можно ходить) для каждой позиции на каждой итерации поиска. Поиск с пошаговым выводом результатов. Считывание матрицы лабиринта из файла. Матрица лабиринта хранится в виде матрицы а размерностью 51Х51. 51Х51 на мой взгляд достаточно. Формат входного файла: 1 стока: размерность матрицы лабиринта 2 строка: координата Х начальной (стартовой) позиции 3 строка: координата Y начальной (стартовой) позиции 4 строка: координата Х конечной (финальной) позиции 5 строка: координата Y конечной (финальной) позиции Затем идет матрица лабиринта размерность n символов на n строк, где n -- число из первой строки файла, размерность матрицы Причем символ «1» означает доступность клетки символ «0» означает препятствие Пример входного файла: 5 1 1 5 4 11010 01110 11100 00111 10000 void tLabirint::ReadMatrix() { FILE *f; char ch; int i,j,n; //Открываем файл f = fopen("input.txt", "rt"); // Считываем размерность fread(&ch,sizeof(ch), 1, f); // Переводим в число n = atoi(&ch); // Считываем перевод строки fread(&ch, sizeof(ch), 1, f); // Читаем стартовую позицию Х fread(&ch,sizeof(ch), 1, f); start.x = atoi(&ch); // Считываем перевод строки fread(&ch, sizeof(ch), 1, f); //Читаем стартовую позицию У fread(&ch,sizeof(ch), 1, f); start.y = atoi(&ch); // Считываем перевод строки fread(&ch, sizeof(ch), 1, f); //Читаем финальную позицию Х fread(&ch,sizeof(ch), 1, f); finish.x = atoi(&ch); // Считываем перевод строки fread(&ch, sizeof(ch), 1, f); // Читаем финальную позицию У fread(&ch,sizeof(ch), 1, f); finish.y = atoi(&ch); // Считываем перевод строки fread(&ch, sizeof(ch), 1, f); count_a=n; memset(a, 0, sizeof(a)); // Считываем матрицу лабиринта for(i=1;i<=count_a;i++) { for(j=1;j<=count_a;j++) { fread(&ch, sizeof(ch), 1, f); a[i][j]=atoi(&ch); ch=0; } // Считываем перевод строки fread(&ch, sizeof(ch), 1, f); } fclose(f); /* for(i=1;i<=count_a;i++) { for(j=1;j<=count_a;j++) printf("%d", a[i][j]); printf("\n"); } */ } Нахождение свободных мест в лабиринте. Функция берет в качестве параметров текущие координаты i, j, соответственно X и Y. Ссылку на массив координат s int tLabirint::GetCommon(int i, int j, smezh &s) { tCoords check[5]; int k, count; count=0; // Вверх check[1].x=j; check[1].y=i-1; // В право check[2].x=j+1; check[2].y=i; // Вниз check[3].x=j; check[3].y=i+1; // Влево check[4].x=j-1; check[4].y=i; for(k=1;k<=4;k++) { // Если не достигнуты границы матрицы, if((check[k].x>0) && (check[k].y>0) && (check[k].x<=count_a) && (check[k].y<=count_a)) { // То проверяем на доступность if(a[check[k].y][check[k].x]==1) { // И если позиция с координатами X, Y доступна, то добавляем к эту позицию в массив s доступных позиций count++; s[count].x=check[k].x; s[count].y=check[k].y; } } } // Возвращаем число доступных позиций. return count; } Поиск в лабиринте. void tLabirint::Find() { GetCoords(); // Получить начальные и конечные координаты DFS();//произвести поиск if(flag==0) outtextxy(20, 440, "No way!"); //Если путь не найден else outtextxy(20, 440, "Found way!"); //Если найден путь } void tLabirint::DFS() { flag=0; // Изначально нет пути DFS_Visit(start.y, start.x); // начинаем поиск } void tLabirint::DFS_Visit(int y, int x) { int i; int cnt; smezh sm; // Искомая вершина достигнута? if(flag==1) { // Если да, то выход exit; } /**/ //Красим вешину в серый цвет, т.е. начали её обработку color[y][x]=1; delay(500); count_p++; path[count_p].x=x; path[count_p].y=y; setcolor(BLUE); //defaultmouseoff; gui->Circle(sx+x*edge-edge / 2, sy+y*edge-edge / 2, 3); //defaultmouseon; //printf("X-%d;Y-%d\n", x, y); //getchar(); if((finish.x==x) && (finish.y==y)) flag=1; /**/ // Получаем координаты лабиринта, куда можно идти cnt=GetCommon(y, x, sm); for(i=1;i<=cnt;i++) { // Если позиция в лабиринте белого цвета, т.е. ещё ни разу не подвергалась обработке и если не достигнута финальная позиция if(color[sm[i].y][sm[i].x]==0 && flag==0) // Просматриваем эти координаты DFS_Visit(sm[i].y, sm[i].x); } color[y][x]=2; // Красим позицию в черный цвет, т.е. все возможные варианты у данной позиции рассмотрены. } Графический вывод В программе реализована иерархия классов для работы в графическом режиме и вывода необходимого на экран. Базовый класс. У него имеются только координаты. class tMyObj { protected: int x0, y0; public: tMyObj(){}; ~tMyObj(){}; tMyObj(int _x, int _y){x0=_x;y0=_y;}; }; Класс линия Это производный класс, он имеет к тому же две пары координат( начальная и конечная точки). class tMyLine:public tMyObj { int x1, y1; public: tMyLine(){}; ~tMyLine(){}; tMyLine(int _x, int _y, int _x1, int _y1):tMyObj(_x, _y){x1=_x1;y1=_y1;}; void Show(){line(x0, y0, x1, y1);}; void Hide(){int o = getcolor();int b = getbkcolor();setcolor(b);Show();setcolor(o);} }; Класс окружность. Это производный от базового класса tMyObj класс. Он имеет кроме координат радуис. class tMyCircle:public tMyObj { int rad; public: tMyCircle(){}; ~tMyCircle(){}; tMyCircle(int _x, int _y, int _rad):tMyObj(_x, _y){rad=_rad;}; void Show(){circle(x0, y0, rad);} }; Класс прямоугольник. Это производный от базового класса tMyObj класс имеет две пары координат (Левую верхнюю и правую нижнюю точки) class tMyRect:public tMyObj { int x1, y1; public: tMyRect(){}; ~tMyRect(){}; tMyRect(int _x, int _y, int _x1, int _y1):tMyObj(_x, _y){x1=_x1;y1=_y1;}; void Show(){rectangle(x0, y0, x1, y1);}; void Hide(){int o = getcolor();int b = getbkcolor();setcolor(b);Show();setcolor(o);} }; Класс графических примитивов. Класс графических примитивов позволяет выводить графические объекты: линия, окружность, прямоугольник, на экран. Это достигается созданием объектов классов примитивов, т.е. объектов классов линия, окружность, прямоугольник. class tMyGUI { public: tMyGUI(); ~tMyGUI(); void Line(int x, int y, int x1, int y1); void Circle(int x, int y, int rad); void Rectangle(int x, int y, int x1, int y1); void Fill(int x, int y, int Color); }; void tMyGUI::Line(int x, int y, int x1, int y1) { tMyLine tl(x, y, x1, y1); tl.Show(); } void tMyGUI::Circle(int x, int y, int rad) { tMyCircle tc(x, y, rad); tc.Show(); } void tMyGUI::Rectangle(int x, int y, int x1, int y1) { tMyRect tr(x, y, x1, y1); tr.Show(); } void tMyGUI::Fill(int x, int y, int Color) { floodfill(x, y, Color); } tMyGUI::tMyGUI() { int gdriver = DETECT, gmode, errorcode; initgraph(&gdriver, &gmode, ""); errorcode = graphresult(); if (errorcode != grOk) /* an error occurred */ { printf("Graphics error: %s\n", grapherrormsg(errorcode)); printf("Press any key to halt:"); getch(); exit(1); /* return with error code */ } } tMyGUI::~tMyGUI() { closegraph(); } Дополнительные типы данных, используемые в программе Тип координат. Представляет собой структуру с двумя полями x и y. typedef struct _tCoords { int x; int y; } tCoords; Тип Смежность Объявлен как массив на 51 элемент типа tCoords typedef tCoords smezh[51]; Константы. Максимальная длина пути. const MAX_PATH=100; Исходный текст программы: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <graphics.h> #include <conio.h> #include <dos.h> typedef struct _tCoords { int x; int y; } tCoords; typedef tCoords smezh[51]; const MAX_PATH=100; class tMyObj { protected: int x0, y0; public: tMyObj(){}; ~tMyObj(){}; tMyObj(int _x, int _y){x0=_x;y0=_y;}; }; class tMyLine:public tMyObj { int x1, y1; public: tMyLine(){}; ~tMyLine(){}; tMyLine(int _x, int _y, int _x1, int _y1):tMyObj(_x, _y){x1=_x1;y1=_y1;}; void Show(){line(x0, y0, x1, y1);}; void Hide(){int o = getcolor();int b = getbkcolor();setcolor(b);Show();setcolor(o);} }; class tMyCircle:public tMyObj { int rad; public: tMyCircle(){}; ~tMyCircle(){}; tMyCircle(int _x, int _y, int _rad):tMyObj(_x, _y){rad=_rad;}; void Show(){circle(x0, y0, rad);} }; class tMyRect:public tMyObj { int x1, y1; public: tMyRect(){}; ~tMyRect(){}; tMyRect(int _x, int _y, int _x1, int _y1):tMyObj(_x, _y){x1=_x1;y1=_y1;}; void Show(){rectangle(x0, y0, x1, y1);}; void Hide(){int o = getcolor();int b = getbkcolor();setcolor(b);Show();setcolor(o);} }; class tMyGUI { public: tMyGUI(); ~tMyGUI(); void Line(int x, int y, int x1, int y1); void Circle(int x, int y, int rad); void Rectangle(int x, int y, int x1, int y1); void Fill(int x, int y, int Color); }; void tMyGUI::Line(int x, int y, int x1, int y1) { tMyLine tl(x, y, x1, y1); tl.Show(); } void tMyGUI::Circle(int x, int y, int rad) { tMyCircle tc(x, y, rad); tc.Show(); } void tMyGUI::Rectangle(int x, int y, int x1, int y1) { tMyRect tr(x, y, x1, y1); tr.Show(); } void tMyGUI::Fill(int x, int y, int Color) { floodfill(x, y, Color); } tMyGUI::tMyGUI() { int gdriver = DETECT, gmode, errorcode; initgraph(&gdriver, &gmode, ""); errorcode = graphresult(); if (errorcode != grOk) /* an error occurred */ { printf("Graphics error: %s\n", grapherrormsg(errorcode)); printf("Press any key to halt:"); getch(); exit(1); /* return with error code */ } } tMyGUI::~tMyGUI() { closegraph(); } class tLabirint { int a[51][51]; // Матрица лабиринта tCoords path[MAX_PATH+1]; // Путь int color[51][51]; // Массив цветов. Используется в поиске для помечивания позиций в лабиринте int count_a; // Размерность матрицы лабиринта int count_p; // Длинна пути. т.е. кол-во элементов в массиве path int flag; // Эта переменная показывает достигнута конечная позиция или нет tCoords start, finish; // Координаты позиций начальной и конечной int cx, cy; // Центр экрана int edge; // Размер ребра int sx, sy; // Начальные координаты для рисования лабиринта int fx, fy; // Конечные координаты для рисования лабиринта tMyGUI *gui; // Объект класса вывода графических примитивов public: tLabirint(); // конструктор ~tLabirint(); // Деструктор void ReadMatrix(); // Считать матрицу int GetCommon(int i, int j, smezh &s); // Найти доступную позицию в лабиринте void DFS_Visit(int y, int x); // Просмотреть позицию в лабиринте void DFS(); // Поиск в глубь void DrawLabirint(); // Нарисовать лабиринт void GetCoords(); // Считать координаты начальной и конечной позиции void Find(); // Искать путь }; tLabirint::tLabirint() { int i, j; flag=0; start.x=0; start.y=0; finish.x=0; finish.y=0; for(i=1;i<=count_a;i++) for(j=1;j<=count_a;j++) color[i][j]=0; for(i=1;i<=MAX_PATH;i++) { path[i].x=0; path[i].y=0; } count_p=0; gui = new tMyGUI(); } tLabirint::~tLabirint() { delete gui; } void tLabirint::ReadMatrix() { FILE *f; char ch; int i,j,n; f = fopen("input.txt", "rt"); fread(&ch,sizeof(ch), 1, f); n = atoi(&ch); fread(&ch, sizeof(ch), 1, f); //Chitat' startovuyu pozitciu:X fread(&ch,sizeof(ch), 1, f); start.x = atoi(&ch); fread(&ch, sizeof(ch), 1, f); //Chitat' startovuyu pozitciu:Y fread(&ch,sizeof(ch), 1, f); start.y = atoi(&ch); fread(&ch, sizeof(ch), 1, f); //Chitat' final'nuyu pozitciu:X fread(&ch,sizeof(ch), 1, f); finish.x = atoi(&ch); fread(&ch, sizeof(ch), 1, f); //Chitat' final'nuyu pozitciu:Y fread(&ch,sizeof(ch), 1, f); finish.y = atoi(&ch); fread(&ch, sizeof(ch), 1, f); count_a=n; memset(a, 0, sizeof(a)); for(i=1;i<=count_a;i++) { for(j=1;j<=count_a;j++) { fread(&ch, sizeof(ch), 1, f); a[i][j]=atoi(&ch); ch=0; } fread(&ch, sizeof(ch), 1, f); } fclose(f); /* for(i=1;i<=count_a;i++) { for(j=1;j<=count_a;j++) printf("%d", a[i][j]); printf("\n"); } */ } int tLabirint::GetCommon(int i, int j, smezh &s) { //struct tCoords check[5]; int k, count; count=0; check[1].x=j; check[1].y=i-1; check[2].x=j+1; check[2].y=i; check[3].x=j; check[3].y=i+1; check[4].x=j-1; check[4].y=i; for(k=1;k<=4;k++) { if((check[k].x>0) && (check[k].y>0) && (check[k].x<=count_a) && (check[k].y<=count_a)) { if(a[check[k].y][check[k].x]==1) { count++; s[count].x=check[k].x; s[count].y=check[k].y; } } } return count; } void tLabirint::DFS_Visit(int y, int x) { int i; int cnt; smezh sm; if(flag==1) { exit; } /**/ color[y][x]=1; delay(500); count_p++; path[count_p].x=x; path[count_p].y=y; setcolor(BLUE); //defaultmouseoff; gui->Circle(sx+x*edge-edge / 2, sy+y*edge-edge / 2, 3); //defaultmouseon; //printf("X-%d;Y-%d\n", x, y); //getchar(); if((finish.x==x) && (finish.y==y)) flag=1; /**/ cnt=GetCommon(y, x, sm); for(i=1;i<=cnt;i++) { if(color[sm[i].y][sm[i].x]==0 && flag==0) DFS_Visit(sm[i].y, sm[i].x); } color[y][x]=2; } void tLabirint::DFS() { flag=0; DFS_Visit(start.y, start.x); } void tLabirint::DrawLabirint() { int i, j; edge=15; cx=getmaxx() / 2; cy=getmaxy() / 2; sx=cx-((count_a / 2)*edge-(edge / 2)); sy=cy-((count_a / 2)*edge-(edge / 2)); fx=sx+count_a*edge; fy=sy+count_a*edge; setcolor(RED); gui->Rectangle(sx, sy, fx, fy); for(i=1;i<=count_a;i++) gui->Line(sx+i*edge, sy, sx+i*edge, fy); for(i=1;i<=count_a;i++) gui->Line(sx, sy+i*edge, fx, sy+i*edge); for(i=1;i<=count_a;i++) { for(j=1;j<=count_a;j++) { if(a[i][j]==1) gui->Fill(sx+(j*edge)-edge / 2, sy+(i*edge)-edge / 2, RED); } } } void tLabirint::GetCoords() { /* start.x=1; start.y=1; finish.x=5; finish.y=4; */ FILE *f; char ch; int i,j,n; f = fopen("input.txt", "rt"); fread(&ch,sizeof(ch), 1, f); n = atoi(&ch); fread(&ch, sizeof(ch), 1, f); //Chitat' startovuyu pozitciu:X fread(&ch,sizeof(ch), 1, f); start.x = atoi(&ch); fread(&ch, sizeof(ch), 1, f); //Chitat' startovuyu pozitciu:Y fread(&ch,sizeof(ch), 1, f); start.y = atoi(&ch); fread(&ch, sizeof(ch), 1, f); //Chitat' final'nuyu pozitciu:X fread(&ch,sizeof(ch), 1, f); finish.x = atoi(&ch); fread(&ch, sizeof(ch), 1, f); //Chitat' final'nuyu pozitciu:Y fread(&ch,sizeof(ch), 1, f); finish.y = atoi(&ch); fread(&ch, sizeof(ch), 1, f); } void tLabirint::Find() { GetCoords(); DFS(); if(flag==0) outtextxy(20, 440, "No way!"); else outtextxy(20, 440, "Found way!"); } void main() { tLabirint *lab; clrscr(); lab = new tLabirint(); lab->ReadMatrix(); lab->DrawLabirint(); lab->Find(); /**/ getch(); delete lab; }
|