鱼C论坛

 找回密码
 立即注册
查看: 1501|回复: 0

[技术交流] C语言,2048游戏文字版,流程逻辑思路,代码详解(中)

[复制链接]
发表于 2021-5-12 16:14:36 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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);
        }
    }
}



现在开始实现⑥部分的数字合并部分,也是整个游戏的逻辑核心。首先看图。

移动合并.png


首先看左侧,游戏往上移动。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;
}




想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-6-16 03:58

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表