目录
一、2048游戏玩法规则
1)游戏开始时,会出现一个4x4的方格,上面会有两个随机数字方块(通常是2或者4)。
玩家可以通过滑动屏幕上的上、下、左、右四个方向来移动所有的方块,直到碰到边界或者另一个方块。
2)当两个相同数字的方块碰到一起时,它们会合并成一个价值为两者之和的新方块。例如:两个2合并成一个4,两个4合并成一个8,以此类推。
3)棋盘被数字填满,无法进行有效移动,判负,游戏结束。
4)棋盘上出现2048,判胜,游戏结束。
还不知道怎么玩的同学,可以下载这个小游戏先玩玩了解熟悉。
二、需掌握的C语言知识点
要实现一个控制台版本的2048小游戏,需要掌握以下C语言知识点:
1)数组和二维数组:用来表示游戏中的格子,每个格子是一个二维数组,行表示列数,列表示格子的状态(是否有数字、数字是多少)。方便表示游戏中的方块,包括方块的位置和数字,以及实现方块的移动和合并。
2)循环语句:使用循环语句来控制游戏的流程,包括初始化游戏、生成随机数字、移动方块、合并方块等。
3)条件语句:用来判断游戏是否结束,以及输出游戏结果。
4)随机数生成:使用随机数生成函数来生成随机数字,以实现方块的随机移动和生成。
5)输入输出:使用输入输出函数来读取用户输入和输出游戏结果。
6)函数:将游戏的不同功能模块化,使得代码更加清晰和易于维护。
除了以上知识点,还需要了解C语言的常用库函数和数据类型,例如stdio.h、stdlib.h、time.h等库函数。
三、实现流程
1)初始化游戏:创建一个4x4的二维数组,用来表示游戏棋盘。初始时,随机生成两个数字方块,分别放在棋盘上。
2)生成随机数字:在游戏过程中,每次生成一个随机数字,用来表示新生成的方块。
3)移动方块:根据用户的输入,将所有的方块向前移动靠拢至边缘。如果两个方块相撞,则合并成一个新的方块。
4)合并方块:当两个相同数字的方块碰到一起时,它们会合并成一个价值为两者之和的新方块。合并方块时,需要使用递归来寻找可以合并的方块。
5)判断游戏结束:如果棋盘被数字填满,无法进行有效移动,或者出现2048的方块,则游戏结束。
6)输出游戏结果:输出棋盘上每个方块的数字和位置,以及游戏得分。
四、实现代码
#include"stdafx.h"
#include"stdlib.h"
#include"stdio.h"
#include"time.h"
#include"conio.h"
#include"windows.h"
int grid[4][4] = { 0 }; //保存4*4的格子数字
int score = 0;//游戏分数
void gotoXY(int x, int y) //设定输出位置
{
COORD c; //光标位置
c.X = x - 1;
c.Y = y - 1;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);//获取句柄,设置位置
HANDLE hOutStd = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci; //控制台光标信息结构类型
cci.dwSize = 1; //光标大小
cci.bVisible = 0; //是否显示光标 true显示
SetConsoleCursorInfo(hOutStd, &cci); //设置控制台屏幕光标大小和可见性
}
void printGrid() { //打印游戏表格
system("cls");
printf("======C语言控制台版2048游戏======\n");
for (int i = 0; i < 4; i++) {
printf("---------------------------------\n");
for (int j = 0; j < 4; j++) {
if (grid[i][j] == 0) { printf("| \t"); }//打印空数
else printf("| %d\t", grid[i][j]);//打印数字
}
printf("|\n");//换行
}
printf("---------------------------------\n");
gotoXY(18 * 2, 5);//定位输出
printf("目前得分:%d", score);
gotoXY(18 * 2, 7);
printf("《请按四个方向箭头进行操作》");
}
void randomNum() {
srand((unsigned int)time(NULL));
int x = rand() % 4; //随机坐标
int y = rand() % 4;
while (grid[x][y] != 0) {//生成的位置已经有数字就重新生成
x = rand() % 4;
y = rand() % 4;
}
int z = rand() % 5;//概率媒介
if (z == 0)grid[x][y] = 4;//五分之一的概率产生数字4
else grid[x][y] = 2;//五分之四的概率产生数字2
}
//获取格子中的最大的数字
int getMax() {
int max = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (grid[i][j] > max) {
max = grid[i][j];
}
}
}
return max;
}
int gameOver() {
int result = 1;//等于0继续游戏,等于1结束游戏
//计算最大的数为2048时赢得游戏结束
if (getMax() == 2048) {
result = 1;
printf("恭喜你赢得游戏!/n");
system("pause");
}
//判断存在空格子,继续
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (grid[i][j] == 0) result = 0;
break;
}
}
//如果格子都不为空,需要进一步判断相邻格子数字是否相同
if (result == 1) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (i != 0 && grid[i][j] == grid[i - 1][j]) result = 0; //与上面的数比较
if (i != 3 && grid[i][j] == grid[i + 1][j]) result = 0; //与下面的数比较
if (j != 0 && grid[i][j] == grid[i][j - 1]) result = 0;//与左边的数比较
if (j != 3 && grid[i][j] == grid[i][j + 1]) result = 0;//与右边的数比较
}
}
}
return result;
}
//向上划
int toUp() {
int col, row;
int isMove = 0;//默认0不移动,设置为1表明已经移动
for (col = 0; col < 4; col++) {
for (row = 1; row < 4; row++) {//纵向开始
if (grid[row][col] && grid[row - 1][col] == 0) { //本格不为空,上一格数为空,补空位
grid[row - 1][col] = grid[row][col];
grid[row][col] = 0;//补位后置空
//重置row,补位到最终位置
if (row > 1) row -= 2;
isMove = 1;
}
}
//纵向相邻相同的数字则累加合位
for (int row = 1; row < 4; row++) {
if (grid[row][col] && grid[row - 1][col] == grid[row][col]) {//本格不为空,且与上一格数字相同则合并
grid[row - 1][col] *= 2;
score += grid[row][col];
grid[row][col] = 0;//合并完后置空
isMove = 1;
}
}
//合并后再次补空位
for (row = 1; row < 4; row++) {
if (grid[row][col] && grid[row - 1][col] == 0) { //本格数不为空,上一格数为空,补空位
grid[row - 1][col] = grid[row][col];
grid[row][col] = 0;//补位后置空
//重置row,补位到最终位置
if (row > 1) row -= 2;
}
}
}
return isMove;
}
//向下划
int toDown() {
int col, row;
int isMove = 0;//默认0不移动
for (col = 0; col < 4; col++) {
for (row = 2; row >= 0; row--) {//纵向开始
if (grid[row][col] && grid[row + 1][col] == 0) { //本格数不为空,下一格数为空,补空位
grid[row + 1][col] = grid[row][col];
grid[row][col] = 0;//补位后置空
//重置row,补位到最终位置
if (row < 2) row += 2;
isMove = 1;
}
}
//纵向相邻相同的数字则累加合位
for (row = 2; row >= 0; row--) {
if (grid[row][col] && grid[row + 1][col] == grid[row][col]) {//本格不为空,且与下一格数字相同则合并
grid[row + 1][col] *= 2;
score += grid[row][col];
grid[row][col] = 0;//合并完后置空
isMove = 1;
}
}
//合并后再次补空位
for (row = 2; row >= 0; row--) {
if (grid[row][col] && grid[row + 1][col] == 0) { //本格数不为空,下一格数为空,补空位
grid[row + 1][col] = grid[row][col];
grid[row][col] = 0;//补位后置空
//重置row,补位到最终位置
if (row < 2) row += 2;
}
}
}
return isMove;
}
//向左划
int toLeft() {
int col, row;
int isMove = 0;//默认0不移动
for (row = 0; row < 4; row++) {
for (col = 1; col < 4; col++) {//横向开始
if (grid[row][col] && grid[row][col - 1] == 0) { //本格数不为空,左格数为空,补空位
grid[row][col - 1] = grid[row][col];
grid[row][col] = 0;//补位后置空
//重置col,补位到最终位置
if (col > 1) col -= 2;
isMove = 1;
}
}
//横向相邻相同的数字则累加合位
for (int col = 1; col < 4; col++) {
if (grid[row][col] && grid[row][col - 1] == grid[row][col]) {//本格不为空,且与左边数字相同则合并
grid[row][col - 1] *= 2;
score += grid[row][col];
grid[row][col] = 0;//合并完后置空
isMove = 1;
}
}
//合并后再次补空位
for (col = 1; col < 4; col++) {
if (grid[row][col] && grid[row][col - 1] == 0) { //本格数不为空,左格数为空,补空位
grid[row][col - 1] = grid[row][col];
grid[row][col] = 0;//补位后置空
//重置col,补位到最终位置
if (col > 1) col -= 2;
}
}
}
return isMove;
}
//向右划
int toRight() {
int col, row;
int isMove = 0;//默认0不移动
for (row = 0; row < 4; row++) {
for (col = 2; col >= 0; col--) {//横向开始
if (grid[row][col] && grid[row][col + 1] == 0) { //本格数不为空,右格数为空,补空位
grid[row][col + 1] = grid[row][col];
grid[row][col] = 0;//补位后置空
//重置col,补位到最终位置
if (col < 2) col += 2;
isMove = 1;
}
}
//横向相邻相同的数字则累加合位
for (col = 2; col >= 0; col--) {
if (grid[row][col] && grid[row][col + 1] == grid[row][col]) {//本格不为空,且与右边数字相同则合并
grid[row][col + 1] *= 2;
score += grid[row][col];
grid[row][col] = 0;//合并完后置空
isMove = 1;
}
}
//合并后再次补空位
for (col = 2; col >= 0; col--) {
if (grid[row][col] && grid[row][col + 1] == 0) { //本格数不为空,右格数为空,补空位
grid[row][col + 1] = grid[row][col];
grid[row][col] = 0;//补位后置空
//重置col,补位到最终位置
if (col < 2) col += 2;
}
}
}
return isMove;
}
//接收移动按键并刷新格子移动
void moveDirection() {
int ch = _getch();
switch (ch) {
//向上箭头 224 72 判断接收两次
case 72: //上划
if (toUp() == 1) {
randomNum();
printGrid();
}
break;
//向下箭头 224 80 判断接收两次
case 80://下划
if (toDown() == 1) {
randomNum();
printGrid();
}
break;
//向左箭头 224 75 判断接收两次
case 75: //左划
if (toLeft() == 1) {
randomNum();
printGrid();
}
break;
//向右箭头 224 77 判断接收两次
case 77://右划
if (toRight() == 1) {
randomNum();
printGrid();
}
break;
default:break;
}
}
void playGame() { //开始游戏
int flag = 1;
while (flag) {
//初始化格子,设置为0
memset(grid, 0, sizeof(grid));
//产生两个随机数字
randomNum();
randomNum();
//打印格子
printGrid();
//游戏没有结束就可以一直操作,1是结束游戏
while (gameOver() == 0) {
//接收移动按键并进行移动
moveDirection();
}
system("cls");
printf("游戏结束,您的分数为:%d\n", score);
printf("按y继续游戏,按n退出游戏!\n");
//切换英文输入法
keybd_event(VK_SHIFT, 0, 0, 0);
Sleep(100);
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
int mark = 1;
while (mark) {
//接收按键
char ch = _getch();
if (ch == 'y' || ch == 'Y') {
flag = 1;
mark = 0;
score = 0;
}
else if (ch == 'n' || ch == 'N') {
system("cls");
printf("欢迎下次来玩!\n");
system("pause");
exit(1);
}
else {
printf("输入错误,请重新输入!\n");
}
}
}
}
int main() {
//进行2048游戏
playGame();
system("pause");
return 0;
}