马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 Stubborn 于 2021-5-12 18:01 编辑
C语言,2048游戏文字版,流程逻辑思路,代码详解(中)
上一篇已经实现了大部分的绘制函数,这部分开始实现游戏的逻辑函数
⑤bool GeneratingRandomNumbers(struct Game *);大致逻辑是,随机生成2或者4,都是1/2的概率,然后随机生成一个索引,在数据列表中为0的位置跟新bool GeneratingRandomNumbers(struct Game *data){
/**Generate a random number and place it in a random position where the data parameter is not 0。
*If the modification is successful, return true; otherwise, return false。
*/
srand(time(NULL));
short value = ((const short []){2, 4})[randint(2)];
size_t randomIndex = (size_t) randint(data->length);
data->score += value;
data->move += 1;
for (size_t rightIndex = randomIndex; rightIndex < data->length; ++rightIndex)
{
if (data->arr[rightIndex]==0)
{
data->arr[rightIndex] = value;
return true;
}
}
for (size_t leftIndex = randomIndex; leftIndex > 0; --leftIndex)
{
if (data->arr[leftIndex]==0)
{
data->arr[leftIndex] = value;
return true;
}
}
return false;
}
好了,写到这里,开始回顾一下,实现的什么功能,以及程序的运行流程。
1.程序运行,展示一个欢迎界面,并提供输入选择。
2.输入对应的选择会有对应的界面
3.选择开始游戏后,生成一个随机数,并且打印出游戏界面。
那么接下来,我们就应该编写监听键盘的输入的函数,并实现⑥数字的移动以及合并选择。
首先是监听键盘的输入的函数bool JudgmentInput(int, struct Game *);
根据对应的键盘操作,调用不同的移动函数,当游戏可以发生移动,或者合并的时候,返回一个true。否则返回一个false。
其次当操作成功之后,在生成一个随机数,操作失败检测下当前游戏是不是可以结束,即当前游戏不能发生移动,合并的情况。
不管成功或者失败,都看下有没有到胜利条件,看下合成的数字有没有到2048。然后再次绘制游戏界面,跟新游戏状态。
函数bool JudgmentInput(int, struct Game *); 实现的逻辑是:
当键盘发生了上下左右的操作,调用对应的移动合并操作。
如果移动合并操作失败,或者发生其他的操作,检查游戏是不是结束,或者胜利。
再次打印游戏界面bool JudgmentInput(int key, struct Game *data){
bool flag = false;
switch (key) { ////LEFT = 75, UP = 72, RIGHT = 77, DOWN = 80, Esc=27
case 72:
flag = MoveUp(data);
break;
case 80:
flag = MoveDown(data);
break;
case 75:
flag = MoveLeft(data);
break;
case 77:
flag = MoveRight(data);
break;
case 27:
exit(0);
}
if (flag){
GeneratingRandomNumbers(data);
} else {
DrawLoser(data);
}
DrawWin(*data);
DrawTheGameBox(*data);
return flag;
}
在void StartGame()函数里面死循环,监听键盘操作void StartGame(){
/**Start the game, run the logic of the game
* */
bool True = true;
struct Game data= {16, {0}, 0, 0, 0, time(NULL)};
struct Game *p = &data;
GeneratingRandomNumbers(p);
DrawTheGameBox(data);
// 监听键盘
while (True)
{
while (kbhit())
{
JudgmentInput(getch(), p);
}
}
}
现在开始实现⑥部分的数字合并部分,也是整个游戏的逻辑核心。首先看图。
首先看左侧,游戏往上移动。2048游戏的逻辑是什么?
数字向上移动,如果相邻的两个各自数字一样,则合并成一个新数字。
所以我们实现的逻辑是什么?具体如何实现?
我们需要实现数字移动,以及数字的合并。
怎么移动数字,一个最基本的逻辑 ,当遍历到数值为0的时候,那么表明这个位置可以被填充的,0下方的数字都可以移动。用编程表达就是这两个位置可以交换arr[index] = arr[index-4];
arr[index-4] = 0;
注意,因为我这里使用的是一维数组,表达方式不一样。实际看个人的数据进行表达。一定要注意数组的越界,我们应该遍历到第三层就停止遍历。
当我们整个遍历一次后,会发生什么?可以移动的数字,全部往上移动了一层。那么我们重复这个步骤,那么就可以全部进行移动
怎么进行数字的合并。和移动数字的逻辑差不多,当遍历数组的时候,发现当前遍历的索引index 和 index + 4 值一样,即上下两个值一样,就可以进行合并。用编程表达就是这两个位置发生改变:arr[index] *= 2;
arr[index-4] = 0;
合并之后,又会出现 0 的空位,此时我们再次调用移动函数,进行移动即可完成一次的移动操作bool _MoveUp(struct Game *data){
bool flag = false;
for (size_t _index = 4; _index < data->length; _index+=4)
{
for (size_t index = 4; index < data->length; ++index)
{
if (data->arr[index-4] == 0 && data->arr[index] !=0)
{
data->arr[index-4] = data->arr[index];
data->arr[index] = 0;
flag = true;
}
}
}
return flag;
}
bool MoveUp(struct Game *data){
// 上移操作,需要实现的逻辑有,数字的移动以及合并,是否是有效的移动
bool flag = false;
flag = _MoveUp(data);
for (size_t index = 0; index < data->length-4; ++index) {
if (data->arr[index] == data->arr[index+4] && data->arr[index] != 0)
{
data->arr[index] *= 2;
if (data->arr[index] > data->max){
data->max = data->arr[index];
}
data->arr[index+4] = 0;
flag = true;
}
}
_MoveUp(data);
return flag;
}
bool _MoveLeft(struct Game *data)
{
bool flag = false;
for (size_t _index = 4; _index < data->length; _index+=4)
{
for (size_t index = 0; index < data->length; index+=4)
{
for (size_t i = 0; i < 4 - 1; ++i)
{
if (data->arr[index + i] == 0 && data->arr[index+i+1] != 0)
{
data->arr[index+i] = data->arr[index+i+1];
data->arr[index+i+1] = 0;
flag = true;
}
}
}
}
return flag;
}
bool MoveLeft(struct Game *data)
{
bool flag = false;
flag = _MoveLeft(data);
for (size_t index = 0; index < data->length; index+=4)
{
for (size_t i = 0; i < 4 - 1; ++i)
{
if (data->arr[index + i] == data->arr[index + i + 1] && data->arr[index + i] != 0)
{
data->arr[index+i] *= 2;
if (data->arr[index+i] > data->max){
data->max = data->arr[index+i];
}
data->arr[index+i+1] = 0;
flag = true;
}
}
}
_MoveLeft(data);
return flag;
}
bool _MoveRight(struct Game *data)
{
bool flag = false;
for (size_t _index = 4; _index < data->length; _index+=4)
{
for (size_t index = 3; index < data->length; index+=4) // 3 7 11 15
{
for (size_t i = 0; i < 4 - 1; ++i)
{
if (data->arr[index - i] == 0 && data->arr[index-i-1] != 0)
{
data->arr[index - i] = data->arr[index-i-1];
data->arr[index- i -1] = 0;
flag = true;
}
}
}
}
return flag;
}
bool MoveRight(struct Game *data)
{
bool flag = false;
flag = _MoveRight(data);
for (size_t index = 3; index < data->length; index+=4) // 3 7 11 15
{
for (size_t i = 0; i < 4 - 1; ++i)
{
if (data->arr[index - i] == data->arr[index- i -1] && data->arr[index- i -1] != 0) // 0 1 2
{
data->arr[index - i] *= 2;
if (data->arr[index-i] > data->max){
data->max = data->arr[index-i];
}
data->arr[index- i -1] = 0;
flag = true;
}
}
}
_MoveRight(data);
return flag;
}
bool _MoveDown(struct Game *data)
{
bool flag = false;
for (size_t _index = 4; _index < data->length; _index+=4)
{
for (size_t index = data->length - 1; index >= 4; --index)
{
if (data->arr[index] == 0 && data->arr[index-4] !=0)
{
data->arr[index] = data->arr[index-4];
data->arr[index-4] = 0;
flag = true;
}
}
}
return flag;
}
bool MoveDown(struct Game *data)
{
bool flag = false;
flag = _MoveDown(data);
for (size_t index = data->length - 1; index >= 4; --index)
{
if (data->arr[index] == data->arr[index-4] && data->arr[index-4] !=0)
{
data->arr[index] *=2 ;
if (data->arr[index] > data->max){
data->max = data->arr[index];
}
data->arr[index-4] = 0;
flag = true;
}
}
_MoveDown(data);
return flag;
}
|