【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

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而