feat: 添加实时公交模拟

This commit is contained in:
2025-12-24 08:43:01 +08:00
parent dff46e6f21
commit 69db4c1c07
4 changed files with 729 additions and 64 deletions

View File

@@ -0,0 +1,87 @@
// include/bus.h
#ifndef BUS_H
#define BUS_H
#include <stdbool.h>
#include "route.h"
#include "station.h"
#define MAX_BUSES 50
// 巴士状态枚举
typedef enum
{
BUS_MOVING, // 行驶中
BUS_STOPPING, // 停靠中
BUS_IDLE // 空闲/未启动
} BusStatus;
// 巴士方向枚举
typedef enum
{
DIRECTION_FORWARD, // 正向(起点到终点)
DIRECTION_BACKWARD // 反向(终点到起点)
} BusDirection;
// 巴士结构体
typedef struct Bus
{
int id; // 巴士编号
int routeId; // 所属线路ID
BusStatus status; // 当前状态
BusDirection direction; // 行驶方向
int currentStationIndex; // 当前站点索引(在线路站点数组中的位置)
double progress; // 在两站之间的进度(0.0-1.0)
double speed; // 速度(km/h)
double stopTimeRemaining; // 剩余停靠时间(分钟)
double totalDistance; // 总行驶距离(km)
double totalTime; // 总运行时间(分钟)
} Bus;
// 巴士管理系统
typedef struct BusSystem
{
Bus buses[MAX_BUSES];
int busCount;
double systemTime; // 系统运行时间(分钟)
} BusSystem;
// 巴士系统初始化
BusSystem *createBusSystem();
void destroyBusSystem(BusSystem *system);
// 巴士管理
int addBus(BusSystem *system, int routeId, int startStationIndex,
BusDirection direction, double speed);
Bus *getBus(BusSystem *system, int busId);
void removeBus(BusSystem *system, int busId);
// 巴士模拟
void updateBusSystem(BusSystem *system, const BusRoute routes[], int routeCount,
const Station stations[], int stationCount, double deltaTime);
void updateSingleBus(Bus *bus, const BusRoute *route, const Station stations[],
int stationCount, double deltaTime);
// 显示功能
void displayBus(const Bus *bus, const BusRoute routes[], int routeCount,
const Station stations[], int stationCount);
void displayAllBuses(const BusSystem *system, const BusRoute routes[], int routeCount,
const Station stations[], int stationCount);
// 查询功能
void queryBusesOnRoute(const BusSystem *system, int routeId,
const BusRoute routes[], int routeCount,
const Station stations[], int stationCount);
void queryBusesAtStation(const BusSystem *system, int stationId,
const BusRoute routes[], int routeCount,
const Station stations[], int stationCount);
// 自动模拟
void runSimulation(BusSystem *system, const BusRoute routes[], int routeCount,
const Station stations[], int stationCount,
double duration, double timeStep);
#endif

View File

@@ -0,0 +1,57 @@
#!/bin/bash
# 项目初始化脚本
echo "=========================================="
echo " 巴士路线管理系统 - 初始化脚本"
echo "=========================================="
# 创建目录结构
echo "创建目录结构..."
mkdir -p include src data obj bin
# 创建 stations.csv
echo "创建 data/stations.csv..."
cat > data/stations.csv << 'EOF'
id,name,latitude,longitude,stopTime
0,火车站,39.9042,116.4074,60
1,市中心,39.9100,116.4100,45
2,大学城,39.9200,116.4200,45
3,科技园,39.9300,116.4300,45
4,商业街,39.9150,116.4250,60
5,体育馆,39.9250,116.4350,45
6,公园,39.9180,116.4180,30
7,机场,39.9400,116.4400,90
8,医院,39.9050,116.4150,50
9,图书馆,39.9280,116.4280,40
EOF
# 创建 routes.csv
echo "创建 data/routes.csv..."
cat > data/routes.csv << 'EOF'
id,routeName,stationCount
0,1号线,4
0,1,2,3
5.0,6.0,7.0
1,2号线,5
0,4,5,7,9
8.0,6.0,10.0,5.0
2,3号线,4
1,6,4,2
4.0,5.0,6.0
3,4号线,3
8,1,3
7.0,12.0
EOF
echo ""
echo "✓ 目录结构创建完成"
echo "✓ 数据文件创建完成"
echo ""
echo "现在可以运行以下命令:"
echo " make # 编译项目"
echo " make run # 运行程序"
echo ""
echo "数据文件位置:"
echo " - data/stations.csv (站点数据)"
echo " - data/routes.csv (线路数据)"
echo "=========================================="

View File

@@ -0,0 +1,338 @@
// src/bus.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "../include/bus.h"
// 创建巴士系统
BusSystem* createBusSystem() {
BusSystem* system = (BusSystem*)malloc(sizeof(BusSystem));
system->busCount = 0;
system->systemTime = 0.0;
for (int i = 0; i < MAX_BUSES; i++) {
system->buses[i].id = -1;
system->buses[i].status = BUS_IDLE;
}
return system;
}
// 销毁巴士系统
void destroyBusSystem(BusSystem* system) {
if (system) {
free(system);
}
}
// 添加巴士
int addBus(BusSystem* system, int routeId, int startStationIndex,
BusDirection direction, double speed) {
if (system->busCount >= MAX_BUSES) {
printf("错误: 巴士数量已达上限\n");
return -1;
}
int busId = system->busCount;
Bus* bus = &system->buses[busId];
bus->id = busId;
bus->routeId = routeId;
bus->status = BUS_STOPPING; // 初始在站点停靠
bus->direction = direction;
bus->currentStationIndex = startStationIndex;
bus->progress = 0.0;
bus->speed = speed;
bus->stopTimeRemaining = 0.0;
bus->totalDistance = 0.0;
bus->totalTime = 0.0;
system->busCount++;
printf("巴士 #%d 已添加到线路 %d\n", busId, routeId);
return busId;
}
// 获取巴士
Bus* getBus(BusSystem* system, int busId) {
if (busId >= 0 && busId < system->busCount) {
return &system->buses[busId];
}
return NULL;
}
// 移除巴士
void removeBus(BusSystem* system, int busId) {
if (busId >= 0 && busId < system->busCount) {
system->buses[busId].status = BUS_IDLE;
printf("巴士 #%d 已移除\n", busId);
}
}
// 计算两点之间的距离(简化版,使用欧氏距离)
double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
double dx = (lon2 - lon1) * 111.0; // 1度经度约111km
double dy = (lat2 - lat1) * 111.0; // 1度纬度约111km
return sqrt(dx * dx + dy * dy);
}
// 更新单个巴士状态
void updateSingleBus(Bus* bus, const BusRoute* route, const Station stations[],
int stationCount, double deltaTime) {
if (bus->status == BUS_IDLE) return;
// 如果正在停靠
if (bus->status == BUS_STOPPING) {
bus->stopTimeRemaining -= deltaTime;
if (bus->stopTimeRemaining <= 0) {
// 停靠结束,开始移动
bus->status = BUS_MOVING;
bus->stopTimeRemaining = 0.0;
// 检查是否到达终点
if (bus->direction == DIRECTION_FORWARD) {
if (bus->currentStationIndex >= route->stationCount - 1) {
// 到达终点,掉头
bus->direction = DIRECTION_BACKWARD;
}
} else {
if (bus->currentStationIndex <= 0) {
// 到达起点,掉头
bus->direction = DIRECTION_FORWARD;
}
}
}
return;
}
// 如果正在行驶
if (bus->status == BUS_MOVING) {
int fromIdx = bus->currentStationIndex;
int toIdx;
if (bus->direction == DIRECTION_FORWARD) {
toIdx = fromIdx + 1;
if (toIdx >= route->stationCount) {
bus->status = BUS_STOPPING;
return;
}
} else {
toIdx = fromIdx - 1;
if (toIdx < 0) {
bus->status = BUS_STOPPING;
return;
}
}
// 计算这一段的行驶时间
int segmentIdx = (bus->direction == DIRECTION_FORWARD) ? fromIdx : toIdx;
double segmentTime = route->segmentTimes[segmentIdx];
// 计算进度增量
double progressDelta = deltaTime / segmentTime;
bus->progress += progressDelta;
// 计算行驶距离
int fromStationId = route->stations[fromIdx];
int toStationId = route->stations[toIdx];
int fromStIdx = findStationById(stations, stationCount, fromStationId);
int toStIdx = findStationById(stations, stationCount, toStationId);
if (fromStIdx != -1 && toStIdx != -1) {
double distance = calculateDistance(
stations[fromStIdx].latitude, stations[fromStIdx].longitude,
stations[toStIdx].latitude, stations[toStIdx].longitude
);
bus->totalDistance += distance * progressDelta;
}
// 如果到达下一站
if (bus->progress >= 1.0) {
bus->progress = 0.0;
bus->currentStationIndex = toIdx;
bus->status = BUS_STOPPING;
// 设置停靠时间
int stationId = route->stations[toIdx];
int stIdx = findStationById(stations, stationCount, stationId);
if (stIdx != -1) {
bus->stopTimeRemaining = stations[stIdx].stopTime / 60.0;
}
}
bus->totalTime += deltaTime;
}
}
// 更新整个巴士系统
void updateBusSystem(BusSystem* system, const BusRoute routes[], int routeCount,
const Station stations[], int stationCount, double deltaTime) {
system->systemTime += deltaTime;
for (int i = 0; i < system->busCount; i++) {
Bus* bus = &system->buses[i];
if (bus->status != BUS_IDLE && bus->routeId >= 0 && bus->routeId < routeCount) {
updateSingleBus(bus, &routes[bus->routeId], stations, stationCount, deltaTime);
}
}
}
// 显示巴士状态
void displayBus(const Bus* bus, const BusRoute routes[], int routeCount,
const Station stations[], int stationCount) {
if (bus->status == BUS_IDLE) return;
printf("\n--- 巴士 #%d ---\n", bus->id);
if (bus->routeId >= 0 && bus->routeId < routeCount) {
printf("线路: %s\n", routes[bus->routeId].routeName);
}
printf("方向: %s\n", bus->direction == DIRECTION_FORWARD ? "正向" : "反向");
const char* statusStr;
switch (bus->status) {
case BUS_MOVING: statusStr = "行驶中"; break;
case BUS_STOPPING: statusStr = "停靠中"; break;
default: statusStr = "空闲"; break;
}
printf("状态: %s\n", statusStr);
if (bus->routeId >= 0 && bus->routeId < routeCount) {
int stationId = routes[bus->routeId].stations[bus->currentStationIndex];
int stIdx = findStationById(stations, stationCount, stationId);
if (stIdx != -1) {
printf("当前位置: %s", stations[stIdx].name);
if (bus->status == BUS_MOVING) {
int nextIdx;
if (bus->direction == DIRECTION_FORWARD) {
nextIdx = bus->currentStationIndex + 1;
} else {
nextIdx = bus->currentStationIndex - 1;
}
if (nextIdx >= 0 && nextIdx < routes[bus->routeId].stationCount) {
int nextStationId = routes[bus->routeId].stations[nextIdx];
int nextStIdx = findStationById(stations, stationCount, nextStationId);
if (nextStIdx != -1) {
printf(" -> %s (进度: %.1f%%)",
stations[nextStIdx].name, bus->progress * 100);
}
}
} else if (bus->status == BUS_STOPPING) {
printf(" (停靠中, 剩余 %.1f 秒)", bus->stopTimeRemaining * 60);
}
printf("\n");
}
}
printf("速度: %.1f km/h\n", bus->speed);
printf("总行驶距离: %.2f km\n", bus->totalDistance);
printf("总运行时间: %.1f 分钟\n", bus->totalTime);
}
// 显示所有巴士
void displayAllBuses(const BusSystem* system, const BusRoute routes[], int routeCount,
const Station stations[], int stationCount) {
printf("\n========== 巴士实时状态 ==========\n");
printf("系统时间: %.1f 分钟\n", system->systemTime);
printf("运行中巴士数: %d\n", system->busCount);
int activeBuses = 0;
for (int i = 0; i < system->busCount; i++) {
if (system->buses[i].status != BUS_IDLE) {
displayBus(&system->buses[i], routes, routeCount, stations, stationCount);
activeBuses++;
}
}
if (activeBuses == 0) {
printf("\n当前没有运行中的巴士\n");
}
printf("==================================\n");
}
// 查询指定线路上的巴士
void queryBusesOnRoute(const BusSystem* system, int routeId,
const BusRoute routes[], int routeCount,
const Station stations[], int stationCount) {
printf("\n========== 线路 %s 上的巴士 ==========\n", routes[routeId].routeName);
int found = 0;
for (int i = 0; i < system->busCount; i++) {
if (system->buses[i].routeId == routeId && system->buses[i].status != BUS_IDLE) {
displayBus(&system->buses[i], routes, routeCount, stations, stationCount);
found++;
}
}
if (found == 0) {
printf("该线路上没有巴士\n");
}
printf("==================================\n");
}
// 查询指定站点的巴士
void queryBusesAtStation(const BusSystem* system, int stationId,
const BusRoute routes[], int routeCount,
const Station stations[], int stationCount) {
int stIdx = findStationById(stations, stationCount, stationId);
if (stIdx == -1) return;
printf("\n========== %s 站的巴士 ==========\n", stations[stIdx].name);
int found = 0;
for (int i = 0; i < system->busCount; i++) {
Bus* bus = (Bus*)&system->buses[i];
if (bus->status == BUS_IDLE || bus->routeId < 0 || bus->routeId >= routeCount)
continue;
int currentStationId = routes[bus->routeId].stations[bus->currentStationIndex];
// 检查是否在该站点或即将到达
if (currentStationId == stationId && bus->status == BUS_STOPPING) {
displayBus(bus, routes, routeCount, stations, stationCount);
found++;
}
}
if (found == 0) {
printf("该站点当前没有巴士\n");
}
printf("==================================\n");
}
// 运行模拟
void runSimulation(BusSystem* system, const BusRoute routes[], int routeCount,
const Station stations[], int stationCount,
double duration, double timeStep) {
printf("\n========== 开始模拟 ==========\n");
printf("模拟时长: %.1f 分钟\n", duration);
printf("时间步长: %.1f 分钟\n", timeStep);
printf("==============================\n\n");
double elapsedTime = 0.0;
int updateCount = 0;
while (elapsedTime < duration) {
updateBusSystem(system, routes, routeCount, stations, stationCount, timeStep);
elapsedTime += timeStep;
updateCount++;
// 每5次更新显示一次状态
if (updateCount % 5 == 0) {
printf("\n[时间: %.1f 分钟]\n", system->systemTime);
displayAllBuses(system, routes, routeCount, stations, stationCount);
printf("\n按 Enter 继续...");
getchar();
}
}
printf("\n========== 模拟结束 ==========\n");
printf("总运行时间: %.1f 分钟\n", system->systemTime);
displayAllBuses(system, routes, routeCount, stations, stationCount);
}

View File

@@ -5,6 +5,7 @@
#include "../include/station.h"
#include "../include/route.h"
#include "../include/graph.h"
#include "../include/bus.h"
#define MAX_ROUTES 20
@@ -13,158 +14,340 @@ Station stations[MAX_STATIONS];
BusRoute routes[MAX_ROUTES];
int stationCount = 0;
int routeCount = 0;
Graph* graph = NULL;
Graph *graph = NULL;
BusSystem *busSystem = NULL;
// 函数声明
void printMenu();
void queryRoute();
void saveQueryResult(const char* filename, const char* startName, const char* endName,
PathNode* path, double totalTime);
void manageBuses();
void startSimulation();
void saveQueryResult(const char *filename, const char *startName, const char *endName,
PathNode *path, double totalTime);
// 打印菜单
void printMenu() {
void printMenu()
{
printf("\n╔════════════════════════════════╗\n");
printf("║ 巴士路线管理系统 ║\n");
printf("╠════════════════════════════════╣\n");
printf("║ 1. 查询最短路径 ║\n");
printf("║ 2. 显示所有站点 ║\n");
printf("║ 3. 显示所有线路 ║\n");
printf("║ 4. 退出系统\n");
printf("║ 4. 巴士管理\n");
printf("║ 5. 启动实时模拟 ║\n");
printf("║ 6. 退出系统 ║\n");
printf("╚════════════════════════════════╝\n");
printf("请选择功能 (1-4): ");
printf("请选择功能 (1-6): ");
}
// 查询路线
void queryRoute() {
// 巴士管理菜单
void manageBuses()
{
int choice;
while (1)
{
printf("\n╔════════════════════════════════╗\n");
printf("║ 巴士管理菜单 ║\n");
printf("╠════════════════════════════════╣\n");
printf("║ 1. 添加巴士 ║\n");
printf("║ 2. 查看所有巴士 ║\n");
printf("║ 3. 查询线路上的巴士 ║\n");
printf("║ 4. 查询站点的巴士 ║\n");
printf("║ 5. 手动更新一次(1分钟) ║\n");
printf("║ 6. 返回主菜单 ║\n");
printf("╚════════════════════════════════╝\n");
printf("请选择 (1-6): ");
if (scanf("%d", &choice) != 1)
{
while (getchar() != '\n')
;
printf("无效输入\n");
continue;
}
switch (choice)
{
case 1:
{
// 添加巴士
printf("\n可用线路:\n");
for (int i = 0; i < routeCount; i++)
{
printf(" %d. %s\n", i, routes[i].routeName);
}
int routeId, startIdx, direction;
double speed;
printf("选择线路ID: ");
scanf("%d", &routeId);
if (routeId < 0 || routeId >= routeCount)
{
printf("无效的线路ID\n");
break;
}
printf("选择起始站点索引 (0-%d): ", routes[routeId].stationCount - 1);
scanf("%d", &startIdx);
printf("选择方向 (0-正向, 1-反向): ");
scanf("%d", &direction);
printf("输入速度(km/h): ");
scanf("%lf", &speed);
addBus(busSystem, routeId, startIdx,
direction == 0 ? DIRECTION_FORWARD : DIRECTION_BACKWARD, speed);
break;
}
case 2:
{
// 查看所有巴士
displayAllBuses(busSystem, routes, routeCount, stations, stationCount);
break;
}
case 3:
{
// 查询线路上的巴士
int routeId;
printf("输入线路ID: ");
scanf("%d", &routeId);
if (routeId >= 0 && routeId < routeCount)
{
queryBusesOnRoute(busSystem, routeId, routes, routeCount,
stations, stationCount);
}
else
{
printf("无效的线路ID\n");
}
break;
}
case 4:
{
// 查询站点的巴士
char stationName[MAX_NAME];
printf("输入站点名称: ");
scanf("%s", stationName);
int stationId = findStationByName(stations, stationCount, stationName);
if (stationId != -1)
{
queryBusesAtStation(busSystem, stationId, routes, routeCount,
stations, stationCount);
}
else
{
printf("找不到站点 '%s'\n", stationName);
}
break;
}
case 5:
{
// 手动更新
printf("更新巴士位置(1分钟)...\n");
updateBusSystem(busSystem, routes, routeCount, stations, stationCount, 1.0);
displayAllBuses(busSystem, routes, routeCount, stations, stationCount);
break;
}
case 6:
return;
default:
printf("无效选择\n");
}
}
}
// 启动模拟
void startSimulation()
{
if (busSystem->busCount == 0)
{
printf("\n错误: 请先添加巴士\n");
return;
}
double duration;
printf("\n输入模拟时长(分钟): ");
scanf("%lf", &duration);
printf("开始自动模拟...\n");
printf("提示: 每5次更新会暂停显示状态\n");
// 清空输入缓冲
while (getchar() != '\n')
;
runSimulation(busSystem, routes, routeCount, stations, stationCount, duration, 1.0);
}
void queryRoute()
{
char startName[MAX_NAME], endName[MAX_NAME];
printf("\n请输入起点站名称: ");
scanf("%s", startName);
printf("请输入终点站名称: ");
scanf("%s", endName);
int startId = findStationByName(stations, stationCount, startName);
int endId = findStationByName(stations, stationCount, endName);
if (startId == -1) {
if (startId == -1)
{
printf("错误: 找不到站点 '%s'\n", startName);
return;
}
if (endId == -1) {
if (endId == -1)
{
printf("错误: 找不到站点 '%s'\n", endName);
return;
}
double totalTime;
PathNode* path = dijkstra(graph, startId, endId, &totalTime);
if (!path || totalTime < 0) {
PathNode *path = dijkstra(graph, startId, endId, &totalTime);
if (!path || totalTime < 0)
{
printf("\n没有找到从 %s 到 %s 的路线\n", startName, endName);
return;
}
printf("\n========== 最短路径查询结果 ==========\n");
printf("起点: %s\n", startName);
printf("终点: %s\n", endName);
printf("总时间: %.2f 分钟\n", totalTime);
printf("\n详细路线:\n");
displayPath(path, stations, stationCount, routes, routeCount);
printf("=====================================\n\n");
// 保存结果
saveQueryResult("data/query_results.txt", startName, endName, path, totalTime);
freePath(path);
}
// 保存查询结果
void saveQueryResult(const char* filename, const char* startName, const char* endName,
PathNode* path, double totalTime) {
FILE* fp = fopen(filename, "a");
if (!fp) {
void saveQueryResult(const char *filename, const char *startName, const char *endName,
PathNode *path, double totalTime)
{
FILE *fp = fopen(filename, "a");
if (!fp)
{
printf("警告: 无法保存查询结果到文件\n");
return;
}
fprintf(fp, "================================\n");
fprintf(fp, "起点: %s\n", startName);
fprintf(fp, "终点: %s\n", endName);
fprintf(fp, "总时间: %.2f 分钟\n", totalTime);
fprintf(fp, "路径: ");
PathNode* curr = path;
while (curr) {
PathNode *curr = path;
while (curr)
{
int stationIdx = findStationById(stations, stationCount, curr->stationId);
if (stationIdx != -1) {
if (stationIdx != -1)
{
fprintf(fp, "%s", stations[stationIdx].name);
if (curr->next) {
if (curr->next)
{
fprintf(fp, " -> ");
}
}
curr = curr->next;
}
fprintf(fp, "\n");
fclose(fp);
}
// 主函数
int main() {
int main()
{
printf("========================================\n");
printf(" 巴士路线管理系统 v1.0\n");
printf("========================================\n\n");
// 加载数据
printf("正在加载系统数据...\n");
stationCount = loadStations("data/stations.csv", stations, MAX_STATIONS);
if (stationCount == 0) {
if (stationCount == 0)
{
printf("错误: 无法加载站点数据\n");
return 1;
}
routeCount = loadRoutes("data/routes.csv", routes, MAX_ROUTES);
if (routeCount == 0) {
if (routeCount == 0)
{
printf("错误: 无法加载线路数据\n");
return 1;
}
// 创建图
graph = createGraph(stationCount);
buildGraphFromRoutes(graph, routes, routeCount, stations, stationCount);
// 创建巴士系统
busSystem = createBusSystem();
printf("巴士系统初始化完成\n");
printf("\n系统初始化完成!\n");
// 主循环
int choice;
while (1) {
while (1)
{
printMenu();
if (scanf("%d", &choice) != 1) {
while (getchar() != '\n');
printf("无效输入,请输入数字1-4\n");
if (scanf("%d", &choice) != 1)
{
while (getchar() != '\n')
;
printf("无效输入,请输入数字1-6\n");
continue;
}
switch (choice) {
case 1:
queryRoute();
break;
case 2:
displayAllStations(stations, stationCount);
break;
case 3:
displayAllRoutes(routes, routeCount, stations, stationCount);
break;
case 4:
printf("\n感谢使用巴士路线管理系统!\n");
destroyGraph(graph);
return 0;
default:
printf("无效选择,请输入1-4\n");
switch (choice)
{
case 1:
queryRoute();
break;
case 2:
displayAllStations(stations, stationCount);
break;
case 3:
displayAllRoutes(routes, routeCount, stations, stationCount);
break;
case 4:
manageBuses();
break;
case 5:
startSimulation();
break;
case 6:
printf("\n感谢使用巴士路线管理系统!\n");
destroyGraph(graph);
destroyBusSystem(busSystem);
return 0;
default:
printf("无效选择,请输入1-6\n");
}
}
return 0;
}