1.6 综合实战:最短路径规划实战
本项目基于CS:GO游戏地图,利用Dijkstra算法为玩家提供最短路径规划,考虑了地图中列车行驶时间,帮助玩家在游戏中更智慧地选择路径。通过集成计算机科学和游戏设计,项目旨在提升CS:GO玩家的战术决策和游戏体验,为他们提供更高效的导航方案。
1.6.1 项目介绍
随着电子竞技的兴起,Counter-Strike: Global Offensive(CS:GO)成为一款备受欢迎的多人射击游戏。在CS:GO的游戏模式中,特别是在“炸弹”模式中,玩家需要迅速而有效地找到并前往炸弹点(Bombsite)以完成任务。为了增添游戏的复杂性,游戏地图通常设计得非常庞大,其中包括了多种路径和地点。如图1-1所示。
图1-1 地图
本项目的背景源于对CS:GO游戏中玩家路径规划的探索,特别是在考虑了地图中列车的行驶时间后。在CS:GO的Train地图中,列车作为一种独特的地图元素,不仅为玩家提供了掩护,同时也增加了在地图上行进的挑战。为了提高游戏体验,项目采用了Dijkstra算法,这是一种用于寻找图中最短路径的经典算法,以确定玩家从起点到达炸弹点的最迅速路径。
通过该项目,玩家可以选择起始位置和目标炸弹点,系统将利用Dijkstra算法计算出最短路径,并考虑列车行驶时间,提供给玩家在游戏中更有效的导航方案。此项目不仅具有技术挑战,还对玩家的战术决策和游戏体验产生积极影响。
1.6.2 构建Graph
在开发这个项目之前,开首先创建了一个Graph表示Counter-Strike: Global Offensive(CS:GO)地图的数据结构。这个Graph是一个带有顶点和边的图,其中每个顶点代表地图上的一个位置,每条边表示两个位置之间的连接。Graph图的雏形如图1-2所示。
图1-2 Graph图的雏形
为了使Graph更加直观和标准,将图1-2继续油画城标准的Graph图,如图1-3所示。
图1-2 Graph标准图
本项目的开发过程始于地图的图形表示,然后演化到路径查找算法的实现,并最终形成用户界面和交互的完整程序。
1.6.3 具体实现
本项目的目的是通过 Dijkstra 算法找到在 CS:GO 地图上从一个起始点到达炸弹点的最短路径,并输出路径以及预计所需的时间。在主函数中,用户被要求选择起始点和目标炸弹点,然后调用 Dijkstra 函数来计算并输出最短路径和预计时间。
实例1-5:探索CS游戏玩家的最短路径(codes/1/cs/main-bahasa.cpp)
编写文件main-bahasa.cpp,使用Dijkstra算法在CS:GO地图中查找最短路径,帮助玩家确定从起点到炸弹点(Bombsite)的最短路径。通过输入起始点和目标炸弹点,程序输出最短路径以及估计的到达时间。代码使用邻接矩阵表示地图,优先队列选择最短距离的顶点,实现了路径和时间的计算与输出。
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
#define INF INT_MAX
using namespace std;
// 使用Dijkstra算法查找最短路径的函数
void dijkstra(vector<vector<int>>& graph, int start, int dest) {
int n = graph.size();
// 向量用于存储从起点到所有顶点的最短距离
vector<int> distance(n, INF);
// 向量用于存储从起点到每个顶点的最短路径
vector<vector<int>> paths(n);
// 优先队列用于选择具有最短距离的顶点
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
distance[start] = 0;
pq.push(make_pair(0, start));
while (!pq.empty()) {
int u = pq.top().second;
pq.pop();
for (int v = 0; v < n; v++) {
if (graph[u][v] != 0) {
int weight = graph[u][v];
if (distance[u] + weight < distance[v]) {
distance[v] = distance[u] + weight;
pq.push(make_pair(distance[v], v));
paths[v].clear();
paths[v].insert(paths[v].end(), paths[u].begin(), paths[u].end());
paths[v].push_back(u);
}
}
}
}
// 打印从起点到目标的最短路径
cout << "从顶点 " << char(start + 'A') << " 到炸弹点的最短路径是: ";
for (int i = 0; i < paths[dest].size(); i++) {
cout << char(paths[dest][i] + 'A') << " -> ";
}
cout << char(dest + 'A') << endl;
// 打印从起点到目标的最短距离
cout << "预计所需时间: " << distance[dest] << endl;
}
int main() {
vector<vector<int>> graph = {
{0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{2, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0},
{0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2},
{0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 2, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 2, 0},
{0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 3},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 3},
{0, 0, 0, 0, 0, 0, 7, 6, 5, 0, 0, 2, 2, 0, 0, 0},
{0, 0, 0, 4, 4, 0, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 4, 3, 3, 0, 0, 0}
};
int startVertex, bomVertex;
char start, bom;
cout << "===================================================================" << endl;
cout << "Program Penentuan Rute Terdekat Menuju Bombsite pada Permainan CSGO" << endl;
cout << "===================================================================" << endl;
cout << "Daftar Lokasi:" << endl;
cout << "Vertex A melambangkan T Spawn (tempat awal teroris)" << endl;
cout << "Vertex B melambangkan Big Blue" << endl;
cout << "Vertex C melambangkan T Long" << endl;
cout << "Vertex D melambangkan Break Room" << endl;
cout << "Vertex E melambangkan Ladder" << endl;
cout << "Vertex F melambangkan Lower Ramp" << endl;
cout << "Vertex G melambangkan A3 Train" << endl;
cout << "Vertex H melambangkan A2 Train" << endl;
cout << "Vertex I melambangkan A1 Train" << endl;
cout << "Vertex J melambangkan Boilers" << endl;
cout << "Vertex K melambangkan Connector" << endl;
cout << "Vertex L melambangkan Pink Train" << endl;
cout << "Vertex M melambangkan Cloud" << endl;
cout << "Vertex N melambangkan CT Spawn (tempat awal anti-teroris)" << endl;
cout << "Vertex O melambangkan Bombsite A" << endl;
cout << "Vertex P melambangkan Bombsite B" << endl;
cout << "Pilih Vertex Awal (Gunakan Kapital): ";
cin >> start;
startVertex = start - 'A';
cout << "Pemilihan Bombsite " << endl;
cout << "Jika Bombsite A Ketik O " << endl;
cout << "Jika Bombsite B Ketik P" << endl;
cout << "Pilih Bom (Gunakan Kapital): ";
cin >> bom;
bomVertex = bom - 'O' + 14;
dijkstra(graph, startVertex, bomVertex);
return 0;
}
上述代码的实现流程如下所示。
- 首先,定义了一个函数dijkstra,该函数使用Dijkstra算法来计算从起点到目标点的最短路径。Dijkstra算法使用优先队列和邻接矩阵表示地图,初始化距离向量和路径向量,将起点加入优先队列。
- 然后,Dijkstra算法进入主循环,每次从优先队列中弹出距离最短的顶点,并更新与该顶点相邻的顶点的距离和路径。这个过程重复直到队列为空,确保所有顶点的最短路径被计算。
- 接着,在主函数中创建了一个CS:GO地图的邻接矩阵,并通过用户输入选择起点和目标炸弹点。通过调用dijkstra函数,程序计算并输出了从起点到目标炸弹点的最短路径,以及估计的到达时间。
- 最后,展示了CS:GO地图中各个顶点的标识,帮助玩家轻松选择起点和目标炸弹点,以便获取最短路径信息。
执行后首先根据提示选择起点:根据地图上显示的顶点信息,输入起点的字母表示(使用大写字母),例如,输入'A'代表T Spawn。然后选择目标炸弹点,根据提示输入字母'O'代表Bombsite A或字母'P'代表Bombsite B。完整的测试过程如下:
===================================================================
Program Penentuan Rute Terdekat Menuju Bombsite pada Permainan CSGO
===================================================================
Daftar Lokasi:
Vertex A melambangkan T Spawn (tempat awal teroris)
Vertex B melambangkan Big Blue
Vertex C melambangkan T Long
Vertex D melambangkan Break Room
Vertex E melambangkan Ladder
Vertex F melambangkan Lower Ramp
Vertex G melambangkan A3 Train
Vertex H melambangkan A2 Train
Vertex I melambangkan A1 Train
Vertex J melambangkan Boilers
Vertex K melambangkan Connector
Vertex L melambangkan Pink Train
Vertex M melambangkan Cloud
Vertex N melambangkan CT Spawn (tempat awal anti-teroris)
Vertex O melambangkan Bombsite A
Vertex P melambangkan Bombsite B
Pilih Vertex Awal (Gunakan Kapital): A
Pemilihan Bombsite
Jika Bombsite A Ketik O
Jika Bombsite B Ketik P
Pilih Bom (Gunakan Kapital): O
从顶点 A 到炸弹点的最短路径是: A -> B -> D -> O
预计所需时间: 8
本Dijkstra篇已完结:
(1-1)Dijkstra算法:Dijkstra算法简介-CSDN博客
(1-2)Dijkstra算法:Dijkstra算法的核心思想-CSDN博客