【C语言】2048小游戏【附源码】

2024-04-06 18:44
文章标签 语言 源码 小游戏 2048

本文主要是介绍【C语言】2048小游戏【附源码】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

欢迎来到英杰社区https://bbs.csdn.net/topics/617804998

一、游戏描述:

        2048是一款数字益智类游戏,玩家需要使用键盘控制数字方块的移动,合并相同数字的方块,最终达到数字方块上出现“2048”的目标。

        每次移动操作,所有数字方块会朝着指定方向同时滑动,并在靠近边界或其他数字方块时停止。如果两个相邻的数字方块数字相同,则它们会合并成一个方块,数字值为原先相同方块的数字值相加。

 

二、效果展示

c661ac348297482ea142d8baa7a78410.png

 

三、代码讲解:

        实现了一个2048游戏的基本功能,包括初始化游戏界面、移动方块、放置新数字以及判定胜负等功能:

  1. DisplayBoard(int board[ROW][COL]):初始化并打印游戏界面。这个函数用于显示游戏的当前状态,包括棋盘上的数字和空格。

  2. init_num(int board[ROW][COL]):在游戏开始时随机生成两个数字2。这个函数用于初始化游戏棋盘,给棋盘上的两个随机位置赋值为2。

  3. put_num(int board[ROW][COL]):在每次移动后随机放置一个数字2或4。这个函数用于在每次玩家移动后,在空白的位置随机生成一个数字2或4。

  4. up(int board[ROW][COL])down(int board[ROW][COL])left(int board[ROW][COL])right(int board[ROW][COL]):分别实现了向上、向下、向左、向右移动的功能。这些函数用于处理玩家的移动操作,更新棋盘上的数字位置。

  5. is_win(int board[ROW][COL]):判断是否获胜。这个函数用于检查游戏是否达到了2048,如果有一个位置的值为2048,则游戏获胜。

  6. is_fail(int board[ROW][COL]):判断是否失败。这个函数用于检查游戏是否失败,即所有位置都被填满且无法进行有效的移动操作。

 

#pragma once#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <windows.h>
#include<conio.h>#define ROW 4
#define COL 4
const int copy[ROW][COL];//初始化并打印游戏界面
void DisplayBoard(int board[ROW][COL]);
//开局随机生成两个2
void init_num(int board[ROW][COL]);
//在移动后随机放置数字2或4
void put_num(int board[ROW][COL]);
//移动
void up(int board[ROW][COL]);
void down(int board[ROW][COL]);
void left(int board[ROW][COL]);
void right(int board[ROW][COL]);
//判定胜负
int is_win(int board[ROW][COL]);
int is_fail(int board[ROW][COL]);

显示2048游戏的棋盘界面

        

  1. 打印横向的分隔线,使用"+"和"-"来表示。
  2. 遍历每个格子,如果格子上有数字,则打印该数字并确保宽度为5个字符,右对齐;如果格子上没有数字,则打印5个空格。
  3. 在每行末尾打印"|"
  4. 再次打印横向的分隔线,使用"+"和"-"来表示。
void DisplayBoard(int board[ROW][COL])
{int i = 0;int j = 0;printf("tip:*方向键控制方块移动*ESC键返回菜单*\n");for (int j = 0; j < COL; j++)printf("+-----");printf("+\n");for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++){printf("|");if (board[i][j] != 0)printf("%5d", board[i][j]);elseprintf("     ");}printf("|\n");for (int j = 0; j < COL; j++){printf("+-----");}printf("+\n");}
}

 

初始化游戏棋盘:

        

  1. 生成一个随机的行索引 x 和列索引 y,确保它们在棋盘范围内。
  2. 在随机选择的位置 (x, y) 上放置一个数字2。
  3. 再次生成一个随机的行索引 x 和列索引 y,确保它们与第一个位置不重复。
  4. 在新的随机选择的位置 (x, y) 上放置另一个数字2。
void init_num(int board[ROW][COL])
{int x, y;x = rand() % ROW;y = rand() % COL;board[x][y] = 2;//随机在一个位置生成2x = rand() % ROW;y = rand() % COL;while (board[x][y] == 2){x = rand() % ROW;y = rand() % COL;}board[x][y] = 2;return;
}

空白位置随机放置一个数字:

  1. 生成一个随机的行索引 x 和列索引 y,确保它们在棋盘范围内。
  2. 如果在选择的位置 (x, y) 上已经有数字,则继续随机选择位置,直到找到一个空白位置。
  3. 生成一个随机数 z,范围为0到9之间的整数。
  4. 如果 z 小于9,则在当前空白位置 (x, y) 放置数字2;如果 z 等于9,则放置数字4。
void put_num(int board[ROW][COL])
{int x = 0;int y = 0;int z = 0;x = rand() % ROW;y = rand() % COL;while (board[x][y] != 0){x = rand() % ROW;y = rand() % COL;}z = rand() % 10;if (z < 9)board[x][y] = 2;elseboard[x][y] = 4;return;
}

简单的 2048 游戏的移动和合并操作

        上下左右四个方向的移动操作:up、down、left、right

每个函数都按照相应的方向进行移动并合并相同的数字。

在每个函数中,首先进行移动操作,然后进行合并操作,再次进行移动操作,并最后检查游戏是否可以继续进行(通过contrast(board)函数判断)。如果游戏可以继续,则调用put_num(board)函数来生成新的数字;否则直接返回。

void up(int board[ROW][COL])
{int i = 0;int j = 0;int x = 0;int y = 0;for (i = 0; i < ROW; i++){//移动j = 0;y = 0;while (j < COL - 1 && y < COL - 1){if (board[j][i] == 0){for (x = j; x < ROW - 1; x++)board[x][i] = board[x + 1][i];board[ROW - 1][i] = 0;y++;}elsej++;}//合并for (j = 0; j < COL - 1; j++)if (board[j][i] == board[j + 1][i] && board[j][i] != 0){board[j][i] = board[j][i] * 2;board[j + 1][i] = 0;}//再次移动补空j = 0;y = 0;while (j < COL - 1 && y < COL - 1){if (board[j][i] == 0){for (x = j; x < ROW - 1; x++)board[x][i] = board[x + 1][i];board[ROW - 1][i] = 0;y++;}elsej++;}}if (contrast(board) == 0)put_num(board);elsereturn;
}void down(int board[ROW][COL])
{int i = 0;int j = 0;int x = 0;int y = 0;for (i = 0; i < ROW; i++){j = COL - 1;y = 0;while (j > 0 && y < COL - 1){if (board[j][i] == 0){for (x = j; x > 0; x--)board[x][i] = board[x - 1][i];board[0][i] = 0;y++;}elsej--;}for (j = COL - 1; j > 0; j--)if (board[j][i] == board[j - 1][i] && board[j][i] != 0){board[j][i] = board[j][i] * 2;board[j - 1][i] = 0;}j = COL - 1;y = 0;while (j > 0 && y < COL - 1){if (board[j][i] == 0){for (x = j; x > 0; x--)board[x][i] = board[x - 1][i];board[0][i] = 0;y++;}elsej--;}}if (contrast(board) == 0)put_num(board);elsereturn;
}void left(int board[ROW][COL])
{int i = 0;int j = 0;int x = 0;int y = 0;for (i = 0; i < ROW; i++){j = 0;y = 0;while (j < 3 && y < 3){if (board[i][j] == 0){for (x = j; x < ROW - 1; x++)board[i][x] = board[i][x + 1];board[i][COL - 1] = 0;y++;}elsej++;}for (j = 0; j < 3; j++)if (board[i][j] == board[i][j + 1] && board[i][j] != 0){board[i][j] = board[i][j] * 2;board[i][j + 1] = 0;}j = 0;y = 0;while (j < 3 && y < 3){if (board[i][j] == 0){for (x = j; x < ROW - 1; x++)board[i][x] = board[i][x + 1];board[i][COL - 1] = 0;y++;}elsej++;}}if (contrast(board) == 0)put_num(board);elsereturn;
}void right(int board[ROW][COL])
{int i = 0;int j = 0;int x = 0;int y = 0;for (i = 0; i < 4; i++){j = COL - 1;y = 0;while (j > 0 && y < COL - 1){if (board[i][j] == 0){for (x = j; x > 0; x--)board[i][x] = board[i][x - 1];board[i][0] = 0;y++;}else j--;}for (j = 3; j > 0; j--)if (board[i][j] == board[i][j - 1] && board[i][j] != 0){board[i][j] = board[i][j] * 2;board[i][j - 1] = 0;}j = COL - 1;y = 0;while (j > 0 && y < COL - 1){if (board[i][j] == 0){for (x = j; x > 0; x--)board[i][x] = board[i][x - 1];board[i][0] = 0;y++;}else j--;}}if (contrast(board) == 0)put_num(board);elsereturn;
}

 

判断在 2048 游戏中是否无法继续移动

  1. 游戏板上还有空格(值为0),即游戏可以继续;
  2. 相邻的方块(上下或左右相邻)有相同的值,即游戏可以继续合并。

如果以上任意情况成立,函数将返回0,表示游戏可以继续;否则,如果所有方块都被填满且没有相邻方块的值相同,函数将返回1,表示游戏无法继续移动,游戏结束。

 

 

int is_fail(int board[ROW][COL])
{int i = 0;int j = 0;for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){if (board[i][j] == 0)return 0;if (i > 0){if (board[i - 1][j] == board[i][j])return 0;}if (j > 0){if (board[i][j - 1] == board[i][j])return 0;}}}return 1;
}

检查在2048游戏中是否获胜

该函数遍历整个游戏板,找到其中的最大值。如果最大值达到或超过2048,函数将返回1,表示玩家已经获胜;否则返回0,表示游戏尚未获胜。

在2048游戏中,玩家的目标是通过合并方块使得其中一个方块的值达到2048。一旦某个方块的值达到2048,玩家就获胜了。

这个函数的作用是在每一步移动后检查游戏是否已经达到了获胜条件。如果返回1,通常会触发游戏获胜的逻辑,比如显示获胜信息或者终止游戏等。

int is_win(int board[ROW][COL])
{int i = 0;int j = 0;int num = 0;for (i = 0; i < ROW; i++)for (j = 0; j < COL; j++){if (board[i][j] > num)num = board[i][j];}if (num >= 2048)return 1;elsereturn 0;
}

        copyboard 函数的作用是将一个二维数组 board 中的元素复制到另一个二维数组 copy 中。通常在编程中,这样的函数用于保存一个数组的副本,以便后续的比较或者其他操作而不影响原始数组。

void copyboard(int board[ROW][COL], int copy[ROW][COL])
{int i = 0;int j = 0;for (i = 0; i < ROW; i++)for (j = 0; j < COL; j++)copy[i][j] = board[i][j];
}

菜单功能:

void menu()
{printf("**************************\n");printf("**************************\n");printf("**************************\n");printf("*****按 1 开 始 游 戏*****\n");printf("*****按 0 退 出 游 戏*****\n");printf("**************************\n");printf("**************************\n");printf("**************************\n");
}

主函数:

int main()
{int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择:");scanf("%d", &input);switch (input){case 1:game2048();break;case 0:printf("退出游戏)\n");break;default:printf("再次进入游戏\n");break;}} while (input);return 0;
}

完整代码:

        Test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game2048.h"void menu()
{printf("**************************\n");printf("**************************\n");printf("**************************\n");printf("*****按 1 开 始 游 戏*****\n");printf("*****按 0 退 出 游 戏*****\n");printf("**************************\n");printf("**************************\n");printf("**************************\n");
}void game2048()
{int board[ROW][COL] = { {0} };int control = 0;DisplayBoard(board);init_num(board);system("cls"); //清屏,美观界面DisplayBoard(board);while ((control = _getch()) != 0x1b){switch (control){case 0xe0:switch (control = getch()){case 72:copyboard(board, copy);up(board);break;case 80:copyboard(board, copy);down(board);break;case 75:copyboard(board, copy);left(board);break;case 77:copyboard(board, copy);right(board);break;default:break;}system("cls");DisplayBoard(board);if (is_win(board) == 1){printf("恭喜你赢了!\n");}if (is_fail(board) == 1){printf("抱歉,您未能通关\n");}}}
}int main()
{int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择:");scanf("%d", &input);switch (input){case 1:game2048();break;case 0:printf("退出游戏)\n");break;default:printf("再次进入游戏\n");break;}} while (input);return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include "game2048.h"void DisplayBoard(int board[ROW][COL])
{int i = 0;int j = 0;printf("tip:*方向键控制方块移动*ESC键返回菜单*\n");for (int j = 0; j < COL; j++)printf("+-----");printf("+\n");for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++){printf("|");if (board[i][j] != 0)printf("%5d", board[i][j]);elseprintf("     ");}printf("|\n");for (int j = 0; j < COL; j++){printf("+-----");}printf("+\n");}
}void init_num(int board[ROW][COL])
{int x, y;x = rand() % ROW;y = rand() % COL;board[x][y] = 2;//随机在一个位置生成2x = rand() % ROW;y = rand() % COL;while (board[x][y] == 2){x = rand() % ROW;y = rand() % COL;}board[x][y] = 2;return;
}void put_num(int board[ROW][COL])
{int x = 0;int y = 0;int z = 0;x = rand() % ROW;y = rand() % COL;while (board[x][y] != 0){x = rand() % ROW;y = rand() % COL;}z = rand() % 10;if (z < 9)board[x][y] = 2;elseboard[x][y] = 4;return;
}void up(int board[ROW][COL])
{int i = 0;int j = 0;int x = 0;int y = 0;for (i = 0; i < ROW; i++){//移动j = 0;y = 0;while (j < COL - 1 && y < COL - 1){if (board[j][i] == 0){for (x = j; x < ROW - 1; x++)board[x][i] = board[x + 1][i];board[ROW - 1][i] = 0;y++;}elsej++;}//合并for (j = 0; j < COL - 1; j++)if (board[j][i] == board[j + 1][i] && board[j][i] != 0){board[j][i] = board[j][i] * 2;board[j + 1][i] = 0;}//再次移动补空j = 0;y = 0;while (j < COL - 1 && y < COL - 1){if (board[j][i] == 0){for (x = j; x < ROW - 1; x++)board[x][i] = board[x + 1][i];board[ROW - 1][i] = 0;y++;}elsej++;}}if (contrast(board) == 0)put_num(board);elsereturn;
}void down(int board[ROW][COL])
{int i = 0;int j = 0;int x = 0;int y = 0;for (i = 0; i < ROW; i++){j = COL - 1;y = 0;while (j > 0 && y < COL - 1){if (board[j][i] == 0){for (x = j; x > 0; x--)board[x][i] = board[x - 1][i];board[0][i] = 0;y++;}elsej--;}for (j = COL - 1; j > 0; j--)if (board[j][i] == board[j - 1][i] && board[j][i] != 0){board[j][i] = board[j][i] * 2;board[j - 1][i] = 0;}j = COL - 1;y = 0;while (j > 0 && y < COL - 1){if (board[j][i] == 0){for (x = j; x > 0; x--)board[x][i] = board[x - 1][i];board[0][i] = 0;y++;}elsej--;}}if (contrast(board) == 0)put_num(board);elsereturn;
}void left(int board[ROW][COL])
{int i = 0;int j = 0;int x = 0;int y = 0;for (i = 0; i < ROW; i++){j = 0;y = 0;while (j < 3 && y < 3){if (board[i][j] == 0){for (x = j; x < ROW - 1; x++)board[i][x] = board[i][x + 1];board[i][COL - 1] = 0;y++;}elsej++;}for (j = 0; j < 3; j++)if (board[i][j] == board[i][j + 1] && board[i][j] != 0){board[i][j] = board[i][j] * 2;board[i][j + 1] = 0;}j = 0;y = 0;while (j < 3 && y < 3){if (board[i][j] == 0){for (x = j; x < ROW - 1; x++)board[i][x] = board[i][x + 1];board[i][COL - 1] = 0;y++;}elsej++;}}if (contrast(board) == 0)put_num(board);elsereturn;
}void right(int board[ROW][COL])
{int i = 0;int j = 0;int x = 0;int y = 0;for (i = 0; i < 4; i++){j = COL - 1;y = 0;while (j > 0 && y < COL - 1){if (board[i][j] == 0){for (x = j; x > 0; x--)board[i][x] = board[i][x - 1];board[i][0] = 0;y++;}else j--;}for (j = 3; j > 0; j--)if (board[i][j] == board[i][j - 1] && board[i][j] != 0){board[i][j] = board[i][j] * 2;board[i][j - 1] = 0;}j = COL - 1;y = 0;while (j > 0 && y < COL - 1){if (board[i][j] == 0){for (x = j; x > 0; x--)board[i][x] = board[i][x - 1];board[i][0] = 0;y++;}else j--;}}if (contrast(board) == 0)put_num(board);elsereturn;
}int is_fail(int board[ROW][COL])
{int i = 0;int j = 0;for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){if (board[i][j] == 0)return 0;if (i > 0){if (board[i - 1][j] == board[i][j])return 0;}if (j > 0){if (board[i][j - 1] == board[i][j])return 0;}}}return 1;
}int is_win(int board[ROW][COL])
{int i = 0;int j = 0;int num = 0;for (i = 0; i < ROW; i++)for (j = 0; j < COL; j++){if (board[i][j] > num)num = board[i][j];}if (num >= 2048)return 1;elsereturn 0;
}void copyboard(int board[ROW][COL], int copy[ROW][COL])
{int i = 0;int j = 0;for (i = 0; i < ROW; i++)for (j = 0; j < COL; j++)copy[i][j] = board[i][j];
}int contrast(int board[ROW][COL])
{int i = 0;int j = 0;for (i = 0; i < 4; i++)for (j = 0; j < 4; j++)if (copy[i][j] != board[i][j])return 0;return 1;
}

 

 

这篇关于【C语言】2048小游戏【附源码】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/880559

相关文章

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路

Go语言使用net/http构建一个RESTful API的示例代码

《Go语言使用net/http构建一个RESTfulAPI的示例代码》Go的标准库net/http提供了构建Web服务所需的强大功能,虽然众多第三方框架(如Gin、Echo)已经封装了很多功能,但... 目录引言一、什么是 RESTful API?二、实战目标:用户信息管理 API三、代码实现1. 用户数据

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

Go语言使用sync.Mutex实现资源加锁

《Go语言使用sync.Mutex实现资源加锁》数据共享是一把双刃剑,Go语言为我们提供了sync.Mutex,一种最基础也是最常用的加锁方式,用于保证在任意时刻只有一个goroutine能访问共享... 目录一、什么是 Mutex二、为什么需要加锁三、实战案例:并发安全的计数器1. 未加锁示例(存在竞态)

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

C语言中%zu的用法解读

《C语言中%zu的用法解读》size_t是无符号整数类型,用于表示对象大小或内存操作结果,%zu是C99标准中专为size_t设计的printf占位符,避免因类型不匹配导致错误,使用%u或%d可能引发... 目录size_t 类型与 %zu 占位符%zu 的用途替代占位符的风险兼容性说明其他相关占位符验证示