老师,学会了函数,在编写代码时方便了许多。
是的,可以多次使用,也可以放到别的函数中使用。
老师,函数要比基本命令难一些,我还要慢慢理解。
没关系,下面进行一些关卡练习,能够帮助大家更好地掌握函数运用。
关卡编号:2-1
关卡难度:*
通关条件:南瓜1个,开关0个。
关卡目标:使用命令组合来右转。
关卡2-1场景图如图3.1所示。
图3.1 关卡2-1场景图
根据第2章学习的基本命令收集到南瓜,大家已经掌握的命令包括移动命令move()、左转命令left()、切换开关命令toggle()和收集南瓜命令take()。在这个关卡中,不能直接使用右转命令right(),大家依旧要多次使用左转命令left()实现右转的功能。
move();
move();
move();
left();
left();
left();
move();
move();
move();
take();
通过观察不难发现,主角向前移动3格后需要向右转。因为没有右转命令,只能使用3次左转命令来实现右转功能。最后再向前移动3格到达南瓜所在砖块,这样就可以收集到南瓜了。关卡2-1通关路线图如图3.2所示。
图3.2 关卡2-1通关路线图
关卡编号:2-2
关卡难度:*
通关条件:南瓜0个,开关2个。
关卡目标:定义函数来实现主角右转。
关卡2-2场景图如图3.3所示。
图3.3 关卡2-2场景图
关卡的任务是打开2个开关,其中有1处开关已经打开,需要到达另一个没有打开的开关位置。主角的移动过程中需要多次右转,本关依旧不能使用右转命令right(),这里最好的办法是自定义一个表示右转的函数,在需要右转的时候调用自定义的右转函数。
C#代码中的字符和括号都是英文字符,在代码编辑器中输入代码时,常常因为误输入中文字符导致代码编译错误。
void TurnRight(){
left();
left();
left();
}
move();
move();
TurnRight();
move();
move();
TurnRight();
move();
TurnRight();
move();
move();
move();
toggle();
首先定义右转TurnRight()函数,通过3个左转命令left()实现右转。在定义完右转函数后,一起来梳理主角的移动步骤。
第一步:向前移动2格;
第二步:向右转;
第三步:向前移动2格;
第四步:向右转;
第五步:向前移动1格到达传送门;
第六步:传送到另一个传送门后向右转;
第七步:向前移动3格到达开关的格子;
第八步:打开开关,完成任务。
关卡2-2通关路线图如图3.4所示。
图3.4 关卡2-2通关路线图
这里需要提醒一下,函数定义和函数调用的代码要一起输入代码编辑器中才可以运行。
关卡编号:2-3
关卡难度:**
通关条件:南瓜4个,开关4个。
关卡目标:定义函数处理重复的模式。
关卡2-3场景图如图3.5所示。
图3.5 关卡2-3场景图
在本关中,每个南瓜旁边都有个开关。如果能把“收集南瓜”和“打开开关”的代码写在一个函数里面,就可以在适当的时候多次调用这个函数,避免重复编写代码。
在以后的关卡中,如果发现有很多重复的模式(模式是指由多个基本命令按固定顺序组成,表达一个复杂的动作或命令),就可以将这个模式定义成函数,多次调用函数要比重复写相同的代码好得多。
void TakeTwo(){
take();
move();
toggle();
move();
}
move();
TakeTwo();
left();
move();
TakeTwo();
move();
left();
move();
TakeTwo();
left();
move();
TakeTwo();
先定义TakeTwo()函数,这个函数可以先移动2个格子,并收集南瓜和打开开关。在4个边上收集南瓜和打开开关时,都可以调用TakeTwo()函数。
在定义完函数后,这里给出主角通关的步骤。
第一步:向前移动1格;
第二步:调用TakeTwo()函数;
第三步:向左转;
第四步:向前移动1格;
第五步:调用TakeTwo()函数;
第六步:向前移动1格并左转;
第七步:向前移动1格;
第八步:调用TakeTwo()函数;
第九步:向左转向;
第十步:向前移动1格;
第十一步:调用TakeTwo()函数,完成任务。
关卡2-3通关路线图如图3.6所示。
图3.6 关卡2-3通关路线图
关卡编号:2-4
关卡难度:**
通关条件:南瓜9个,开关0个。
关卡目标:识别重复的收集模式,并定义函数。
关卡2-4场景图如图3.7所示。
本关卡中,需要收集9个南瓜,这些南瓜分布有什么特点呢?
这些南瓜排列成3行3列,是不是可以将每列3个南瓜分为一组,然后将收集这一组3个南瓜的代码定义为一个函数。
图3.7 关卡2-4场景图
void GetThree(){
take();
move();
take();
move();
take();
}
move();
GetThree();
right();
move();
right();
GetThree();
left();
move();
left();
GetThree();
首先定义一个函数GetThree(),用来收集一行上的3个南瓜,然后按照图3.8所示的运动方向逐行收集南瓜。
在定义完函数后,给出如下的核心步骤。
第一步:向前移动1格;
图3.8 关卡2-4通关路线图
第二步:调用GetThree()函数;
第三步:向右转;
第四步:向前移动1格,并向右转;
第五步:调用GetThree()函数;
第六步:向左转;
第七步:向前移动1格,并向左转;
第八步:调用GetThree()函数,完成任务。
当然,大家也可以想出自己的方法,利用函数收集到所有的南瓜。但务必使用函数减少重复的代码。
关卡编号:2-5
关卡难度:*
通关条件:南瓜4个,开关0个。
关卡目标:从一个函数调用另一个函数。
关卡2-5场景图如图3.9所示。
图3.9 关卡2-5场景图
本关卡中,需要收集4个南瓜,这些南瓜分布有什么特点呢?
这些南瓜分布在不同的方向上,从主角位置到达每个南瓜的距离相同,在收集南瓜后还要转身回到起始位置,再去下一个南瓜位置收集。
void TurnBack(){
left();
left();
}
void OneLine(){
move();
move();
take();
TurnBack();
move();
move();
}
OneLine();
OneLine();
right();
OneLine();
OneLine();
在每次收集南瓜后都要转身,将转身的动作定义成函数TurnBack()。另外,从中心位置去收集南瓜然后回到中心位置,每个方向的这个过程都是相同的,因此,将这个过程定义成函数OneLine()。
TurnBack()函数调用2次左转命令left()实现转身的效果,大家可以操作一下转身。
OneLine()函数,首先向前移动2格,在收集南瓜时调用TurnBack()函数转身,然后向前移动2格,回到起始位置。
主角要完成收集目标所需的动作如下:首先在第一个方向收集南瓜,然后回到起始点,再到对面方向收集南瓜,然后又回到起始点,先左转,进行第三个方向收集南瓜,回到起始点,再进行最后一个方向的南瓜收集。
关卡2-5通关路线图如图3.10所示。
图3.10 关卡2-5通关路线图
通过函数把一个较大的问题分解成较小问题的方式,称为“问题分解”,这种方式有利于解决关卡难题,让代码更加简单易读。
关卡编号:2-6
关卡难度:**
通关条件:南瓜6个,开关0个。
关卡目标:通过多个函数来分解问题。
关卡2-6场景图如图3.11所示。
图3.11 关卡2-6场景图
本关卡中,需要收集6个南瓜。这些南瓜分布有什么特点呢?读者可以思考一下!
接下来,一起找找南瓜分布有哪些相似的模式。如果以主角所站砖块画一个中心线,两边的南瓜分布是对称的,就是说从中心线到南瓜的距离是相同的。
函数的命名小常识:在给函数命名时,可以基于函数的用途和目的给函数命名,尽量用有意义的单词组合,这样以后看到函数的时候,就可以知道这个函数的用途。
void TakeTurnRound(){
move();
move();
take();
left();
left();
move();
move();
}
void TakeOneLine(){
left();
TakeTurnRound();
TakeTurnRound();
right();
}
move();
TakeOneLine();
move();
TakeOneLine();
move();
TakeOneLine();
每次从中线位置去收集一侧的南瓜再回到中线,这个过程可以定义成函数TakeTurnBack()。
void TakeTurnRound(){
move();
move();
take();
left();
left();
move();
move();
}
TakeTurnRound()函数的核心步骤如下。
第一步:向前移动2格;
第二步:在南瓜所在砖块中,进行南瓜的收集;
第三步:转身;
第四步:向前移动2格,回到起始位置;
将两个TakeTurnRound()命令组合在一起,就可以实现收集两侧南瓜的效果,这个过程定义成函数TakeOneLine()。
void TakeOneLine(){
left();
TakeTurnRound();
TakeTurnRound();
right();
}
TakeOneLine()函数的核心步骤如下。
第一步:在中心格向左转;
第二步:收集一侧的南瓜回到中线;
第三步:收集另一侧的南瓜回到中线;
第四步:右转,面向下一组收集的方向。
move();
TakeOneLine();
move();
TakeOneLine();
move();
TakeOneLine();
有了TakeTurnRound()函数和TakeOneLine()函数后,主角的通关步骤就变得简单许多。
(1)向前移动1格然后收集第一行南瓜;
(2)在第一行收集后再移动1格收集第二行南瓜;
(3)在第二行收集后再移动1格收集最后一行南瓜。
关卡2-6通关路线图如图3.12所示。
图3.12 关卡2-6通关路线图
关卡编号:2-7
关卡难度:***
通关条件:南瓜0个,开关6个。
关卡目标:将问题分解成多个函数。
关卡2-7场景图如图3.13所示。
在关卡2-7中,需要打开6个开关,这些开关分布有什么特点呢?大家耐心地思考一下。虽然这些开关分布在不同的方向上,但似乎可以找到一些相似的模式。
图3.13 关卡2-7场景图
大家一起找找有哪些相似的模式,以主角所在位置为中心,4个方向上,可以发现如下规律:
(1)有2条长路线和2条短路线;
(2)长路线有2个开关,短路线有1个开关;
(3)长路线开关位置相同;
(4)短路线开关位置相同。
除了找到关卡开关的分布规律,还要将问题进行分解,将大问题分解成相似的小问题,通过使用函数完成关卡任务。
void MoveToggle(){
move();
move();
toggle();
}
void BackMove(){
left();
left();
move();
move();
}
void LoneLine(){
MoveToggle();
MoveToggle();
BackMove();
move();
move();
}
void ShortLine(){
MoveToggle();
BackMove();
}
ShortLine();
ShortLine();
right();
LoneLine();
LoneLine();
可以把主角的动作组合定义成多个函数,通关组合这些函数,打开长路线和短路线的开关。
示例代码中定义了4个函数,分别实现了“前进切换开关”“掉头回来”“打开长路线开关”和“打开短路线开关”,下面分别介绍这几个函数。
首先定义MoveToggle()函数,这个函数可以让主角向前移动2格,并切换开关状态,具体步骤如下。
第一步:向前移动2格;
第二步:站在开关所在格子中,切换打开状态。
void MoveToggle(){
move();
move();
toggle();
}
然后定义BackMove()函数,这个函数主要实现主角转身后向前移动2格。
void BackMove(){
left();
left();
move();
move();
}
函数LoneLine()的功能是打开长路线上的开关,这个函数调用了MoveToggle()和BackMove()这两个之前定义的函数,具体步骤如下。
第一步:调用MoveToggle()函数,打开第一个开关;
第二步:继续调用MoveToggle()函数,打开第二个开关;
第三步:调用BackMove()函数,转身往回移动2格;
第四步:再移动2格回到主角初始位置。
void LoneLine(){
MoveToggle();
MoveToggle();
BackMove();
move();
move();
}
函数ShortLine()的功能是打开短路线上的开关,这个函数也调用了MoveToggle()和BackMove()函数,具体步骤如下。
第一步:调用MoveToggle()函数,移动打开开关;
第二步:调用BackMove()函数,转身往回移动2格,回到主角初始位置。
void ShortLine(){
MoveToggle();
BackMove();
}
有了上面定义的4个函数,就可以从容地完成本关的关卡目标,具体步骤如下。
第一步:打开2个短路线的开关;
第二步:右转;
第三步:打开2个长路线的开关。
ShortLine();
ShortLine();
right();
LoneLine();
LoneLine();
关卡2-7通关路线图如图3.14所示。
图3.14 关卡2-7通关路线图