C的简单新手小游戏练习,知识基本是数组,用到指针的比较少,代码含有少量简单的C++,个人认为2048的核心是数字的移动与合并,其次是玩家有效操作的判断,与井字棋有点像。
代码实现了2048的基本功能,数字移动、合并、随机数产生在随机空白位置、有效操作判定、步数记录、得分情况、放弃本局游戏,以及通过修改宏定义常量值能玩更大的棋盘。如果加入文件的读写应该可以多一个排行榜功能。
目前存在情况是随着数字的位数增加界面框会歪斜,以及在游戏菜单界面输入字母直接退出。
代码如下
game.h 文件
#pragma once
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define ROW 4
#define COL 4
extern void Intialize(int (*p)[COL]);
extern void Checkerboard(int (*p)[COL]);
extern void Random(int (*p)[COL],int k);
extern void MoveAss(int(*p)[COL], int i, int j,char o);
//extern void Valid(int(*p)[COL],char o,char q,int* g);
//extern void Valid(int(*p)[COL], char o, int q);
extern int Move(int(*p)[COL], char o);
extern void Operate(int (*p)[COL],int k,int* c,int* g);
extern int Criterion(int (*p)[COL]);
extern void Progress(int (*p)[COL]);
game.cpp 文件
#include "game.h"
//界面初始化
void Intialize(int (*p)[COL])
{
int i = 0;
int j = 0;
for (i = 0; i < ROW; i++)//遍历
{
for (j = 0; j < COL; j++)
p[i][j] = 0;
}
}
//打印界面
void Checkerboard(int (*p)[COL])
{
int i = 0;
int j = 0;
for (i = 0; i < ROW; i++)
{
for (j = 0; j < COL; j++)
{
if (j == COL - 1)
{
if (p[i][j])
cout << ' ' << p[i][j];
else
cout << ' ' << ' ';//掩盖 0
}
else
{
if (p[i][j])
cout << ' ' << p[i][j] << ' ' << '|';//打印 p[][] | 单元
else
cout << ' ' << ' ' << ' ' << '|';//掩盖 0
}
}
cout << endl;
for (j = 0; j < COL; j++)
{
if (i != ROW-1)
cout << "----";//打印 --- 单元
if (j == COL - 1)
cout << endl;
}
}
cout << endl;
}
//在界面随机生成一个2/4数字
void Random(int (*p)[COL],int k)
{
int x = 0;
int y = 0;
if (k != 2048)
{
if (k)
{
while (1)//生成一个随机数
{
x = rand() % ROW;
y = rand() % COL;
if (p[x][y] == 0)//寻找空位
{
p[x][y] =(rand() % 2 + 1) * 2;
break;//(rand()%2+1)*2随机生成2/4数字
}
}
}
if (k != ROW * COL)
Checkerboard(p);//在界面上显示
}
}
//辅助移动
void MoveAss(int(*p)[COL],int i,int j,char o)
{
switch (o)
{
case 'w':
{
if (p[i][j])
{
if ((i != 0)&&(i <= ROW-1))
{
if (p[i - 1][j] == 0)
{
p[i - 1][j] = p[i][j];
p[i][j] = 0;
MoveAss(p, i + 1, j, o);//递归调用
}
}
}
break;
}
case 's':
{
if (p[i][j])
{
if ((i != ROW-1)&&(i >= 0))
{
if (p[i + 1][j] == 0)
{
p[i + 1][j] = p[i][j];
p[i][j] = 0;
MoveAss(p, i - 1, j, o);//递归调用
}
}
}
break;
}
case 'a':
{
if (p[i][j])
{
if ((j != 0)&&(j <= COL - 1))
{
if (p[i][j - 1] == 0)
{
p[i][j - 1] = p[i][j];
p[i][j] = 0;
MoveAss(p, i, j + 1, o);//递归调用
}
}
}
break;
}
case 'd':
{
if (p[i][j])
{
if ((j != ROW - 1)&&(j >= 0))
{
if (p[i][j + 1] == 0)
{
p[i][j + 1] = p[i][j];
p[i][j] = 0;
MoveAss(p, i, j - 1, o);//递归调用
}
}
}
break;
}
}
}
//数字移动与合并
int Move(int (*p)[COL],char o)
{
int i = 0;
int j = 0;
int g = 0;
switch (o)
{
case 'w':
{
for (i = ROW - 1; i >= 0; i--)//移动
{
for (j = COL - 1; j >= 0; j--)
{
MoveAss(p, i, j, o);
}
}
for (i = 0; i < ROW-1; i++)//合并
{
for (j = 0; j < COL; j++)
{
if (p[i][j] == p[i + 1][j])
{
p[i][j] = 2 * p[i][j];
g = g + p[i][j];
p[i + 1][j] = 0;
}
}
}
for (i = ROW - 1; i >= 0; i--)//移动
{
for (j = COL - 1; j >= 0; j--)
MoveAss(p,i,j,o);
}
break;
}
case 's':
{
for (i = 0; i < ROW; i++)//移动
{
for (j = 0; j < COL; j++)
{
MoveAss(p, i, j, o);
}
}
for (i = ROW-1; i > 0; i--)//合并
{
for (j = 0; j < COL; j++)
{
if (p[i][j] == p[i - 1][j])
{
p[i][j] = 2 * p[i][j];
g = g + p[i][j];
p[i - 1][j] = 0;
}
}
}
for (i = 0; i < ROW; i++)//移动
{
for (j = 0; j < COL; j++)
MoveAss(p, i, j, o);
}
break;
}
case 'a':
{
for (j = COL - 1; j >= 0; j--)//移动
{
for (i = ROW - 1; i >= 0; i--)
{
MoveAss(p, i, j, o);
}
}
for (j = 0; j < COL - 1; j++)//合并
{
for (i = 0; i < ROW; i++)
{
if (p[i][j] == p[i][j + 1])
{
p[i][j] = 2 * p[i][j];
g = g + p[i][j];
p[i][j + 1] = 0;
}
}
}
for (j = COL - 1; j >= 0; j--)//移动
{
for (i = ROW - 1; i >= 0; i--)
MoveAss(p, i, j, o);
}
break;
}
case 'd':
{
for (j = 0; j < COL; j++)//移动
{
for (i = 0; i < ROW; i++)
{
MoveAss(p, i, j, o);
}
}
for (j = COL-1; j > 0; j--)//合并
{
for (i = 0; i < ROW; i++)
{
if (p[i][j] == p[i][j - 1])
{
p[i][j] = 2 * p[i][j];
g = g + p[i][j];
p[i][j - 1] = 0;
}
}
}
for (j = 0; j < COL; j++)//移动
{
for (i = 0; i < ROW; i++)
MoveAss(p, i, j, o);
}
break;
}
}
return g;
}
//有效移动判定
int Valid(int (*p)[COL],char o,char q,int* g)//重载,通过参数为字符还是整形来调用同名的不同函数
{
int arr1[ROW][COL];
int i = 0;
int j = 0;
int v = 0;
for (i = 0; i < ROW; i++)//拷贝一份
{
for (j = 0; j < COL; j++)
{
arr1[i][j] = p[i][j];
}
}
*g = *g + Move(p, o);
for (i = 0; i < ROW; i++)
{
for (j = 0; j < COL; j++)
{
if (arr1[i][j] != p[i][j])
{
v = 1;
break;
}
}
if (v == 1)
break;
}
return v;
}
int Valid(int(*p)[COL], char o,int q)//重载,通过参数为字符还是整形来调用同名的不同函数
{
int arr1[ROW][COL];
int i = 0;
int j = 0;
int v = 0;
for (i = 0; i < ROW; i++)//拷贝一份
{
for (j = 0; j < COL; j++)
{
arr1[i][j] = p[i][j];
}
}
Move(arr1, o);
for (i = 0; i < ROW; i++)
{
for (j = 0; j < COL; j++)
{
if (arr1[i][j] != p[i][j])
{
v = 1;
break;
}
}
if (v == 1)
break;
}
return v;
}
//玩家操作
void Operate(int (*p)[COL],int* k,int* c,int* g)
{
char o = '0';
char ret[20];
while (1)
{
cout << "请输入:" << endl;
cin >> ret;
o = ret[0];//只读取输入的第一个字符
if (o == 'w' || o == 's' || o == 'a' || o == 'd')
{
if (Valid(p, o, 'q', g))
{
*c = *c + 1;
break;
}
else
cout << "无效移动" << endl;
}
else if (o == '0')
break;
else
cout << "输入错误" << endl;
}
if (o == '0')
*k = -1;
else
Checkerboard(p);
}
//游戏结束判定
int Criterion(int (*p)[COL])
{
int i = 0;
int j = 0;
int k = COL * ROW;//空格剩余数
for (i = 0; i < ROW; i++)
{
for (j = 0; j < COL; j++)
{
if (p[i][j] == 2048)//胜利
{
k = 2048;
break;
}
if (p[i][j] != 0)
k--;
}
if (k == 2048)
break;
}
return k;
}
//控制游戏进程
void Progress(int (*p)[COL])
{
int k = ROW * COL;//初始空格数
int count = 0;
int grade = 0;
Random(p,k);
while(1)
{
k = Criterion(p);
Random(p,k);
if ((k > 0) && (k != 2048))
k = k - 1;
if (k == 2048)
{
cout << "恭喜,你赢了!" << endl;
break;
}
if (k == 0)
{
if ((Valid(p, 'w',1) || Valid(p, 's',1) || Valid(p, 'a',1) || Valid(p, 'd',1)) == 0)
{
cout << "很遗憾,你输了。" << endl;
break;
}
}
Operate(p, &k,&count,&grade);
if (k == -1)
{
cout << "已放弃当前游戏。" << endl;
break;
}
cout << "步数: " << count << " ";
cout << "分数: " << grade << endl << endl;
}
}
test.cpp 文件
#include "game.h"
void nume()
{
cout << endl;
cout << "*****************************" << endl;
cout << "****** 2 0 4 8 *******" << endl;
cout << "****** 1:paly *******" << endl;
cout << "****** 0:exit *******" << endl;
cout << "*****************************" << endl << endl;
}
void game()
{
int ARR[ROW][COL] = {0};
int (*p)[COL] = ARR;
Intialize(p);
//Checkerboard(p);
Procgress(p);
}
void select()
{
int input = 0;
do
{
nume();
srand((unsigned int)time(NULL));
cout << "请选择" << endl << endl;
cin >> input;
cout << endl;
switch (input)
{
case 1:
cout << "开始游戏" << endl << endl;
cout << " w:上移 s:下移" << endl << endl;
cout << " a:左移 d:右移" << endl << endl;
cout << " 0:放弃当前游戏" << endl << endl;
game();
break;
case 0:
cout << "退出" << endl;
break;
default:
cout << "选择错误,请重新选择" << endl<<endl;
break;
}
} while (input);
}
int main()
{
srand((unsigned int)time(NULL));
select();
return 0;
}