程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 用棧實現的自動走迷宮

用棧實現的自動走迷宮

編輯:C++入門知識

[cpp
sqStack.h 
#include "selemtype.h" 
#define MaxSize 1000 
typedef struct 

    SElemType data[MaxSize]; 
    int top; 
}Stack; 
 
Status InitStack(Stack &S); 
Status DestroyStack(Stack &S); 
Status StackEmpty(Stack &S); 
Status Push(Stack &S,SElemType &e); 
Status Pop(Stack &S,SElemType &e); 
[cpp] view plaincopy
sqStack.cpp 
 
#include "sqstack.h" 
#include<iostream> 
using namespace std; 
Status InitStack(Stack &S) 
{    
    S.top = 0 ; 
    for( int i = 0 ; i < MaxSize ; i++ ) 
    { 
        S.data[i].di = 0 ; 
        S.data[i].ord = 0 ;  
        S.data[i].seat.c = 0; 
        S.data[i].seat.r = 0; 
    } 
    return true; 

Status DestroyStack(Stack &S) 

    S.top = 0 ; 
    return true; 

Status StackEmpty(Stack &S) 

    bool judger = false ; 
    if(S.top == 0) 
        judger = true; 
    return judger; 

Status Push(Stack &S,SElemType &e)  

    bool judger = false; 
    if(S.top < MaxSize) 
    { 
         
        S.data[S.top] = e ; 
        S.top++; 
        judger = true ; 
    } 
    return judger; 

Status Pop(Stack &S,SElemType &e) 
{    
    bool judger = false ; 
    if(S.top > 0) 
    { 
        S.top--; 
        e = S.data[S.top] ; 
        judger = true ;  
         
    } 
    return judger; 

[cpp] 
Mazepath.h 
 
#define N 15 
#define M 22 
//分割塊占總空間比例 
#define V 0.4 
typedef struct ElemType 

    int x,y; 
    char c; 
}ElemType; 
typedef struct MazeType 

    ElemType arr[N][M];  
}MazeType; 
 
Status Pass(MazeType &MyMaze, PosType CurPos); 
void FootPrint(MazeType &MyMaze, PosType CurPos); 
void MarkPrint(MazeType &MyMaze, PosType CurPos); 
PosType NextPos(PosType CurPos, int Dir); 
Status MazePath(MazeType &maze, PosType start, PosType end); 
[cpp] 
Mazepath.cpp 
 
/*------------------------------------------------
    走迷宮算法v1.0
N            迷宮行數
M            迷宮列數
V            分割塊占總空間比例
ElemType     迷宮元素類型
MazeType     迷宮類型
 
函數MazePath   走迷宮算法
函數Pass       判斷當前位置是否可通過
函數FootPrint  留下足跡
函數MarkPrint  留下不能再走的標記
函數NextPos    計算下一位置
-------------------------------------------------*/ 
#include "MazePath.h" 
Status MazePath(MazeType &maze, PosType start, PosType End) 

    // 算法3.3 
    // 若迷宮maze中從入口 start到出口 end的通道,則求得一條存放在棧中 
    // (從棧底到棧頂),並返回TRUE;否則返回FALSE    
    Stack stack;   //定義一個棧 
    InitStack(stack);  //初始化該棧 
    int count = 0 ;   //用來記錄通道塊的序號 
    PosType nextPos = start,curPos = start; 
    SElemType e,pe; 
    pe.di = 0; 
    int di = 0 ; 
    bool judger = true ; 
    bool uu = true; 
    while(true) 
    { 
         
        for(int i = 1 ; i <= 4 ; i++ ) 
        { 
                nextPos = NextPos(curPos,i); 
                if(Pass(maze,nextPos)) 
                { 
 
                    count++; 
                    e.seat = curPos ; 
                    e.ord = count; 
                    e.di = i ; 
                    FootPrint(maze,curPos); 
                    Push(stack, e); 
                    curPos = nextPos ; 
                    judger = true ; 
                    if(curPos.c==End.c&&curPos.r==End.r) 
                    { 
                        count++; 
                        e.seat = curPos ; 
                        e.ord = count; 
                        e.di = i ; 
                        FootPrint(maze,curPos); 
                        Push(stack, e); 
                        return true ; 
                    } 
                    break; 
                } 
            if(i == 4) 
            { 
                if(judger)  //走投無路時將最後一個通道塊壓入棧 
                { 
 
                    count++; 
                    e.seat = curPos ; 
                    e.ord = count; 
                    e.di = i ; 
                    FootPrint(maze,curPos); 
                    Push(stack, e);  
                    judger = false; 
                    if(curPos.c==End.c&&curPos.r==End.r) 
                        return true ; 
                } 
                Pop(stack , pe);   //出棧 
                curPos = pe.seat ; 
                MarkPrint(maze , pe.seat);    //標記為走過且不可走 
                if(stack.top == 0) 
                    return false; 
                break; 
            } 
             
        } 
    } 
 
 
}  //MazePath 
 
Status Pass( MazeType &MyMaze,PosType CurPos)  

    if (MyMaze.arr[CurPos.r][CurPos.c].c==' ') 
        return 1;     // 如果當前位置是可以通過,返回1 
    else return 0;  // 其它情況返回0 

 
void FootPrint(MazeType &MyMaze,PosType CurPos)  

    //循環是判斷全局線程互斥變量的值,等待走步, 
    //值為false,迷宮走步,並重新設為true,交給 
    //主線程繪制,子線程等待 
    while(drawflag) 
        ; 
    drawflag=true; 
    MyMaze.arr[CurPos.r][CurPos.c].c='*'; 
     

 
void MarkPrint(MazeType &MyMaze,PosType CurPos)  

    //循環是判斷全局線程互斥變量的值,等待走步, 
    //值為false,迷宮走步,並重新設為true,交給 
    //主線程繪制,子線程等待 
    while(drawflag) 
        ; 
    drawflag=true; 
    MyMaze.arr[CurPos.r][CurPos.c].c='!'; 

 
PosType NextPos(PosType CurPos, int Dir)  

    PosType ReturnPos;  
    switch (Dir)  
    { 
    case 1: 
        ReturnPos.r=CurPos.r; 
        ReturnPos.c=CurPos.c+1; 
        break; 
    case 2: 
        ReturnPos.r=CurPos.r+1; 
        ReturnPos.c=CurPos.c; 
        break; 
    case 3: 
        ReturnPos.r=CurPos.r; 
        ReturnPos.c=CurPos.c-1; 
        break; 
    case 4: 
        ReturnPos.r=CurPos.r-1; 
        ReturnPos.c=CurPos.c; 
        break; 
    } 
    return ReturnPos; 

[cpp] view plaincopy
selemtype.h 
 
#pragma once 
#define Status bool 
#define TRUE true 
#define FALSE false 
struct PosType  

    int r,c;             //行列 or xy 
}; 
 
typedef struct 

    int ord;            //通道塊在路徑上的序號 
    PosType seat;       //通道塊在迷宮中的坐標位置 
    int di;             //從此通道塊走向下一通道塊的方向 
}SElemType; 
extern bool drawflag;   //全局變量外部聲明 
[cpp] 
main.cpp 
 
#include <iostream> 
using namespace std; 
#include "graphics.h" 
#include <time.h> 
#include "mazepath.h" 
/*------------------------------------------------
    走迷宮游戲v1.0
屏幕大小:   640*480
Width        每個小方塊寬度
Space        每個小方塊間隔
Step         每塊占據象素
 
drawflag     線程互斥全局變量,為true畫圖,
             為false走迷宮
threadflag   判斷線程是否結束的全局變量,為false
             線程結束,程序結束
maze;        迷宮全局對象
start,end    迷宮起終點全局變量
 
 
函數InitMaze        初始化迷宮
函數RandmMaze       隨機生成迷宮
函數DrawMaze        繪制迷宮
函數ThreadMazePath  子線程函數,調用走迷宮函數修
                    改迷宮對象數據
    算法設計思想
數據結構:     迷宮每個元素由位置坐標x,y和是否可走
               的狀態c構成,x、y代表畫塊的左上角坐
               標,c為#是障礙,為空格是空位,為!
               是已走過且不能再走,為*是走過且還有
               選擇;
基本操作:     棧的初始化、銷毀、入棧、出棧等;
繪制迷宮操作: 在主線程中繪制,根據元素值c選擇不同
               顏色繪制,根據元素值x、y,確定繪制
               位置;
走迷宮操作:   在子線程中計算迷宮對象走動的每一步,
               修改迷宮對象的值,但不繪制迷宮,通
               過修改互斥變量drawflag的值,在兩個
               線程中交替進行繪制和走步。                
-------------------------------------------------*/ 
#define Width 24 
#define Space 2 
#define Step  (Width + Space) 
 
bool drawflag=true; 
MazeType maze; 
PosType start,End; 
bool threadflag=true; 
 
void InitMaze(MazeType &maze) 

    //初始化迷宮,將二維數組的每個元素計算出屏幕坐標 
    int i,j; 
    for(i=0;i<N;i++) 
        for(j=0;j<M;j++) 
        { 
            maze.arr[i][j].x=30+j*Step; 
            maze.arr[i][j].y=30+i*Step; 
        } 

void RandmMaze(MazeType &maze,PosType start,PosType end) 

    //隨機生成迷宮,在二維數組內除起終點外其余位置隨 
    //機生成障礙,障礙數量按比例V計算 
    int i,j,k,num; 
    //邊界和空位初始化 
    for(i=0;i<N;i++) 
    { 
        maze.arr[i][0].c='#'; 
        maze.arr[i][M-1].c='#';      
 
        if(i!=0&&i!=N-1) 
        { 
            for(j=1;j<M-1;j++) 
            { 
                maze.arr[i][j].c=' '; 
            } 
        } 
    } 
    for(i=1;i<M-1;i++) 
    { 
        maze.arr[0][i].c='#'; 
        maze.arr[N-1][i].c='#'; 
    } 
 
    //按分割塊占總空間比例隨機生成迷宮 
    num=(N-2)*(M-2)*V;   //計算需要的分割塊數量 
 
    maze.arr[start.r][start.c].c='#'; //為了隨機生成分割塊不占用起始和終止位置 
    maze.arr[end.r][end.c].c='#'; 
 
    k=num;  
    while(k>1) 
    { 
        i=rand()%(N-2)+1;j=rand()%(M-2)+1; 
        if(maze.arr[i][j].c==' ') 
            maze.arr[i][j].c='#'; 
        k--; 
    } 
    maze.arr[start.r][start.c].c=' '; 
    maze.arr[end.r][end.c].c=' ';    
 

void DrawMaze(MazeType &maze) 

    //繪制迷宮,按不同狀態繪制不同顏色方塊 
    int i,j; 
         
    for(i=0;i<N;i++) 
    { 
        for(j=0;j<M;j++) 
        { 
            switch(maze.arr[i][j].c) 
            { 
            case '#':   //障礙塊 
                setfillstyle(SOLID_FILL,LIGHTBLUE); 
                break; 
            case '!':   //已走過且無路可走的塊 
                setfillstyle(SOLID_FILL,LIGHTRED); 
                break; 
            case '*':   //走過的塊 
                setfillstyle(SOLID_FILL,LIGHTGREEN); 
                break; 
            case ' ':   //空閒塊 
                setfillstyle(SOLID_FILL,BLACK); 
                break; 
            } 
            bar(maze.arr[i][j].x,maze.arr[i][j].y,maze.arr[i][j].x+Width,maze.arr[i][j].y+Width); 
        } 
        //cout<<endl; 
    } 
 

 
DWORD WINAPI ThreadMazePath(LPVOID plParameter) 

    //子線程函數,調用走迷宮函數修改迷宮對象數據 
    //迷宮無解再生成新迷宮,直到有解 
    int k=1; 
    srand(time(0)); 
    RandmMaze(maze,start,End); //隨機生成迷宮 
 
    while(!MazePath(maze,start,End)) 
    {        
        cout<<"第"<<k<<"個迷宮無解!"<<endl; 
         
        getchar(); 
        InitMaze(maze); 
        RandmMaze(maze,start,End);k++;       
    } 
    cout<<"第"<<k<<"個迷宮有解!"<<endl; 
     
    setfillstyle(SOLID_FILL,BLACK); 
    bar(100,450,500,480); 
    setcolor(YELLOW); 
    SetFont(16,16,0,0,0,FALSE,FALSE,FALSE,"宋體"); //文字設為宋體 
    outtextxy(100,450,"此迷宮有通路!"); 
 
    threadflag=false;  //線程結束標記 
    return 0; 

void main() 

    //初始化圖形界面 
    initgraph(640,480); 
    //清屏 
    cleardevice(); 
 
    //默認全局變量為true 
    drawflag=true;    
    threadflag=true; 
 
     
    InitMaze(maze);     //初始化迷宮對象 
     
    start.r=start.c=1;  //初始化起終點 
    End.r=N-2;End.c=M-2; 
 
    //創建走迷宮數據計算子線程 
    HANDLE hThread1=CreateThread(NULL, 
        0,ThreadMazePath,NULL,0,NULL); 
 
    while(threadflag)   //子線程未結束 
    { 
        Sleep(100); 
        if(drawflag)     //線程互斥變量為真,畫圖,否則等待迷宮走完一步 
        { 
            DrawMaze(maze);  
            drawflag=false;  //畫完一步,置為假,迷宮數據計算子線程走下一步 
        } 
    } 
 
    //結束前任意鍵暫停 
    getchar(); 
    //關閉圖形界面 
    closegraph(); 
 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved