自学内容网 自学内容网

扫雷游戏大家都不陌生,如果问你想不想自己动手做一个扫雷游戏,你会不会来看看呢!!!

在线扫雷游戏:http://www.minesweeper.cn/

首先,让我们详细分析和设计这个扫雷游戏的代码。

我将从游戏的整体设计、各个函数的作用、以及代码的具体实现来展开。

游戏设计

1. 游戏规则

扫雷游戏的基本规则如下:

  • 游戏棋盘是一个二维数组,每个格子可能是雷或空格。
  • 玩家通过输入坐标来翻开格子。
  • 如果翻开的格子是雷,则游戏结束。
  • 如果翻开的格子是空格,则显示该格子周围雷的数量。
  • 玩家需要翻开所有非雷格子才能赢得游戏。
2. 数据结构
  • 棋盘:使用两个二维数组来表示棋盘。
    • mine[ROWS][COLS]:存放真实的雷分布情况,'1' 表示有雷,'0' 表示无雷。
    • show[ROWS][COLS]:存放玩家看到的棋盘状态,'*' 表示未翻开,数字表示周围雷的数量。
3. 功能模块
  • 初始化棋盘:将棋盘初始化为默认状态。
  • 打印棋盘:显示当前棋盘的状态。
  • 布置雷:随机生成雷的位置。
  • 排查雷:处理玩家的输入,判断翻开的格子,并更新棋盘状态。
  • 获取周围雷的数量:计算某个格子周围雷的数量。

代码实现

1. game.h 文件

定义了常量和函数声明。

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define EASY_COUNT 10
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2

// 初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
// 打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
// 布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
// 排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
// 获取周围雷的数量
int GetMineCount(char mine[ROWS][COLS], int x, int y);
2. game.c 文件

实现了各个功能函数。

#include "game.h"

// 初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            board[i][j] = set;
        }
    }
}

// 打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col) {
    printf("--------扫雷游戏-------\n");
    printf("  ");
    for (int i = 1; i <= col; i++) {
        printf("%d ", i);
    }
    printf("\n");
    for (int i = 1; i <= row; i++) {
        printf("%d ", i);
        for (int j = 1; j <= col; j++) {
            printf("%c ", board[i][j]);
        }
        printf("\n");
    }
}

// 布置雷
void SetMine(char board[ROWS][COLS], int row, int col) {
    srand((unsigned int)time(NULL));
    int count = EASY_COUNT;
    while (count) {
        int x = rand() % row + 1;
        int y = rand() % col + 1;
        if (board[x][y] == '0') {
            board[x][y] = '1';
            count--;
        }
    }
}

// 获取周围雷的数量
int GetMineCount(char mine[ROWS][COLS], int x, int y) {
    return (mine[x-1][y-1] + mine[x-1][y] + mine[x-1][y+1] +
            mine[x][y-1] + mine[x][y+1] +
            mine[x+1][y-1] + mine[x+1][y] + mine[x+1][y+1] - 8 * '0');
}

// 排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {
    int x = 0;
    int y = 0;
    int win = 0;
    while (win < row * col - EASY_COUNT) {
        printf("请输入要排查的坐标:>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 1 && y <= col) {
            if (mine[x][y] == '1') {
                printf("很遗憾,你被炸死了\n");
                DisplayBoard(mine, ROW, COL);
                return;
            } else {
                int count = GetMineCount(mine, x, y);
                show[x][y] = count + '0';
                DisplayBoard(show, ROW, COL);
                win++;
            }
        } else {
            printf("坐标非法,重新输入\n");
        }
    }
    printf("恭喜你,排雷成功\n");
    DisplayBoard(mine, ROW, COL);
}
3. test.c 文件

包含主函数和游戏菜单。

#include "game.h"

// 显示菜单
void menu() {
    printf("***********************\n");
    printf("***** 1. play *****\n");
    printf("***** 0. exit *****\n");
    printf("***********************\n");
}

// 游戏主逻辑
void game() {
    char mine[ROWS][COLS]; // 存放布置好的雷
    char show[ROWS][COLS]; // 存放排查出的雷的信息
    // 初始化棋盘
    InitBoard(mine, ROWS, COLS, '0');
    InitBoard(show, ROWS, COLS, '*');
    // 打印棋盘
    DisplayBoard(show, ROW, COL);
    // 布置雷
    SetMine(mine, ROW, COL);
    // 排查雷
    FindMine(mine, show, ROW, COL);
}

int main() {
    int input = 0;
    srand((unsigned int)time(NULL));
    do {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input) {
            case 1:
                game();
                break;
            case 0:
                printf("退出游戏\n");
                break;
            default:
                printf("选择错误,重新选择\n");
                break;
        }
    } while (input != 0);
    return 0;
}

详细分析

初始化棋盘
  • InitBoard 函数将棋盘初始化为指定的字符。
  • mine 数组初始化为 '0',表示没有雷。
  • show 数组初始化为 '*',表示未翻开的格子。
打印棋盘
  • DisplayBoard 函数打印当前棋盘的状态。
  • 首先打印列编号,然后逐行打印行编号和格子状态。
布置雷
  • SetMine 函数随机生成雷的位置。
  • 使用 rand() 函数生成随机坐标,确保每个位置最多只有一个雷。
获取周围雷的数量
  • GetMineCount 函数计算某个格子周围雷的数量。
  • 通过遍历周围的八个格子,累加雷的数量。
排查雷
  • FindMine 函数处理玩家的输入,判断翻开的格子,并更新棋盘状态。
  • 玩家输入坐标后,检查该位置是否有雷。
  • 如果有雷,游戏结束。
  • 如果没有雷,显示该位置周围雷的数量,并更新 win 计数器。
  • 当 win 计数器达到非雷格子总数时,游戏胜利。
主函数
  • main 函数包含游戏菜单和游戏逻辑。
  • 使用 do-while 循环不断显示菜单,直到玩家选择退出。
  • 根据玩家的选择调用相应函数。

通过以上设计和实现,我们构建了一个简单的扫雷游戏。这也是市面上大部分游戏制作的思路之一,先分析在动手,接下来,我就给大家奉上源代码,需要的可以看看哦!

源代码

game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define EASY_COUNT 10
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2

// 初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
// 打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
// 布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
// 排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
// 获取周围雷的数量
int GetMineCount(char mine[ROWS][COLS], int x, int y);
game.c
#include "game.h"

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            board[i][j] = set;
        }
    }
}

void DisplayBoard(char board[ROWS][COLS], int row, int col) {
    printf("--------扫雷游戏-------\n");
    printf("  ");
    for (int i = 1; i <= col; i++) {
        printf("%d ", i);
    }
    printf("\n");
    for (int i = 1; i <= row; i++) {
        printf("%d ", i);
        for (int j = 1; j <= col; j++) {
            printf("%c ", board[i][j]);
        }
        printf("\n");
    }
}

void SetMine(char board[ROWS][COLS], int row, int col) {
    srand((unsigned int)time(NULL));
    int count = EASY_COUNT;
    while (count) {
        int x = rand() % row + 1;
        int y = rand() % col + 1;
        if (board[x][y] == '0') {
            board[x][y] = '1';
            count--;
        }
    }
}

int GetMineCount(char mine[ROWS][COLS], int x, int y) {
    return (mine[x-1][y-1] + mine[x-1][y] + mine[x-1][y+1] +
            mine[x][y-1] + mine[x][y+1] +
            mine[x+1][y-1] + mine[x+1][y] + mine[x+1][y+1] - 8 * '0');
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {
    int x = 0;
    int y = 0;
    int win = 0;
    while (win < row * col - EASY_COUNT) {
        printf("请输入要排查的坐标:>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 1 && y <= col) {
            if (mine[x][y] == '1') {
                printf("很遗憾,你被炸死了\n");
                DisplayBoard(mine, ROW, COL);
                return;
            } else {
                int count = GetMineCount(mine, x, y);
                show[x][y] = count + '0';
                DisplayBoard(show, ROW, COL);
                win++;
            }
        } else {
            printf("坐标非法,重新输入\n");
        }
    }
    printf("恭喜你,排雷成功\n");
    DisplayBoard(mine, ROW, COL);
}
test.c
#include "game.h"

void menu() {
    printf("***********************\n");
    printf("***** 1. play *****\n");
    printf("***** 0. exit *****\n");
    printf("***********************\n");
}

void game() {
    char mine[ROWS][COLS]; // 存放布置好的雷
    char show[ROWS][COLS]; // 存放排查出的雷的信息
    // 初始化棋盘
    InitBoard(mine, ROWS, COLS, '0');
    InitBoard(show, ROWS, COLS, '*');
    // 打印棋盘
    DisplayBoard(show, ROW, COL);
    // 布置雷
    SetMine(mine, ROW, COL);
    // 排查雷
    FindMine(mine, show, ROW, COL);
}

int main() {
    int input = 0;
    srand((unsigned int)time(NULL));
    do {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input) {
            case 1:
                game();
                break;
            case 0:
                printf("退出游戏\n");
                break;
            default:
                printf("选择错误,重新选择\n");
                break;
        }
    } while (input != 0);
    return 0;
}
代码解释
  1. 初始化棋盘

    • InitBoard 函数用于初始化棋盘,将所有位置设置为指定字符。
  2. 打印棋盘

    • DisplayBoard 函数用于打印棋盘,显示当前的状态。
  3. 布置雷

    • SetMine 函数用于随机布置雷,确保每个位置最多只有一个雷。
  4. 获取周围雷的数量

    • GetMineCount 函数用于计算某个位置周围雷的数量。
  5. 排查雷

    • FindMine 函数用于玩家输入坐标,检查该位置是否有雷,并显示周围雷的数量。
  6. 主函数

    • main 函数包含游戏菜单和游戏逻辑,允许玩家选择开始游戏或退出。

当你编译并运行这段代码时,你会看到一个简单的扫雷游戏界面。玩家可以选择开始游戏或退出。在游戏中,玩家输入坐标来排查雷,如果踩到雷则游戏结束,否则显示周围雷的数量。如果玩家成功排查所有非雷位置,则游戏胜利。这就是一个简单的扫雷游戏!

重量级扫雷

当然,还有一个重量级别的扫雷,那就是具备网页,有不同难度,但是还尚不完善,我可以先给大家玩一玩,后面完善在给大家更好的体验!

将扫雷游戏移植到网页上可以通过多种前端技术和框架来实现。

这里我们使用 HTML、CSS 和 JavaScript 来创建一个简单的扫雷游戏。我们可以使用纯JavaScript 或者结合一些流行的前端框架(如 React、Vue 等)来实现。

基本实现步骤
  1. HTML 结构:创建基本的 HTML 结构。
  2. CSS 样式:添加样式来美化界面。
  3. JavaScript 逻辑:实现游戏的核心逻辑。
示例代码
1. HTML 结构
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>扫雷游戏</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div id="game-container">
        <h1>扫雷游戏</h1>
        <button id="start-button">开始游戏</button>
        <div id="minefield"></div>
    </div>
    <script src="script.js"></script>
</body>
</html>
2. CSS 样式
/* styles.css */
body {
    font-family: Arial, sans-serif;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: #f0f0f0;
}

#game-container {
    text-align: center;
}

#minefield {
    display: grid;
    grid-template-columns: repeat(9, 40px);
    gap: 2px;
    margin-top: 20px;
}

.cell {
    width: 40px;
    height: 40px;
    background-color: #ddd;
    border: 1px solid #aaa;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
}

.cell.revealed {
    background-color: #fff;
}

.cell.flagged {
    background-color: #ff0;
    color: red;
}

.cell.mine {
    background-color: #f00;
    color: #fff;
}

.cell.number {
    color: blue;
}
3. JavaScript 逻辑
// script.js
const ROWS = 9;
const COLS = 9;
const MINE_COUNT = 10;

let minefield = [];
let revealedCells = 0;
let mines = [];

function initGame() {
    minefield = [];
    revealedCells = 0;
    mines = [];
    generateMinefield();
    renderMinefield();
}

function generateMinefield() {
    for (let i = 0; i < ROWS; i++) {
        minefield[i] = [];
        for (let j = 0; j < COLS; j++) {
            minefield[i][j] = { mine: false, revealed: false, flagged: false, number: 0 };
        }
    }

    let count = MINE_COUNT;
    while (count > 0) {
        let x = Math.floor(Math.random() * ROWS);
        let y = Math.floor(Math.random() * COLS);
        if (!minefield[x][y].mine) {
            minefield[x][y].mine = true;
            mines.push({ x, y });
            count--;
        }
    }

    for (let { x, y } of mines) {
        updateNumbers(x, y);
    }
}

function updateNumbers(x, y) {
    const directions = [
        [-1, -1], [-1, 0], [-1, 1],
        [0, -1], [0, 1],
        [1, -1], [1, 0], [1, 1]
    ];

    for (let [dx, dy] of directions) {
        let nx = x + dx;
        let ny = y + dy;
        if (nx >= 0 && nx < ROWS && ny >= 0 && ny < COLS) {
            minefield[nx][ny].number++;
        }
    }
}

function renderMinefield() {
    const minefieldContainer = document.getElementById('minefield');
    minefieldContainer.innerHTML = '';

    for (let i = 0; i < ROWS; i++) {
        for (let j = 0; j < COLS; j++) {
            const cell = document.createElement('div');
            cell.classList.add('cell');
            cell.dataset.x = i;
            cell.dataset.y = j;
            cell.addEventListener('click', revealCell);
            cell.addEventListener('contextmenu', flagCell);
            minefieldContainer.appendChild(cell);
        }
    }
}

function revealCell(event) {
    event.preventDefault();
    const x = parseInt(this.dataset.x);
    const y = parseInt(this.dataset.y);

    if (minefield[x][y].revealed || minefield[x][y].flagged) return;

    if (minefield[x][y].mine) {
        this.classList.add('mine');
        this.textContent = '💣';
        alert('很遗憾,你被炸死了!');
        revealAllMines();
        return;
    }

    minefield[x][y].revealed = true;
    revealedCells++;

    if (minefield[x][y].number > 0) {
        this.classList.add('revealed', 'number');
        this.textContent = minefield[x][y].number;
    } else {
        this.classList.add('revealed');
        revealAdjacentCells(x, y);
    }

    if (revealedCells === ROWS * COLS - MINE_COUNT) {
        alert('恭喜你,排雷成功!');
        revealAllMines();
    }
}

function flagCell(event) {
    event.preventDefault();
    const x = parseInt(this.dataset.x);
    const y = parseInt(this.dataset.y);

    if (minefield[x][y].revealed) return;

    if (minefield[x][y].flagged) {
        this.classList.remove('flagged');
        this.textContent = '';
        minefield[x][y].flagged = false;
    } else {
        this.classList.add('flagged');
        this.textContent = '🚩';
        minefield[x][y].flagged = true;
    }
}

function revealAdjacentCells(x, y) {
    const directions = [
        [-1, -1], [-1, 0], [-1, 1],
        [0, -1], [0, 1],
        [1, -1], [1, 0], [1, 1]
    ];

    for (let [dx, dy] of directions) {
        let nx = x + dx;
        let ny = y + dy;
        if (nx >= 0 && nx < ROWS && ny >= 0 && ny < COLS && !minefield[nx][ny].revealed) {
            const cell = document.querySelector(`[data-x="${nx}"][data-y="${ny}"]`);
            if (minefield[nx][ny].mine) continue;
            minefield[nx][ny].revealed = true;
            revealedCells++;
            cell.classList.add('revealed');
            if (minefield[nx][ny].number > 0) {
                cell.classList.add('number');
                cell.textContent = minefield[nx][ny].number;
            } else {
                revealAdjacentCells(nx, ny);
            }
        }
    }
}

function revealAllMines() {
    for (let { x, y } of mines) {
        const cell = document.querySelector(`[data-x="${x}"][data-y="${y}"]`);
        cell.classList.add('mine');
        cell.textContent = '💣';
    }
}

document.getElementById('start-button').addEventListener('click', initGame);

initGame();
解释
  1. HTML 结构

    • 创建了一个按钮用于开始游戏。
    • 创建了一个容器用于显示雷区。
  2. CSS 样式

    • 设置了基本的样式,使游戏界面美观。
    • 使用 grid 布局来排列雷区单元格。
  3. JavaScript 逻辑

    • initGame 函数初始化游戏,生成雷区并渲染到页面。
    • generateMinefield 函数生成随机雷区。
    • updateNumbers 函数更新每个单元格周围的雷数。
    • renderMinefield 函数将雷区渲染到页面。
    • revealCell 函数处理点击单元格的逻辑,揭示单元格内容。
    • flagCell 函数处理右键标记单元格的逻辑。
    • revealAdjacentCells 函数递归揭示相邻的空单元格。
    • revealAllMines 函数揭示所有雷区中的雷。

这三段代码分别对应 HTML、CSS 和 JavaScript 文件。

你可以将它们放在各自的文件中,然后通过 HTML 文件链接这些文件。

文件结构
project/
│
├── index.html
├── styles.css
└── script.js

原文地址:https://blog.csdn.net/speaking_me/article/details/143752732

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!