0基础学习C++做贪吃蛇,边玩边学习!(五)for循环和作用域——可长可短的蛇

点击链接回顾前几篇:
(一)标准输出cout——一条安静的蛇
(二)代码详解和Sleep()——蛇之闪现
(三)SetConsoleCursorPosition光标移动效果——一条前进的蛇
(四)预定义和函数调用——妄图得分的蛇
在前几篇中,我们学习了如何用cout()输出字符串到屏幕,如何用Sleep()实现闪现,如何用SetConsoleCursorPosition()让蛇前进,以及关于预处理命令#define函数的相关知识。

接下来,我们将学习在循环中快捷地打印蛇身图案。

    for (int i = 0;i < 5;i++) {
        SetConsoleCursorPosition(handle, { i,i });
        cout << BodySymbol;
    }

for是C++关键字,用来定义一个循环

可以看到,for的()中有三个表达式,用分号隔开,我们称之为表达式一,表达式二,表达式三。大括号{}内的部分叫循环体

如图:

for (语句一;语句二;语句三){
    循环体
}

我们知道,程序一般是顺序执行的,那么for循环是如何执行的呢?

Created with Raphaël 2.3.0 开始 语句一 语句二 循环体 语句三 结束 yes no
可以看到,当程序运行到for循环时,先执行语句一(预处理语句),然后判断语句二是否成立(非0即为成立),若成立,进入循环,循环体执行一遍过后执行语句三(通常是控制条件语句),然后再判断语句二是否成立,若成立者继续循环,若不成立则结束循环。

也就是说,每次循环在判断语句二为成立后开始,在语句三执行完毕后结束。
程序按照语句二——循环体——语句三的顺序多次执行直到语句二不成立,循环结束。而语句一仅执行一次
现在我们可以直观地了解上面那个for循环的意义:

Created with Raphaël 2.3.0 开始 定义i=0 i<5吗? 在{i,i}处打印 i增加1 结束 yes no

注:i++相当于i=i+1

可以想到:当i依次是0,1,2,3,4时,在屏幕上{0,0} {1,1} {2,2} {3,3} {4,4},五个点处依次打印出了BodySymbol,蛇的身体。
在主函数中写入这个for循环:

int main() {
    handle = GetStdHandle(STD_OUTPUT_HANDLE);
    for (int i = 0;i < 5;i++) {
        SetConsoleCursorPosition(handle, { i,i });
        cout << BodySymbol;
    }
    getch();
    return 0;
}

编译运行:
在这里插入图片描述

注:getch()函数等待一个字符输入(敲键盘),可以让程序暂停下来,需要#include<conio.h>

接下来:改LENGTH 的值为5

#define LENGTH 5

将for循环移入ready()函数,并做一些修改

void ready() {
    for (int i = 0;i < LENGTH;i++) {
        SetConsoleCursorPosition(handle, { i,10});
        cout << BodySymbol;
    }
    cout << HeadSymbol;//最后打印一个蛇头
}

我们将y坐标改成“恒为10”,使得输出将在从左到右的一行(第十行)

注:之所以不设为0是为了体现SetConsoleCursorPosition()的作用,因为光标本身就在第0行(Y=0),从左向右移动(x++)

将5改为LENGTH,则循环LENGTH次(即按照长度打印蛇)

注:Windows坐标系方向为:从左上角水平向右为X轴正方向。从左上角竖直向下为Y轴正方向。

此时输出:
在这里插入图片描述

如果我们将LENGTH改成30,则输出:
在这里插入图片描述

30个蛇身,一个蛇头。
此时程序全部代码为:

#include <iostream>
#include<conio.h>
#include <windows.h>
//初始长度
#define LENGTH 30
//输出符号
#define NoSymbol ' '
#define BodySymbol 'o'
#define HeadSymbol 'O'
using namespace std;
//窗口句柄
HANDLE handle;
//蛇体坐标数组
void ready() {
    for (int i = 0;i < LENGTH;i++) {
        SetConsoleCursorPosition(handle, { i,10});
        cout << BodySymbol;
    }
    cout << HeadSymbol;//最后打印一个蛇头
}
int main() {
    ready();
    getch();
    return 0;
}

不知道大家有没有发现,自从ready()出现以来,HANDLE handle这句语句就移到了主函数外面,这是为什么呢?
因为每个变量都有自己的作用域,只能在作用域范围内使用。
当程序执行到变量定义语句时,就在内存为此变量分配储存空间(变量被定义),当程序离开子程序(代码块,函数等,一个子程序的特征是用大括号{}括起来。)时,所有在这个子程序中被定义的变量被释放,如果下一次执行此子程序,所有变量都会被重新定义。

所以变量的生命是从定义语句开始,到它所在的大括号结束处(右括号)结束。

因此:
变量 i 的作用域是for循环内部
变量 handle 的作用域则是全局
所谓的全局变量就是没有定义在大括号内的变量,他在全局一直存在,直到程序结束。

如果handle还在main()内部,我们就无法在ready()中使用他,可以试试将handle的定义移回main(),编译不会通过。

“handle” was not declared in this scope.
“handle” 未被定义在此作用域。

其实我们还可以使用参数传递的方法:
将main()中ready()那一行改为:

    ready(handle);

这个语句就是我们上一篇说的函数调用,其中handle是实际参数,简称实参。(具有值)
将ready()的函数头改为:

void ready(HANDLE handle) //函数头就是函数类型、名称、参数表所在那一行

其中handle是形式参数,又叫形参(没有值,接受实参的值)

实参形参傻傻分不清?
要知道main()中的handle和ready()中的handle是两个变量(变量在作用域内不许同名,在作用域外则无妨
可以将ready()中的handle改为h,这个时候,handle是实参,h是形参,参数传递的实质就是:
h = handle;

即将实参的值赋给形参。

关于形参和实参的联系是:
函数调用—赋值前: 实参有值,形参无值。
函数调用——赋值时: 实参和形参值相等。
函数调用时: 形参可以发生改变,不对实参形成影响。
函数返回后: 形参被释放,无碍于实参。

还记得上一篇提到的数组和COORD类型吗?我们将在下一篇具体讲解数组,实现真正的移动!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 将遗传算法和深度学习应用于贪吃蛇游戏的训练,可以通过以下步骤实现。 首先,定义贪吃蛇游戏的环境。将游戏区域划分为一个二维网格,并设定贪吃蛇的起始位置和初始长度。同时,定义游戏的规则,如碰壁或咬到自己身体时游戏结束,并设定游戏得分的计算方式。 接下来,使用遗传算法来生成初始的咬方式。遗传算法的基本思想是通过模拟生物进化的过程,不断优化的移动策略,直至找到最优解。通过随机生成一些初始的咬方式(染色体),并根据预先设定的适应度函数评估每个染色体的表现,选择表现较好的个体进行交叉和变异,生成下一代染色体。重复这个过程,直到找到较优的染色体。 接下来,将选定的染色体作为输入数据,通过深度学习模型来构建的智能行为策略。可以使用卷积神经网络(CNN)或循环神经网络(RNN)等适合处理空间和时间序列数据的深度学习模型。将游戏区域和当前状态作为输入,输出的下一步移动方向。使用标注好的训练数据,通过反向传播算法来调整网络参数,不断优化模型的预测能力。 最后,在训练完成的AI模型的指导下,进行贪吃蛇游戏的实时演示和验证。将AI模型的输出与游戏环境进行交互,实现的智能移动。根据游戏结束时的得分来评估AI模型的表现,可根据需要对模型进行进一步调优或重新训练。 综上所述,通过使用遗传算法和深度学习来训练AI玩贪吃蛇游戏,可以提升的智能移动策略,使其在更复杂的游戏环境中取得更高的得分。同时,这种方法在训练过程中也能够不断优化AI模型的学习能力和预测准确性。 ### 回答2: 贪吃蛇是一款经典的游戏,如今通过结合遗传算法和深度学习,我们可以训练AI来玩这个游戏。下面是一个简单的教程: 首先,我们需要定义游戏的状态和动作空间。状态空间包括的位置、食物的位置和的移动方向等信息。动作空间包括的移动方向,例如上、下、左、右。 接下来,我们使用深度学习模型来定义AI的决策策略。常见的深度学习模型可以使用卷积神经网络或者循环神经网络等。模型的输入是游戏的状态空间,输出是在该状态下的移动方向。 然后,我们要考虑如何训练深度学习模型。传统的方法是使用监督学习,人工标注大量样本作为训练集,然后通过最小化预测值与实际值之间的误差来优化模型。但是,由于贪吃蛇的决策策略很难确定,监督学习的方法并不适用。 因此,我们可以利用遗传算法来进行训练。遗传算法是一种优化方法,通过模拟自然进化的过程来寻找最优解。我们可以将AI的决策策略看作一个个体,通过对一代代个体进行选择、交叉和变异等操作,逐渐优化AI的决策策略。 具体来说,我们可以将深度学习模型的参数作为个体的基因,通过遗传算法来优化这些基因。每代都会根据个体的适应度来选择存活个体,并根据选择的个体进行交叉操作产生新的个体,最后通过变异操作加入一定的随机性。这样,经过多代的进化,AI的决策策略会逐渐变得更好。 最后,我们可以通过将训练好的AI应用到贪吃蛇游戏中进行测试。可以将AI的决策策略与随机策略或者专家策略进行对比,评估AI的性能。 总之,使用遗传算法和深度学习训练AI来玩贪吃蛇游戏是一个有趣的任务。通过逐代优化AI的决策策略,我们可以让AI逐渐变得更加智能,并在贪吃蛇游戏中表现出优秀的游戏技巧。 ### 回答3: 要使用遗传算法和深度学习来训练AI玩贪吃蛇的游戏,可以按照以下步骤进行: 1. 创建游戏环境:首先,需要创建一个贪吃蛇的游戏环境,包括的初始位置、食物的位置等。可以使用Python编程语言来实现游戏环境。 2. 定义神经网络模型:接下来,需要定义一个神经网络模型,作为AI的大脑。可以使用深度学习框架,如TensorFlow或PyTorch,来创建模型。模型的输入为游戏环境的状态,输出为的动作,如向上、向下、向左、向右移动。 3. 遗传算法初始化种群:使用遗传算法来优化神经网络模型的参数。首先,需要随机生成一批个体(神经网络模型),也称为初始种群。这些个体的参数会在后续的训练过程中不断优化。 4. 评估适应度:使用初始种群中的每个个体来玩贪吃蛇游戏,并评估它们的性能。可以定义适应度函数来量化个体在游戏中的表现。比如,可以根据吃到的食物数量作为适应度评估的指标。 5. 选择和交叉:根据每个个体的适应度,选择一些优秀的个体进行交叉,生成新的个体。选择和交叉的过程是为了保留优质基因,并引入新的基因。 6. 变异和选择:对新生成的个体进行变异操作,引入新的基因变化。变异和选择的过程是为了增加种群的多样性,避免陷入局部最优解。 7. 重复迭代:重复进行步骤4至6,直到达到预设的迭代次数或达到停止条件。每次迭代都可以得到一批新的个体,通过不断优化适应度函数,逐步提高AI在贪吃蛇游戏中的表现。 通过以上步骤的迭代训练,AI能够逐渐学习到更好的策略和动作选择,以实现在贪吃蛇游戏中取得较高的得分。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值