基于C语言的益智游戏合集

导语:

        游戏是人们放松娱乐的极佳方式,而多合一控制台游戏项目将不同类型的游戏集成到一个程序中,为玩家提供了多种娱乐方式。

  1. 背景:立项时,对于只是编程初学者,对于复杂的项目无法实现,用这种多个小项目集合成的合集能提升每个组员的动手能力,以便于为后续的开发奠定基础。
  2. 现状:组内人员仅有部分是提前学习过编程。
  3. 意义:提升组内成员的团队协作能力、动手能力,为日后实现大项目奠定基础

本文将介绍我小组的一个多合一游戏项目,展示了其创新特色、游戏种类和成果。

项目创新点:

1.多种游戏集成

        这个项目中,我们为玩家提供了四种截然不同的小游戏。首先,贪吃蛇是一种考验反应速度和策略的游戏,玩家需要控制一条蛇吃食物,不撞到自己。井字棋则是一款经典的策略游戏,两名玩家轮流下棋,目标是连成一条线。扫雷是一种挑战性的逻辑游戏,玩家需要根据数字提示揭示雷的位置而不触发它们。最后,我们还加入了一个五子棋游戏,两名玩家可以在电脑上进行对局。这种多样性使得我们的项目在游戏选择上更加灵活,适合不同类型的玩家。

2.用户界面改进

        为了增强用户体验,我们在控制台应用中实现了一些用户界面的改进。这包括一个交互式游戏菜单,玩家可以通过简单的文本菜单选择他们想要玩的游戏。此外,游戏板也得到了可视化展示的改进,让玩家更清晰地看到游戏的状态和棋盘。

3.得分记录和数据存储

        一个好的游戏不仅仅是娱乐,还需要有一种记录和分享成绩的机制。在我们的项目中,我们实现了得分记录功能。这意味着玩家可以保存他们的游戏得分,以便日后查看和分享。特别是在扫雷游戏中,这一功能为玩家提供了一个机会来记录自己是否赢得了游戏。

4.模块化的设计和团队合作

这个项目的设计采用了模块化的方法,每个小游戏被视为一个独立的模块,这使得不同的团队成员可以专注于各自的游戏。这不仅有助于提高每个成员的动手能力,还培养了团队合作的技能。在项目的不同阶段,我们都需要协调工作,确保不同模块的顺利集成和互操作。

项目成果(核心代码实现展示)

        项目的主要成果包括多个游戏的实现、游戏选择和得分记录、数据的读取和存储、用户界面改进等。这些成果为玩家提供了多种娱乐方式,并为未来的改进和扩展奠定了基础。模块化的设计让团队成员分工明确,让团队成员初步掌握了团队合作能力。

(1)贪吃蛇

绘画 地图 和 蛇

        一个用于绘制贪吃蛇游戏界面的函数。

1. `system("cls")` 用于清空控制台屏幕,以便在每次更新画面时覆盖之前的内容,实现动态效果。

2. 两个 `for` 循环用于绘制游戏界面的顶部和底部边框,以 `#` 字符表示,形成游戏区域的边界。

3. 接下来是一个嵌套的 `for` 循环,用于遍历游戏区域的每个单元格。在每个单元格中,根据其内容,绘制不同的字符:

   - 如果 `(i, j)` 单元格的位置与蛇头的位置 `(headY, headX)` 相同,则打印字符 "O" 表示蛇头。
   - 如果 `(i, j)` 单元格的位置与食物的位置 `(fruitY, fruitX)` 相同,则打印字符 "F" 表示食物。
   - 否则,进一步检查蛇的身体部分。如果 `(i, j)` 与蛇身体中的某个部分位置 `(tailY[k], tailX[k])` 相同,则打印小写字母 "o" 表示蛇的身体。如果没有匹配的身体部分,打印空格字符以表示空白。

4. 在每行的结尾处,打印 `#` 字符以形成游戏区域的右边界。

5. 在游戏界面的底部,打印玩家的得分,使用 `printf("Score:%d\n", score)`,以及一个消息提示玩家如何退出游戏,使用 `printf("~  input 'x' to exit\n")`。

void Draw() {
    system("cls");

    for (int i = 0; i < WIDTH + 2; i++)
        printf("#");
    printf("\n");

    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            if (j == 0)
                printf("#");
            if (i == headY && j == headX)
                printf("O"); // 蛇头
            else if (i == fruitY && j == fruitX)
                printf("F"); // 食物
            else {
                bool print = false;
                for (int k = 0; k < nTail; k++) {
                    if (tailX[k] == j && tailY[k] == i) {
                        printf("o"); // 蛇身
                        print = true;
                    }
                }
                if (!print)
                    printf(" ");
            }

            if (j == WIDTH - 1)
                printf("#");
        }
        printf("\n");
    }

    for (int i = 0; i < WIDTH + 2; i++)
        printf("#");
    printf("\n");
    printf("Score:%d\n", score);
    printf("~  input 'x' to exit\n");
}

游戏逻辑的实现

        定义了名为`Logic`的函数,负责更新游戏状态,包括移动蛇、检查碰撞以及处理吃到水果的情况。

1. `prevX` 和 `prevY` 存储了蛇头的上一个位置。
2. `prev2X` 和 `prev2Y` 用于在循环中存储蛇尾的上一个位置。
3. 代码通过将每个部分的位置向前一个部分的位置移动来更新蛇身体的位置。
4. `switch` 语句(`switch (dir)`)根据当前的移动方向(`LEFT`、`RIGHT`、`UP` 或 `DOWN`)更新蛇头的位置。
5. 在更新蛇头位置后,代码检查蛇是否移出了游戏区域的边界。如果是,它将蛇头移到屏幕的相对边,以创建一个连续的游戏区域。
6. 一个循环遍历蛇尾部分,检查蛇头是否与任何蛇尾部分发生碰撞。如果发生碰撞,游戏会将`gameOver_2`设置为`true`,表示游戏结束。
7. 最后,代码检查蛇头的位置是否与水果的位置匹配。如果匹配,玩家的得分增加10,生成新的随机水果位置,并增加蛇的长度(`nTail`)。

这段代码是贪吃蛇游戏的基本逻辑实现。它假定存在其他游戏变量,如`gameOver_2`、`WIDTH`、`HEIGHT`、`dir`、`tailX`、`tailY`、`headX`、`headY`、`nTail`、`fruitX`、`fruitY` 和 `score` 以控制游戏。这段代码应该是一个更大程序的一部分,用于处理用户输入、渲染和其他游戏功能,以创建一个完整的贪吃蛇游戏。

void Logic() {
    int prevX = tailX[0];
    int prevY = tailY[0];
    int prev2X, prev2Y;
    tailX[0] = headX;
    tailY[0] = headY;
    for (int i = 1; i < nTail; i++) {
        prev2X = tailX[i];
        prev2Y = tailY[i];
        tailX[i] = prevX;
        tailY[i] = prevY;
        prevX = prev2X;
        prevY = prev2Y;
    }
    switch (dir) {
    case LEFT:
        headX--;
        break;
    case RIGHT:
        headX++;
        break;
    case UP:
        headY--;
        break;
    case DOWN:
        headY++;
        break;
    default:
        break;
    }

    if (headX >= WIDTH) headX = 0; else if (headX < 0) headX = WIDTH - 1;
    if (headY >= HEIGHT) headY = 0; else if (headY < 0) headY = HEIGHT - 1;

    for (int i = 0; i < nTail; i++) {
        if (tailX[i] == headX && tailY[i] == headY)
            gameOver_2 = true;
    }

    if (headX == fruitX && headY == fruitY) {
        score += 10;
        fruitX = rand() % WIDTH;
        fruitY = rand() % HEIGHT;
        nTail++;
    }
}

 (2)三子棋

判断柚游戏是否结束

用于检查井字游戏的胜利条件和平局条件的函数。

1. `bool CheckWin()`
   - 这个函数用于检查是否有玩家获胜。
   - 首先,它通过迭代检查每一行和每一列,查看是否有任一行或列上的所有格子都被当前玩家 (`currentPlayer`) 占据。如果有,表示当前玩家获胜,函数返回 `true`。
   - 然后,它检查两个对角线上是否所有格子都被当前玩家占据,如果是,则返回 `true`。
   - 如果在所有检查之后仍然没有获胜,函数返回 `false`,表示没有玩家获胜。

2. `bool CheckDraw()`
   - 这个函数用于检查游戏是否平局(即没有获胜者)。
   - 它通过迭代遍历整个游戏棋盘,检查是否还有空格(用空格字符 `' '` 表示)。如果发现任何一个空格,函数会立刻返回 `false`,表示游戏尚未结束,不是平局。
   - 如果遍历完整个棋盘都没有找到空格,函数返回 `true`,表示游戏是平局。

这两个函数一起用于判断井字游戏的胜利和平局状态。通常,它们会在每次玩家下棋后被调用,以检查游戏是否已经结束。如果有一方获胜或游戏平局,相应的函数会返回 `true`,在游戏中采取相应的措施,如宣布胜利者或平局,结束游戏等。

// 检查是否有玩家获胜
bool CheckWin() {
    // 检查行和列
    for (int i = 0; i < 3; i++) {
        if (board[i][0] == currentPlayer && board[i][1] == currentPlayer && board[i][2] == currentPlayer) {
            return true;
        }
        if (board[0][i] == currentPlayer && board[1][i] == currentPlayer && board[2][i] == currentPlayer) {
            return true;
        }
    }

    // 检查对角线
    if (board[0][0] == currentPlayer && board[1][1] == currentPlayer && board[2][2] == currentPlayer) {
        return true;
    }
    if (board[0][2] == currentPlayer && board[1][1] == currentPlayer && board[2][0] == currentPlayer) {
        return true;
    }

    return false;
}

// 检查游戏是否平局
bool CheckDraw() {
    for (int row = 0; row < 3; row++) {
        for (int col = 0; col < 3; col++) {
            if (board[row][col] == ' ') {
                return false;
            }
        }
    }
    return true;
}

(3)五子棋

判断柚游戏是否结束

        用于判断五子棋游戏的胜利、有效移动和棋盘是否已满的条件。

1. `bool IsValidMove(int row, int col)`
   - 此函数用于检查玩家是否可以在指定的行和列下有效的一步棋。
   - 它检查以下条件:
     - 行和列均在棋盘大小的有效范围内。
     - 指定的行和列上的格子为空(即,尚未被任何玩家占据)。
   - 如果满足这些条件,函数返回 `true`,表示这是一个有效的移动;否则,返回 `false`。

2. `bool CheckWin(int row, int col)`
   - 此函数用于检查是否有一方玩家获胜,即在五子棋中是否有五颗连珠。
   - 它接受最后一次下棋的位置(行 `row` 和列 `col`)作为参数,以便检查该位置是否有获胜的可能。
   - 函数检查以下四个方向:
     - 水平方向:从指定位置向左和向右检查相同颜色的棋子是否连续达到五颗。
     - 垂直方向:从指定位置向上和向下检查相同颜色的棋子是否连续达到五颗。
     - 正斜线方向:从指定位置向左上和右下检查相同颜色的棋子是否连续达到五颗。
     - 反斜线方向:从指定位置向左下和右上检查相同颜色的棋子是否连续达到五颗。
   - 如果在任何一个方向上发现五颗相同颜色的棋子连珠,则返回 `true`,表示有一方玩家获胜。否则,返回 `false`,表示没有获胜者。

3. `bool IsBoardFull()`
   - 这个函数用于检查游戏棋盘是否已满,即没有空余的格子可供下棋。
   - 它遍历整个棋盘,检查每个格子是否为空(使用空格字符 `' '` 表示)。如果发现任何一个格子为空,函数返回 `false`,表示棋盘尚未满。
   - 如果遍历完整个棋盘都没有找到空格,函数返回 `true`,表示棋盘已满,游戏可能以平局结束。

bool IsValidMove(int row, int col) {
    return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] == ' ';
}

bool CheckWin(int row, int col) {
    char target = board[row][col];

    // 检查水平方向
    int count = 1;
    for (int i = 1; i < 5; i++) {
        if (col + i >= BOARD_SIZE || board[row][col + i] != target) {
            break;
        }
        count++;
    }
    for (int i = 1; i < 5; i++) {
        if (col - i < 0 || board[row][col - i] != target) {
            break;
        }
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 检查垂直方向
    count = 1;
    for (int i = 1; i < 5; i++) {
        if (row + i >= BOARD_SIZE || board[row + i][col] != target) {
            break;
        }
        count++;
    }
    for (int i = 1; i < 5; i++) {
        if (row - i < 0 || board[row - i][col] != target) {
            break;
        }
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 检查正斜线方向
    count = 1;
    for (int i = 1; i < 5; i++) {
        if (row + i >= BOARD_SIZE || col + i >= BOARD_SIZE || board[row + i][col + i] != target) {
            break;
        }
        count++;
    }
    for (int i = 1; i < 5; i++) {
        if (row - i < 0 || col - i < 0 || board[row - i][col - i] != target) {
            break;
        }
        count++;
    }
    if (count >= 5) {
        return true;
    }

    // 检查反斜线方向
    count = 1;
    for (int i = 1; i < 5; i++) {
        if (row + i >= BOARD_SIZE || col - i < 0 || board[row + i][col - i] != target) {
            break;
        }
        count++;
    }
    for (int i = 1; i < 5; i++) {
        if (row - i < 0 || col + i >= BOARD_SIZE || board[row - i][col + i] != target) {
            break;
        }
        count++;
    }
    if (count >= 5) {
        return true;
    }

    return false;
}

bool IsBoardFull() {
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            if (board[i][j] == ' ') {
                return false;
            }
        }
    }
    return true;
}

(4)扫雷 

放置地雷

void PlaceMines() {
    srand(time(NULL));

    int minesPlaced = 0;
    while (minesPlaced < MINES) {
        int row = rand() % ROWS;
        int col = rand() % COLS;

        if (board[row][col] != '*') {
            board[row][col] = '*';
            minesPlaced++;
        }
    }
}

 打印棋盘

用于显示一个矩阵,用于扫雷游戏的游戏板状态。

1. `printf("   ")`:打印一行空白以留出顶部的空间。

2. `for (int i = 0; i < COLS; i++)`:通过循环打印列索引,以便玩家知道每列的编号。

3. `printf(" %d", i)`:打印列索引(`i` 变量),其中 `i` 是当前列的编号。

4. `printf("\n")`:换行,以便下一行的内容从新行开始。

5. 接下来,使用两个嵌套的循环来遍历游戏板的行和列。

6. `printf("%2d ", i)`:在每行的开头,打印行索引(`i` 变量),其中 `i` 是当前行的编号。

7. 内部循环遍历当前行的每个列。

8. `if (revealed[i][j])`:检查当前位置是否已被揭示(即,是否已经被翻开)。如果已经揭示,则继续打印相应的内容,否则打印点号表示未揭示的位置。

9. 如果已经揭示,进一步检查游戏板上的内容。如果当前位置上有地雷(`board[i][j] == '*'`),则打印星号 `*` 表示地雷。

10. 如果当前位置不是地雷,计算该位置周围的地雷数量,然后打印相应的数字(0-8)表示周围的地雷数量。计数是通过检查周围八个方向上的邻居位置是否包含地雷来实现的。如果周围没有地雷,打印两个空格表示。

11. 如果当前位置没有被揭示,打印点号 `.` 表示未揭示的位置。

12. 最后,换行结束当前行的打印。

这段代码的目的是以可视化的方式显示扫雷游戏板的状态,其中包括已揭示的区域、地雷位置以及周围地雷的数量。

void DisplayBoard_4() {
    printf("   ");
    for (int i = 0; i < COLS; i++) {
        printf(" %d", i);
    }
    printf("\n");

    for (int i = 0; i < ROWS; i++) {
        printf("%2d ", i);
        for (int j = 0; j < COLS; j++) {
            if (revealed[i][j]) {
                if (board[i][j] == '*') {
                    printf("* ");
                }
                else {
                    int count = 0;
                    if (i > 0 && j > 0 && board[i - 1][j - 1] == '*') count++;
                    if (i > 0 && board[i - 1][j] == '*') count++;
                    if (i > 0 && j < COLS - 1 && board[i - 1][j + 1] == '*') count++;
                    if (j > 0 && board[i][j - 1] == '*') count++;
                    if (j < COLS - 1 && board[i][j + 1] == '*') count++;
                    if (i < ROWS - 1 && j > 0 && board[i + 1][j - 1] == '*') count++;
                    if (i < ROWS - 1 && board[i + 1][j] == '*') count++;
                    if (i < ROWS - 1 && j < COLS - 1 && board[i + 1][j + 1] == '*') count++;

                    if (count == 0)
                        printf("  ");
                    else
                        printf("%d ", count);
                }
            }
            else {
                printf(". ");// .
            }
        }
        printf("\n");
    }
}

结语:

        多合一控制台游戏项目展示了创造力和技术的结合,为游戏爱好者提供了多种娱乐方式。通过不断改进和扩展,这个项目有望吸引更多玩家,并继续为游戏开发领域的创新做出贡献。

        无论是游戏开发者还是游戏爱好者,这个多合一游戏项目都为我们提供了一个探索、娱乐和学习的机会,让未来我们去实现更加复杂的项目奠定基础。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值