所有的遊戲地圖基本上都是由矩陣所構成,而矩陣中美一個元素可能代表著不同的意思,下圖試一個迷宮的矩陣,我們可以看到裡面有許多的數字:
其中4表示外牆、3表示內牆、1表示起點、2表示終點而0表示可以走的通道!
當然我們一般在玩遊戲時根本不知道原來地圖是長這樣的,因為這些數字對於玩家來說只會眼花撩亂而已,當電腦只要知道這些數字,再將這些數字利用不同的圖片或者符號印出時,就可以得到我們平常玩遊戲時的場景,比如說下面這張圖:
![]() |
| 點圖可放大 |
以下產生的迷宮都是固定迷宮至於如何產生亂數迷宮呢?
請看 資料結構-老鼠走迷宮
接下來我們看一些基本的範例應該可以更有印象,版本由淺入深,盡量每一個都跑過一次~後面的版本請建置專案,將標頭檔與cpp檔放在一起(或者是將標頭檔內容複製到cpp檔程式碼最上端)
以下程式碼請勿直接貼到編譯器中執行,因為會有編碼問題! 請先轉碼!
版本1
#include <stdio.h>
#include <stdlib.h>
#define SIZE 7
typedef struct {
int x;
int y;
} Point;
Point pt(int, int);
int visit(int[][SIZE], Point, Point);
void print(int[][SIZE]);
int main(void) {
//地圖 2為障礙物 0為可以走的地區,可自行調整地圖
int maze[SIZE][SIZE] = {{2, 2, 2, 2, 2, 2, 2},
{2, 0, 0, 0, 0, 0, 2},
{2, 0, 2, 0, 2, 0, 2},
{2, 0, 0, 2, 0, 2, 2},
{2, 2, 0, 2, 0, 2, 2},
{2, 0, 0, 0, 0, 0, 2},
{2, 2, 2, 2, 2, 2, 2}};
if(!visit(maze, pt(1, 1), pt(5, 5))) {
printf("\n沒有找到出口!\n");
}
print(maze);
return 0;
}
Point pt(int x, int y) {
Point p = {x, y};
return p;
}
/*開始拜訪迷宮*/
int visit(int maze[][SIZE], Point start, Point end) {
if(!maze[start.x][start.y]) {
maze[start.x][start.y] = 1;
if(!maze[end.x][end.y] &&
!(visit(maze, pt(start.x, start.y + 1), end) ||
visit(maze, pt(start.x + 1, start.y), end) ||
visit(maze, pt(start.x, start.y - 1), end) ||
visit(maze, pt(start.x - 1, start.y), end))) {
maze[start.x][start.y] = 0;
}
}
return maze[end.x][end.y];
}
/*印出地圖*/
void print(int maze[][SIZE]) {
int i, j;
for(i = 0; i < SIZE; i++) {
for(j = 0; j < SIZE; j++) switch(maze[i][j]) {
case 0 : printf(" "); break;
case 1 : printf("◇"); break;
case 2 : printf("█");
}
printf("\n");
}
}
版本2(貌似有點問題?! 請先用其它版本)
//用此類別來紀錄走訪過的路,含有堆疊的特性
#ifndef RECORD_H
#define RECORD_H
class RECORD_ROAD
{
private:
int row,col;
public:
void pop(int* r,int* c){*r = row; *c = col;}
void push(int r,int c){row = r;col = c;}
};
#endif
/*題目:老鼠走迷宮陣列版本 ,以該迷宮一定有路徑可以達到終點為前提
1.使用物件陣列來儲存走訪的路徑,記憶體使用上有些許浪費
2.走訪的方法,則是使用巢狀if else結構來完成
*/
#include <cstdlib>
#include <iostream>
#include "record.h"//RECORD_ROAD類別與實做的宣告
#include <windows.h>//COORD結構的宣告
using namespace std;
const int row_size = 14;//迷宮圖列
const int col_size = 17;//迷宮圖行
int top = 0;
void draw_map(bool map[row_size][col_size]);//畫出迷宮圖
void gotoxy(int x,int y);//設置列印座標
void print_path(RECORD_ROAD* record_road);//列印出路徑
int main(int argc, char *argv[])
{
//將迷宮的外層圍一層牆壁
bool map[row_size][col_size] = {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,0,0,1,1,0,0,0,1,1,1,1,1,1},
{1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,1,1},
{1,0,1,1,0,0,0,0,1,1,1,1,0,0,1,1,1},
{1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,0,1},
{1,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1},
{1,0,0,1,1,0,1,1,1,0,1,0,0,1,0,1,1},
{1,0,0,1,1,0,1,1,1,0,1,0,0,1,0,1,1},
{1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1},
{1,1,1,0,0,0,1,1,0,1,1,0,0,0,0,1,1},
{1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,0,1},
{1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
int row = 1,col = 1;//起點(1,1)
RECORD_ROAD record_road[100];//利用物件陣列來紀錄走過的座標
draw_map(map);//畫出迷宮圖案
record_road[top].push(row,col);//push (1,1)
map[row][col] = 1;//凡走過,則將該圖上的位置標示為 1
//當座標還沒有到達終點之前,繼續走訪
while((row != row_size-2)||(col != col_size-2))
{
if(map[row-1][col] == 0 )//正上方
{
row--;
}
else if(map[row-1][col+1]==0 )//右上方
{
row--; col++;
}
else if(map[row][col+1]==0 )//右方
{
col++;
}
else if(map[row+1][col+1]==0 )//右下方
{
row++; col++;
}
else if(map[row+1][col]==0)//下方
{
row++;
}
else if(map[row+1][col-1]==0 )//左下方
{
row++; col--;
}
else if(map[row][col-1]==0 )//左方
{
col--;
}
else if(map[row-1][col-1]==0 )//左上方
{
row--; col--;
}
else//當目前的座標位置沒有路可以前進時
{
top--;
//返回前一步的座標
record_road[top].pop(&row,&col);
//pop前一步的座標
continue;
//重新判斷是否有方向可以走訪
}
//如果有路可以走的話,則前進並且紀錄目前的座標
top++;
//前進
record_road[top].push(row,col);
//將目前的座標紀錄下來
map[row][col] = 1;
//凡走過,則將該圖上的位置標示為 1
}
print_path(record_road);
//將物件陣列的位址pass給function
system("PAUSE");
return EXIT_SUCCESS;
}
void draw_map(bool map[row_size][col_size])
{
int row,col;
for(row=0; row<row_size; row++)
{
for(col=0; col<col_size; col++)
{
if(row==0||row==13)cout<<"-";
else if(col==0||col==16)cout<<"|";
else
cout<< (map[row][col]== 1? "x":"o");
}
cout<<endl;
}
}
void gotoxy(int x,int y)//設置列印座標
{
COORD c;
c.X = x;
c.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
//設置終端機滑鼠指標位置
}
void print_path( RECORD_ROAD* record_road)
{
int row,col;
//列印出可以走到終點的路徑
for(int i=0; i<=top; i++)
{
record_road.pop(&row,&col);//將走訪過路徑pop出來
gotoxy(col,row);//col行,代表是x座標;row列,代表是y座標
cout<<static_cast<char>(1);
_sleep(200);//is included in stdlib.h參數為毫秒 200->0.2秒
}
}
版本3
//用此類別來紀錄走訪過的路,含有堆疊的特性
#ifndef RECORD_H
#define RECORD_H
class RECORD_ROAD
{
private:
int row,col;
public:
void pop(int* r,int* c){*r = row; *c = col;}
void push(int r,int c){row = r;col = c;}
RECORD_ROAD* forward,*next;//雙向鏈結
};
#endif
/*題目:老鼠走迷宮鏈結串列版,以該迷宮一定有路徑可以達到終點為前提
1.使用雙向鏈結串列來儲存走訪的路徑,可達到節省記憶體的效果
2.走訪的方法,則是使用巢狀if else結構來完成
*/
#include <cstdlib>
#include <iostream>
#include "record.h"//RECORD_ROAD類別與實做的宣告
#include <windows.h>//COORD結構的宣告
using namespace std;
const int row_size = 14;//迷宮圖列
const int col_size = 17;//迷宮圖行
void draw_map(bool map[row_size][col_size]);//畫出迷宮圖
void gotoxy(int x,int y);//設置列印座標
void print_path(RECORD_ROAD* first_point);//列印出路徑
int main(int argc, char *argv[])
{
//將迷宮的外層圍一層牆壁
bool map[row_size][col_size] = {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,0,0,1,1,0,0,0,1,1,1,1,1,1},
{1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,1,1},
{1,0,1,1,0,0,0,0,1,1,1,1,0,0,1,1,1},
{1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,0,1},
{1,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1},
{1,0,0,1,1,0,1,1,1,0,1,0,0,1,0,1,1},
{1,0,0,1,1,0,1,1,1,0,1,0,0,1,0,1,1},
{1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1},
{1,1,1,0,0,0,1,1,0,1,1,0,0,0,0,1,1},
{1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,0,1},
{1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
int row = 1,col = 1;//起點(1,1)
RECORD_ROAD *first_point,*this_point;
draw_map(map);//畫出迷宮圖案
this_point = first_point = new RECORD_ROAD;//建立第一個節點
this_point->push(row,col);//push (1,1)
map[row][col] = 1;//凡走過,則將該圖上的位置標示為 1
//當座標還沒有到達終點之前,繼續走訪
while((row != row_size-2)||(col != col_size-2))
{
if(map[row-1][col] == 0 )//正上方
{
row--;
}
else if(map[row-1][col+1]==0 )//右上方
{
row--; col++;
}
else if(map[row][col+1]==0 )//右方
{
col++;
}
else if(map[row+1][col+1]==0 )//右下方
{
row++; col++;
}
else if(map[row+1][col]==0)//下方
{
row++;
}
else if(map[row+1][col-1]==0 )//左下方
{
row++; col--;
}
else if(map[row][col-1]==0 )//左方
{
col--;
}
else if(map[row-1][col-1]==0 )//左上方
{
row--; col--;
}
else//當目前的座標位置沒有路可以前進時
{
this_point = this_point->forward;
//退回前一步
delete(this_point->next);
//釋放原位置記憶體
this_point->pop(&row,&col);
//pop出前一個位置的座標
continue;
//重新判斷是否有方向可以走訪
}
//如果有路可以走的話,則前進並且紀錄目前的座標
this_point->next = new RECORD_ROAD;
//動態配置一個新的節點並且指定給this_point->next這個指標
this_point->next->forward = this_point;
//將現在的位置指定給下一個節點中的forward指標
this_point = this_point->next;
//位置往前移一格
this_point->push(row,col);
//將目前座標紀錄下來
map[row][col] = 1;
//凡走過,則將該圖上的位置標示為 1
}
print_path(first_point);
//將首節點位址pass給function
system("PAUSE");
return EXIT_SUCCESS;
}
void draw_map(bool map[row_size][col_size])
{
int row,col;
for(row=0; row<row_size; row++)
{
for(col=0; col<col_size; col++)
{
if(row==0||row==13)cout<<"-";
else if(col==0||col==16)cout<<"|";
else
cout<< (map[row][col]== 1? "x":"o");
}
cout<<endl;
}
}
void gotoxy(int x,int y)//設置列印座標
{
COORD c;
c.X = x;
c.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
//設置終端機滑鼠指標位置
}
void print_path(RECORD_ROAD* first_point)//列印出路徑
{
int row,col;
RECORD_ROAD* this_point;
//列印出可以走到終點的路徑
this_point=first_point;
//從第一個節點開始
while(this_point!=NULL)
{ //當節點不存在時候就跳出
this_point->pop(&row,&col);//將走訪過路徑pop出來
gotoxy(col,row);//col行,代表是x座標;row列,代表是y座標
cout<<static_cast<char>(1);
_sleep(300);//is included in stdlib.h參數為毫秒 300->0.3秒
this_point = this_point->next;
//靠著next來移動節點
}
}
版本4
//用此類別來紀錄走訪過的路,含有堆疊的特性
#ifndef RECORD_H
#define RECORD_H
class RECORD_ROAD
{
private:
int row,col;
public:
void pop(int* r,int* c){*r = row; *c = col;}
void push(int r,int c){row = r;col = c;}
RECORD_ROAD* forward,*next;//雙向鏈結
};
#endif
#ifndef DIRECTION_H
#define DIRECTION_H
//利用列舉型態名稱來作為陣列的索引值,將索引值帶入則可以得到方向值
enum DIR{top, r_top, right, r_down, down, l_down, left, l_top};
short r_value[8] = {-1,-1,0,1,1, 1, 0,-1};
short c_value[8] = { 0, 1,1,1,0,-1,-1,-1};
#endif
/*題目:老鼠走迷宮鏈結串列版,以該迷宮一定有路徑可以達到終點為前提
1.使用雙向鏈結串列來儲存走訪的路徑,可達到節省記憶體的效果
2.使用enum來建立方向表,利用方向表來走訪(請見direction.h)
*/
#include <cstdlib>
#include <iostream>
#include "record.h"//RECORD_ROAD類別與實做的宣告
#include "direction.h"
#include <windows.h>//COORD結構的宣告
using namespace std;
const int row_size = 14;//迷宮圖列
const int col_size = 17;//迷宮圖行
void draw_map(bool map[row_size][col_size]);//畫出迷宮圖
void gotoxy(int x,int y);//設置列印座標
void print_path(RECORD_ROAD* first_point);//列印出路徑
int main(int argc, char *argv[])
{
//將迷宮的外層圍一層牆壁
bool map[row_size][col_size] = {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,0,0,1,1,0,0,0,1,1,1,1,1,1},
{1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,1,1},
{1,0,1,1,0,0,0,0,1,1,1,1,0,0,1,1,1},
{1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,0,1},
{1,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1},
{1,0,0,1,1,0,1,1,1,0,1,0,0,1,0,1,1},
{1,0,0,1,1,0,1,1,1,0,1,0,0,1,0,1,1},
{1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1},
{1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1},
{1,1,1,0,0,0,1,1,0,1,1,0,0,0,0,1,1},
{1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,0,1},
{1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
bool go_ahead;
int row = 1,col = 1;//起點(1,1)
RECORD_ROAD *first_point,*this_point;
draw_map(map);//畫出迷宮圖案
this_point = first_point = new RECORD_ROAD;//建立第一個節點
this_point->push(row,col);//push (1,1)
map[row][col] = 1;//凡走過,則將該圖上的位置標示為 1
//當座標還沒有到達終點之前,繼續走訪
while((row != row_size-2)||(col != col_size-2))
{
go_ahead = false;
// 判斷八個方向中是否有可以前進的路,由top開始,順時鐘找尋
for(int dir = top; dir<=l_top; dir++)
{
//有路可以前進的時候
if(map[row+r_value[dir]][col+c_value[dir]] == 0 )
{
row += r_value[dir];
col += c_value[dir];
go_ahead = true;
//標記可以前進,以便辨認要執行pop或是push
break;//找到可以前進的路,就跳出迴圈
}
}
//如果go_ahead沒有被標記為true代表目前的位置沒有路可以前進
//所以要執行pop動作
if(! go_ahead)
{
this_point = this_point->forward;
//退回前一步
delete(this_point->next);
//釋放原位置記憶體
this_point->pop(&row,&col);
//pop出前一個位置的座標
continue;
//重新判斷是否有方向可以走訪
}
//反之,代表有路可以走,則前進,執行push的動作
else
{
this_point->next = new RECORD_ROAD;
//動態配置一個新的節點並且指定給this_point->next這個指標
this_point->next->forward = this_point;
//將現在的位置指定給下一個節點中的forward指標
this_point = this_point->next;
//位置往前移一格
this_point->push(row,col);
//將目前座標紀錄下來
map[row][col] = 1;
//凡走過,則將該圖上的位置標示為 1
}
}
print_path(first_point);
//將首節點位址pass給function
system("PAUSE");
return EXIT_SUCCESS;
}
void draw_map(bool map[row_size][col_size])
{
int row,col;
for(row=0; row<row_size; row++)
{
for(col=0; col<col_size; col++)
{
if(row==0||row==13)cout<<"-";
else if(col==0||col==16)cout<<"|";
else
cout<< (map[row][col]== 1? "x":"o");
}
cout<<endl;
}
}
void gotoxy(int x,int y)//設置列印座標
{
COORD c;
c.X = x;
c.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
//設置終端機滑鼠指標位置
}
void print_path(RECORD_ROAD* first_point)//列印出路徑
{
int row,col;
RECORD_ROAD* this_point;
//列印出可以走到終點的路徑
this_point=first_point;
//從第一個節點開始
while(this_point!=NULL)
{ //當節點不存在時候就跳出
this_point->pop(&row,&col);//將走訪過路徑pop出來
gotoxy(col,row);//col行,代表是x座標;row列,代表是y座標
cout<<static_cast<char>(1);
_sleep(300);//is included in stdlib.h參數為毫秒 300->0.3秒
this_point = this_point->next;
//靠著next來移動節點
}
}
相關文章:
資料結構-老鼠走迷宮
老鼠走迷宮-easyx版本








沒有留言:
張貼留言
俗話說
凡走過必留下痕跡,凡住過必留下鄰居
凡爬過必留下樓梯,凡來過必留下IP
看過文章之後歡迎留下您寶貴的意見喔!