参考文档
借助了这位大佬的开发思路, 开发过程中学到了很多
C语言实现《2048游戏》
技术点:
system调整控制台大小的问题
unsigned and 符号位
C++对齐输出(左对齐和右对齐)
C++ goto语句详解
完整代码
/*********************************************************************
程序名: 贪吃蛇
*********************************************************************/
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#include <iostream> // 对应c中的#include <stdio.h>
#include <cstdlib> // 对应C中的#include <stdlib.h>
#include <ctime> // 对应c中的#include <time.h>
#include <conio.h> // 使用getch()函数
#include <windows.h> //使用Sleep()函数
#include <iomanip> // C++ 输出对齐函数
#include <fstream> // 文件操作头函数
using namespace std;
void Menu();//菜单
void Rule_of_game();//游戏规则
void Begin(); //开始
void Table();//打印4×4方格
int Random_number1();//产生2或4的随机数
int Random_number2();//产生0、1、2、3的随机数
int Get(int *p_cnt, int score);//输入指令
void Move();//保留上一次的棋盘布局
int If_move();//判断是否移动
int Over();//判断是否结束
void Write_max(int score);//向2048游戏-最高记录写入最高分
int Read_max();//读出最高分记录的文件
void Write_file(int *p_cnt, int scort);//存档
int Read_file(int *p_cnt);//读档
void again();//是否继续游戏
int color(int c);//更改颜色
void box_color(int x);//不同数值对应不同颜色
int a[4][4] = { 0 };// 定义全局的二维数组
int A[4][4]; //保留上一步的棋局
char *name_max = "2048游戏-最高记录.txt";
char *name_file = "[山海]-2048游戏.txt";
int main()
{
system("mode con cols=90 lines=30"); //调整控制台大小
system("title 2048超级大大型游戏"); //程序标题
system("color F0");//F 表示背景颜色,0表示前景颜色
Menu();
system("PAUSE");
return 0;
}
void Menu() //菜单
{
cout << "\t\t║ 欢迎使用由[山海]制作的2048超级大大型游戏 ║\n";
cout << "\t\t╟──────────────────────────────────────────────╢\n";
cout << "\t\t║请输入选项: ║\n";
cout << "\t\t║ ┌───┐ ║\n";
cout << "\t\t║ │ 1 │ 游戏规则 ║\n";
cout << "\t\t║ └───┘ ║\n";
cout << "\t\t║ ┌───┐ ║\n";
cout << "\t\t║ │ 2 │ 开始游戏 ║\n";
cout << "\t\t║ └───┘ ║\n";
cout << "\t\t║ ┌───┐ ║\n";
cout << "\t\t║ │ 3 │ 继续游戏 ║\n";
cout << "\t\t║ └───┘ ║\n";
cout << "\t\t║ ┌───┐ ║\n";
cout << "\t\t║ │ 4 │ 退出游戏 ║\n";
cout << "\t\t║ └───┘ ║\n";
cout << "\t\t╚══════════════════════════════════════════════╝\n";
int x = 1, max = 0;
while (x)
{
switch (getch()) // getch()函数检测按键。
{
case '1':
x = 0;
Rule_of_game();//游戏规则
Menu();
break;
case '2':
x = 0;
system("cls");//清屏
int h, l;
for (h = 0; h < 4; h++)
{
for (l = 0; l < 4; l++)
{
a[h][l] = 0;
A[h][l] = 0;
}
}
Begin(); //开始游戏
break;
case '3':
x = 0;
system("cls");//清屏
max = Read_max();//读取之前的最高记录
Begin(); //开始游戏
break;
case '4':
exit(0);
default:
cout << "输入了非法选项,请重新选择!" << endl;
}
}
}
void Rule_of_game()
{
system("cls");//清屏
cout << "╔══════════════════════════════════════════════════════════════════════════════════╗" << endl;
cout << "║本游戏通过按键W、S、A、D(不区分大小写)四个键分别控制滑块上移、下移、左移和右移。 ║" << endl;
cout << "║滑块移动的过程中,如有相邻且相等数字的滑块将会相加,并获得相应的分数。 ║" << endl;
cout << "║当棋盘上的所有位置均有数字,且不能合成,则游戏结束。本游戏未设置游戏成功。 ║"<< endl;
cout << "║游戏过程中输入I即为存档并退出游戏,输入O即为读档,输入P则退出游戏。 ║"<< endl;
cout << "║“开始游戏”则清除最高记录及存档、“继续游戏”则保存之前的最高记录,且可以读档。 ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════════════════════════╝" << endl;
system("pause");//暂停
system("cls");//清屏
}
void Begin()
{
int score = 0;
int sign = 1;
int h, l, cnt = 0;
int *p_cnt = &cnt;
while (1)
{
cout << "\t\t╔══════════════════════════════════════════════╗" << endl;
cout << "\t\t║ 欢迎使用由[山海]制作的2048超级大大型游戏 ║" << endl;
cout << "\t\t╟──────────────────────────────────────────────╢" << endl;
cout << "\t\t║移动: ┌───┐ 存档: 读档: 退出: ║" << endl;
cout << "\t\t║ │ W │ ║" << endl;
cout << "\t\t║ ┌───┼───┼───┐ ┌───┐ ┌───┐ ┌───┐ ║" << endl;
cout << "\t\t║ │ A │ S │ D │ │ I │ │ O │ │ P │ ║" << endl;
cout << "\t\t║ └───┴───┴───┘ └───┘ └───┘ └───┘ ║" << endl;
cout << "\t\t╚══════════════════════════════════════════════╝" << endl;
while (1)
{
if (sign == 1){
h = Random_number2();
l = Random_number2();
if (a[h][l] == 0) {
a[h][l] = Random_number1();
cnt++;
break;
}
}
else{
break;
}
}
Table(); // 打印棋盘
int max = Read_max();
printf("\t\t移动的步数:%d\t当前得分:%d\n\t\t最高记录:%d\n", cnt - 1, score, max);
Move(); //保留棋盘
score += Get(p_cnt, score);//得分
if (score > max)
{
Write_max(score);//保存此次记录
}
sign = If_move();//判断棋盘是否有变动
if (Over() == 0){
if (max < score){//打破记录
Write_max(score);//保存此次记录
cout << "\t\t恭喜您已打破记录!" << endl;
}
break;
}
system("cls"); //清屏
}
}
int Get(int *p_cnt,int score)
{
int h, l, t, sum = 0;
char ch;
ch = getch();//输入字符
switch (ch){
/*滑块向上移动*/
case 'w':
case 'W':
/*向上聚集数字*/
for (l = 0; l < 4; l++){
for (t = 0; t < 4; t++){
for (h = 3; h > 0; h--){
if (a[h - 1][l] == 0){
a[h - 1][l] = a[h][l];
a[h][l] = 0;
}
}
}
}
/*竖直方向上,相邻且相同的数字相加*/
for (l = 0; l < 4; l++){
for (h = 0; h < 3; h++){
if (a[h][l] == a[h + 1][l]){
a[h][l] += a[h + 1][l];
a[h + 1][l] = 0;
sum += a[h][l];
}
}
}
/*向上聚集数字*/
for (l = 0; l < 4; l++){
for (t = 0; t < 4; t++){
for (h = 3; h > 0; h--){
if (a[h - 1][l] == 0){
a[h - 1][l] = a[h][l];
a[h][l] = 0;
}
}
}
}
break;
case 's':
case 'S':
for (l = 0; l < 4; l++){
for (t = 0; t < 4; t++){
for (h = 0; h < 3; h++){
if (a[h + 1][l] == 0){
a[h + 1][l] = a[h][l];
a[h][l] = 0;
}
}
}
}
for (l = 0; l < 4; l++){
for (h = 3; h > 0; h--){
if (a[h][l] == a[h - 1][l]){
a[h][l] += a[h - 1][l];
a[h - 1][l] = 0;
sum += a[h][l];
}
}
}
for (l = 0; l < 4; l++){
for (t = 0; t < 4; t++){
for (h = 0; h < 3; h++){
if (a[h + 1][l] == 0){
a[h + 1][l] = a[h][l];
a[h][l] = 0;
}
}
}
}
break;
case 'a':
case 'A':
for (h = 0; h < 4; h++){
for (t = 0; t < 4; t++){
for (l = 3; l > 0; l--){
if (a[h][l - 1] == 0){
a[h][l - 1] = a[h][l];
a[h][l] = 0;
}
}
}
}
for (h = 0; h < 4; h++){
for (l = 0; l < 3; l++){
if (a[h][l] == a[h][l + 1]){
a[h][l] += a[h][l + 1];
a[h][l + 1] = 0;
sum += a[h][l];
}
}
}
for (h = 0; h < 4; h++){
for (t = 0; t < 4; t++){
for (l = 3; l > 0; l--){
if (a[h][l - 1] == 0){
a[h][l - 1] = a[h][l];
a[h][l] = 0;
}
}
}
}
break;
case 'd':
case 'D':
for (h = 0; h < 4; h++){
for (t = 0; t < 4; t++){
for (l = 0; l < 3; l++){
if (a[h][l + 1] == 0){
a[h][l + 1] = a[h][l];
a[h][l] = 0;
}
}
}
}
for (h = 0; h < 4; h++){
for (l = 3; l > 0; l--){
if (a[h][l] == a[h][l - 1]){
a[h][l] += a[h][l - 1];
a[h][l - 1] = 0;
sum += a[h][l];
}
}
}
for (h = 0; h < 4; h++){
for (t = 0; t < 4; t++){
for (l = 0; l < 3; l++){
if (a[h][l + 1] == 0){
a[h][l + 1] = a[h][l];
a[h][l] = 0;
}
}
}
}
break;
case 'i':
case 'I': //存档当前游戏格局
Write_file(p_cnt, score);//调用存档函数
break;
case 'o':
case 'O':
sum = Read_file(p_cnt);//读档
break;
case 'p':
case 'P':
system("cls"); //清屏
Menu();//回到菜单
default:
break;
}
return sum;
}
void Table()
{
int h, l;
for (h = 0; h < 4; h++){
if (h == 0){
printf("\t\t\t┏━━━━━━┳━━━━━━┳━━━━━━┳━━━━━━┓\n");
}
else {
printf("\t\t\t┣━━━━━━╋━━━━━━╋━━━━━━╋━━━━━━┫\n");
}
printf("\t\t\t┃ ┃ ┃ ┃ ┃\n");
for (l = 0; l < 4; l++){
if (a[h][l] == 0){//如果二维数组与棋盘对应的位置为零,则不放入数据
if (l == 0){
printf("\t\t\t┃ ");
}
else {
printf("┃ ");
}
}
else{//否则放入与二维数组对应的数据
if (l == 0){
printf("\t\t\t┃");
box_color(a[h][l]);//判断滑块的数值,给对应颜色
printf("%5d ", a[h][l]);
color(0);//恢复白色背景
}
else {
printf("┃");
box_color(a[h][l]);//判断滑块的数值,给对应颜色
printf("%5d ", a[h][l]);
color(0);//恢复白色背景
}
}
}
printf("┃\n");
printf("\t\t\t┃ ┃ ┃ ┃ ┃\n");
}
printf("\t\t\t┗━━━━━━┻━━━━━━┻━━━━━━┻━━━━━━┛\n");
}
int Random_number1() //随机生成2 or 4
{
int s;
srand(time(0));
s = ((unsigned)rand() % 2);
s = s == 0 ? 2 : 4;
return s;
}
int Random_number2() //随机生成二维数组的下标
{
int x;
x = ((unsigned)rand() % 4);
return x;
}
void Move()
{
int h, l;
for (h = 0; h < 4; h++){
for (l = 0; l < 4; l++){
A[h][l] = a[h][l];
}
}
}
int If_move()
{
int h, l, sign = 0;
for (h = 0; h < 4; h++){
for (l = 0; l < 4; l++){
if (a[h][l] != A[h][l]){//未进入条件框,说明滑块没有发生移动
sign = 1;
goto out;
}
}
}
out:
return sign;
}
int Over()
{
int over = 0;
int h, l;
for (h = 0; h < 4; h++){
for (l = 0; l < 4; l++){
if (a[h][l] == 0){//有空格
over = 1;//游戏继续
return 1;
}
}
}
if (over == 0){//没有空格
for (h = 0; h < 3; h++){
for (l = 0; l < 3; l++){
if (a[h][l] == a[h][l + 1]){
over = 1;//游戏继续
break;
}
else if (a[h][l] == a[h + 1][l]){
over = 1;//游戏继续
break;
}
}
if (over == 1){
break;
}
}
}
return over;//游戏结束
}
void Write_max(int score)//写入文件
{
ofstream fout(name_max); //读写操作,对打开的文件可进行读写操作
fout << score;
fout.close();
}
int Read_max() // 读取文件
{
int max_score = 0;
ifstream fin(name_max, ios::in);
if (!fin)
{
cout << "\t\t读取失败!程序即将自动退出 . . .";
Sleep(3000);//睡眠3000毫秒,即停留3秒钟
exit(0); //退出程序
}
else
{
fin >> max_score;
fin.close();
}
return max_score;//返回最高记录的值
}
void Write_file(int *p_cnt, int score)
{
int h, l;
ofstream fout(name_file);
if (!fout)
{
cout << "\t\t存档失败!程序即将自动退出 . . ." << endl;
Sleep(3000);//睡眠3000毫秒,即停留3秒钟
exit(0);
}
else
{
for (h = 0; h < 4; h++){
for (l = 0; l < 4; l++){
fout << a[h][l] << " ";
}
}
}
fout << score << " ";
fout << *p_cnt - 1;
cout << "\t\t存档成功!游戏即将自动退出 . . ." << endl;
Sleep(3000); //睡眠3000毫秒,即停留3秒钟
exit(0);
fout.close();
}
int Read_file(int *p_cnt)
{
int h, l, score = 0;
ifstream fin(name_file , ios::in);
if (!fin)
{
cout << "\t\t读档失败!程序即将自动退出 . . ." << endl;
Sleep(3000); //睡眠3000毫秒,即停留3秒钟
exit(0);
}
else
{
for (h = 0; h < 4; h++){
for (l = 0; l < 4; l++){
fin >> a[h][l];
}
}
}
fin >> score;
fin >> *p_cnt;
fin.close();
Table(); // 打印棋盘
return score;
}
void again()
{
cout << "\t\t╔══════════════════════════════════════════════╗" << endl;
cout << "\t\t║ 您已失败 ║" << endl;
cout << "\t\t╟──────────────────────────────────────────────╢" << endl;
cout << "\t\t║是否继续: ║" << endl;
cout << "\t\t║ ┌───┐ ║" << endl;
cout << "\t\t║ │ 1 │ 扶我起来,我还能再来一局! ║" << endl;
cout << "\t\t║ └───┘ ║" << endl;
cout << "\t\t║ ┌───┐ ║" << endl;
cout << "\t\t║ │ 2 │ 不了不了,我要学习! ║" << endl;
cout << "\t\t║ └───┘ ║" << endl;
cout << "\t\t╚══════════════════════════════════════════════╝" << endl;
if (getch() == '1'){
system("cls"); // 清屏
int h, l;
for (h = 0; h < 4; h++)
{
for (l = 0; l < 4; l++)
{
a[h][l] = 0;
A[h][l] = 0;
}
}
Menu();//回到菜单
}
else {
cout << "\t\t游戏结束!" << endl;
}
}
int color(int c)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
BACKGROUND_INTENSITY |
BACKGROUND_BLUE |
BACKGROUND_RED |
BACKGROUND_GREEN |
c);
return 0;
}
void box_color(int x)
{
switch (x){
case 2:
color(8);
break;
case 4:
color(0);
break;
case 8:
color(2);
break;
case 16:
color(6);
break;
case 32:
color(10);
break;
case 64:
color(3);
break;
case 128:
color(9);
break;
case 256:
color(11);
break;
case 512:
color(5);
break;
case 1024:
color(13);
break;
case 2048:
color(12);
break;
default:
color(4);
break;
}
}
运行示例