最近突然间想怀旧一下热血传奇,于是去淘宝里买了个单机版的热血传奇。在祖玛阁中死了好几次,发现乱走是很消耗人品的事,网络上搜索出来的走法也是无效的,于是只能自己动手了。
打开MirServer\Mir200\Envir\MapInfo.txt文件,找到祖玛阁相关内容,才发现自己小看了这张图。一张图有12个小阁,横4阁,竖3阁;从祖玛六层到祖玛七层有10张祖玛阁的地图——即共120个小地图,手动找一条可行路径是找死的行为。
1.分析一下数据
1.1 截取祖玛阁部分数据:
太长了,放本文的最后。
1.2 使用EXCEL描绘这些坐标,可以得到以下散点图:
1.3 离散化一下数据:
1.3.1 根据数据得知:
一共有10张祖玛阁的地图;
每张地图有12个小阁,纵向3个,横向4个;
每个小阁有4个门,出入口相间±1的坐标值;
1.3.2 将数据离散化到每个小阁(到每个门也行),则共有120个点,每个点包含4个门
#define START_ID 5061
#define END_ID 5071
#define WIDTH 100
#define HEIGHT 100
#define VERTICAL_ROOM 3
#define HORIZONTAL_ROOM 4
#define X_UNIT (WIDTH/HORIZONTAL_ROOM)
#define Y_UNIT (HEIGHT/VERTICAL_ROOM)
#define DOOR_NUM 4
#define ROOM_NUM (VERTICAL_ROOM*HORIZONTAL_ROOM)
#define TOTAL_ROOM_NUM (120+1)
#define GET_INDEX(Id,x,y) ((Id-START_ID)*ROOM_NUM + x/X_UNIT*VERTICAL_ROOM + y/Y_UNIT)
#define START_INDEX 0
#define END_INDEX 120
struct NodePath {
int destRoom;
int x;
int y;
bool flag;
}mapNodePath[TOTAL_ROOM_NUM][DOOR_NUM];
1.4 从文件读取数据:
注意到有些行中有以‘;’符号开头,根据上下文分析,表示该行是无效数据。因此,读取方式如下:
if(freopen("mapInfo_sub.txt", "r", stdin) == NULL)
return 0;
int leftID, rightID;
int xL, yL;
int xR, yR;
memset(mapNodePath,0,sizeof(mapNodePath));
memset(map,-1,sizeof(map));
char ch,chL,chR;
while(scanf("%c",&ch) != EOF){
if(ch == ';' ){
scanf("%c%d %d %d -> %c%d %d %d ",&chL,&leftID,&xL,&yL,&chR,&rightID,&xR,&yR);
continue;
}
else
scanf("%d %d %d -> %c%d %d %d ",&leftID,&xL,&yL,&chR,&rightID,&xR,&yR);
int index = GET_INDEX(leftID,xL,yL);
for(int i = 0; i < DOOR_NUM; i++){
if(!mapNodePath[index][i].flag){
mapNodePath[index][i].x = xL;
mapNodePath[index][i].y = yL;
int destRoom = GET_INDEX(rightID,xR,yR);
mapNodePath[index][i].destRoom = destRoom;
mapNodePath[index][i].flag = true;
map[index][destRoom] = 1;
break;
}
}
}
fclose(stdin);
2.1 深度优先搜索
最朴素的想法就是一个个点的去尝试,撞到南墙了就返回来找下一条路。防止一直打转,就需要做些限制。到达某点时,检测一下是否有更短的路径到达该点,有的话就放弃目前路径对该点的搜索——每次到达X点时记下用了几步。
#include <stdio.h>
#include <string.h>
bool room[TOTAL_ROOM_NUM];
int path[TOTAL_ROOM_NUM];
int depthRoom[TOTAL_ROOM_NUM];
void DeepFindPath(int src, int dest, int depth){
depth++;
for(int i = 0; i < DOOR_NUM; i++){
if(mapNodePath[src][i].flag){
int destRoom = mapNodePath[src][i].destRoom;
if(depthRoom[destRoom] > depth ){
depthRoom[destRoom] = depth;
path[destRoom] = src;
if(destRoom == dest)
return ;
if(room[destRoom])
continue;
room[destRoom] = true;
DeepFindPath(destRoom, dest, depth);
room[destRoom] = false;
}
}
}
}
void DFS()
{
memset(depthRoom,0x7f,sizeof(depthRoom));
memset(room,false,sizeof(room));
memset(path,-1,sizeof(path));
room[START_INDEX] = true;
depthRoom[START_INDEX] = 0;
DeepFindPath(START_INDEX,END_INDEX,0);
}
2.2 dijkstra算法
将数据转化一下,用矩阵记录所有小阁的点。这样既可用dijkstra算法解决。网上随便找了个模板,直接套用:
int map[TOTAL_ROOM_NUM][TOTAL_ROOM_NUM];
void dijkstra(){
memset(room,false,sizeof(room));
memset(path,-1,sizeof(path));
int dist[TOTAL_ROOM_NUM];
memset(dist,-1,sizeof(dist));
dist[START_INDEX]=0;
while(1)
{
int v=-1;
for(int i=0; i!=TOTAL_ROOM_NUM; ++i)
if(!room[i]&&dist[i]>=0)
if(v<0||dist[i]<dist[v])
v=i;
if(v<0)break;
room[v]=true;
for(int i=0; i!=TOTAL_ROOM_NUM; ++