Bootstrap

数据结构课设——“迷宫求解”

        设计“迷宫求解”小游戏,通过实践掌握用数组和队列综合解决实际问题的方法。程序开始运行时显示一个迷宫地图,迷宫中央有一只老鼠,迷宫的右下方有一个粮仓。游戏的任务是使用键盘上的方向键操纵老鼠在规定的时间内走到粮仓处。

任务要求:

  1. 老鼠形象可辨认,可用键盘操纵老鼠上下左右移动;
  2. 迷宫的墙足够结实,老鼠不能穿墙而过;
  3. 正确检测结果,若老鼠在规定时间内走到粮仓处,提示成功,否则提示失败;
  4. 添加编辑迷宫的功能,可修改当前迷宫,修改内容:墙变路,路变墙;
  5. 找出走出迷宫的所有路径,以及最短路径;
  6. 利用序列化功能实现迷宫地图文件的存盘和读出等功能。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <windows.h>

#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3

#define ROWS 10
#define COLS 10
#define MAX_PATHS 1000
#define MAX_PATH_LENGTH 100

#define TIME_LIMIT 60  // 规定时间,以秒为单位

typedef struct {
    int x, y;
} Position;

typedef struct {
    Position steps[MAX_PATH_LENGTH];
    int length;
} Path;

typedef struct {
    Path paths[MAX_PATHS];
    int count;
} PathCollection;

typedef struct {
    Path path;
    Position pos;
} QueueNode;

typedef struct {
    QueueNode nodes[MAX_PATHS];
    int front, rear;
} Queue;

int maze[ROWS][COLS];
Position mouse, cheese;
time_t startTime, currentTime;
PathCollection allPaths;
Path shortestPath;
Path playerPath;




// 初始化队列
void initQueue(Queue* q) {
    q->front = q->rear = 0;
}

// 判断队列是否为空
int isQueueEmpty(Queue* q) {
    return q->front == q->rear;
}

// 判断队列是否已满
int isQueueFull(Queue* q) {
    return (q->rear + 1) % MAX_PATHS == q->front;
}

// 入队
void enqueue(Queue* q, QueueNode n) {
    if (!isQueueFull(q)) {
        q->nodes[q->rear] = n;
        q->rear = (q->rear + 1) % MAX_PATHS;
    }
}

// 出队
QueueNode dequeue(Queue* q) {
    QueueNode n = { 0 };
    if (!isQueueEmpty(q)) {
        n = q->nodes[q->front];
        q->front = (q->front + 1) % MAX_PATHS;
    }
    return n;
}

// 初始化迷宫
void initMaze() {
    int initialMaze[ROWS][COLS] = {
        {1,1,1,1,1,1,1,1,1,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,0,1,0,1,1,1,1,0,1},
        {1,0,1,0,0,0,0,1,0,1},
        {1,0,1,0,1,0,0,0,0,1},
        {1,0,1,0,1,1,0,1,0,1},
        {1,0,1,0,1,0,0,1,0,1},
        {1,0,1,1,1,0,1,1,0,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,1,1,1,1,1,1,1,1,1}
    };
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            maze[i][j] = initialMaze[i][j];
        }
    }
    mouse.x = 1; mouse.y = 1; // 老鼠初始位置
    cheese.x = 6; cheese.y = 6; // 奶酪位置
}

// 显示迷宫
void displayMaze() {
    system("cls"); // 清屏
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            if (i == mouse.x && j == mouse.y) {
                printf("M ");
            }
            else if (i == cheese.x && j == cheese.y) {
                printf("C ");
            }
            else {
                printf(maze[i][j] == 1 ? "# " : ". ");
            }
        }
        printf("\n");
    }
}

// 老鼠移动
void moveMouse(int direction) {
    Position newMouse = mouse;
    switch (direction) {
    case UP: newMouse.x--; break;
    case DOWN: newMouse.x++; break;
    case LEFT: newMouse.y--; break;
    case RIGHT: newMouse.y++; break;
    }

    if (maze[newMouse.x][newMouse.y] == 0) {
        mouse = newMouse;
        playerPath.steps[playerPath.length++] = mouse;
    }
}

// 查找所有路径
void findAllPaths() {
    allPaths.count = 0;
    shortestPath.length = MAX_PATH_LENGTH;

    int visited[ROWS][COLS] = { 0 };
    Queue queue;
    initQueue(&queue);

    Path startPath = { {mouse}, 1 };
    QueueNode startNode = { startPath, mouse };
    enqueue(&queue, startNode);
    visited[mouse.x][mouse.y] = 1;

    int directions[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };

    while (!isQueueEmpty(&queue)) {
        QueueNode current = dequeue(&queue);
        if (current.pos.x == cheese.x && current.pos.y == cheese.y) {
            allPaths.paths[allPaths.count++] = current.path;
            if (shortestPath.length == 0 || current.path.length < shortestPath.length) {
                shortestPath = current.path;
            }
            continue;
        }

        for (int i = 0; i < 4; i++) {
            Position nextPos = {
                current.pos.x + directions[i][0],
                current.pos.y + directions[i][1]
            };

            if (maze[nextPos.x][nextPos.y] == 0 && !visited[nextPos.x][nextPos.y]) {
                Path nextPath = current.path;
                nextPath.steps[nextPath.length++] = nextPos;
                QueueNode nextNode = { nextPath, nextPos };
                enqueue(&queue, nextNode);
                visited[nextPos.x][nextPos.y] = 1;
            }
        }
    }
}

// 计算最短路径距离
int calculateShortestDistance(Position start, Position end) {
    int directions[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
    int visited[ROWS][COLS] = { 0 };
    Queue queue;
    initQueue(&queue);

    Path startPath = { {start}, 1 };
    QueueNode startNode = { startPath, start };
    enqueue(&queue, startNode);
    visited[start.x][start.y] = 1;

    while (!isQueueEmpty(&queue)) {
        QueueNode current = dequeue(&queue);
        if (current.pos.x == end.x && current.pos.y == end.y) {
            return current.path.length - 1;
        }

        for (int i = 0; i < 4; i++) {
            Position nextPos = {
                current.pos.x + directions[i][0],
                current.pos.y + directions[i][1]
            };

            if (maze[nextPos.x][nextPos.y] == 0 && !visited[nextPos.x][nextPos.y]) {
                Path nextPath = current.path;
                nextPath.steps[nextPath.length++] = nextPos;
                QueueNode nextNode = { nextPath, nextPos };
                enqueue(&queue, nextNode);
                visited[nextPos.x][nextPos.y] = 1;
            }
        }
    }
    return -1; // 无法到达终点
}

// 检查时间
int checkTime() {
    time(&currentTime);
    double elapsed = difftime(currentTime, startTime);
    return (elapsed > TIME_LIMIT) ? 1 : 0;
}

// 游戏结束检查
int isShortestPath(Path player, Path shortest) {
    if (player.length != shortest.length) return 0;
    for (int i = 0; i < player.length; i++) {
        if (player.steps[i].x != shortest.steps[i].x || player.steps[i].y != shortest.steps[i].y) {
            return 0;
        }
    }
    return 1;
}

void endGameCheck(Position currentPos) {
    if (currentPos.x == cheese.x && currentPos.y == cheese.y) {
        printf("恭喜!你找到了奶酪!\n");
        if (isShortestPath(playerPath, shortestPath)) {
            printf("你走了最短路径!\n");
        }
        else {
            printf("你没有走最短路径。\n");
            printf("最短路径长度:%d 步\n", shortestPath.length - 1);
            printf("最短路径详情:\n");
            for (int i = 1; i < shortestPath.length; i++) {
                printf("第 %d 步:从 (%d, %d) 到 (%d, %d)\n", i, shortestPath.steps[i - 1].x, shortestPath.steps[i - 1].y, shortestPath.steps[i].x, shortestPath.steps[i].y);
            }
        }
    }
    else {
        int startDistance = shortestPath.length - 1;  // 初始位置到奶酪的最短距离
        int currentDistance = calculateShortestDistance(currentPos, cheese);
        printf("游戏结束。\n");
        printf("初始到奶酪的距离:%d 步\n", startDistance);
        printf("当前到奶酪的距离:%d 步\n", currentDistance);
        if (currentDistance < startDistance) {
            printf("你靠近了奶酪!\n");
        }
        else {
            printf("你没有靠近奶酪。\n");
        }
        printf("最短路径长度:%d 步\n", shortestPath.length - 1);
        printf("最短路径详情:\n");
        for (int i = 1; i < shortestPath.length; i++) {
            printf("第 %d 步:从 (%d, %d) 到 (%d, %d)\n", i, shortestPath.steps[i - 1].x, shortestPath.steps[i - 1].y, shortestPath.steps[i].x, shortestPath.steps[i].y);
        }
    }
}

// 编辑迷宫
void editMaze() {
    char command;
    Position cursor = { 1, 1 }; // 光标初始位置
    while (1) {
        displayMaze();
        printf("编辑迷宫:使用 W, A, S, D 移动光标,按 E 切换墙壁和路径,按 Q 完成编辑\n");
        printf("当前光标位置:(%d, %d)\n", cursor.x, cursor.y);

        command = _getch();
        switch (command) {
        case 'W': if (cursor.x > 0) cursor.x--; break;
        case 'S': if (cursor.x < ROWS - 1) cursor.x++; break;
        case 'A': if (cursor.y > 0) cursor.y--; break;
        case 'D': if (cursor.y < COLS - 1) cursor.y++; break;
        case 'E':
            if (maze[cursor.x][cursor.y] == 1) {
                maze[cursor.x][cursor.y] = 0;
            }
            else {
                maze[cursor.x][cursor.y] = 1;
            }
            break;
        case 'Q': return; // 完成编辑
        }
    }
}

// 保存迷宫到文件
void saveMaze(const char* filename) {
    FILE* file = fopen(filename, "wb");
    if (file == NULL) {
        printf("无法打开文件进行保存。\n");
        return;
    }
    // 保存迷宫布局
    fwrite(maze, sizeof(int), ROWS * COLS, file);
    // 保存老鼠位置
    fwrite(&mouse, sizeof(Position), 1, file);
    // 保存奶酪位置
    fwrite(&cheese, sizeof(Position), 1, file);
    fclose(file);
    printf("迷宫已保存到文件 %s。\n", filename);
}

// 从文件读取迷宫
void loadMaze(const char* filename) {
    FILE* file = fopen(filename, "rb");
    if (file == NULL) {
        printf("无法打开文件进行读取。\n");
        return;
    }
    // 读取迷宫布局
    fread(maze, sizeof(int), ROWS * COLS, file);
    // 读取老鼠位置
    fread(&mouse, sizeof(Position), 1, file);
    // 读取奶酪位置
    fread(&cheese, sizeof(Position), 1, file);
    fclose(file);
    printf("迷宫已从文件 %s 读取。\n", filename);
}


// 主函数
int main() {
    char choice;
    printf("是否加载迷宫? (Y/N): ");
    choice = _getch();
    if (choice == 'Y' || choice == 'y') {
        loadMaze("maze.dat");
    }
    else {
        initMaze();
    }

    printf("是否编辑迷宫? (Y/N): ");
    choice = _getch();
    if (choice == 'Y' || choice == 'y') {
        editMaze();
        saveMaze("maze.dat");
    }

    time(&startTime);  // 记录游戏开始时间
    displayMaze();
    findAllPaths();  // 寻找所有路径和最短路径

    playerPath.length = 0;
    playerPath.steps[playerPath.length++] = mouse; // 初始位置

    char command;
    int gameEnd = 0;

    printf("使用 W, A, S, D 移动,按 Q 退出:\n");

    while (1) {
        if (_kbhit()) {
            command = _getch();
            switch (command) {
            case 'W': moveMouse(UP); break;
            case 'S': moveMouse(DOWN); break;
            case 'A': moveMouse(LEFT); break;
            case 'D': moveMouse(RIGHT); break;
            case 'Q': gameEnd = 1; break; // 退出游戏
            }
            displayMaze();
            if (mouse.x == cheese.x && mouse.y == cheese.y) {
                gameEnd = 1;  // 游戏结束
                endGameCheck(mouse);
                break;
            }
        }

        if (checkTime()) {
            gameEnd = 1;  // 游戏结束
            endGameCheck(mouse);
            break;
        }

        Sleep(100);  // 延迟以减少CPU使用率
    }

    if (!gameEnd) {
        endGameCheck(mouse);
    }

    return 0;
}
;