条件详解

条件详解

> LeekScript 教程

好!是时候给你的程序加上条件了!

到目前为止,你的代码每次都做同样的事。条件就是来解决这个问题的。

条件是我们要讲的第一种“控制结构”。它能让你的代码更灵活,根据具体情况做出调整。

目前你看到的代码都是线性执行的,一条指令接着一条指令。现在我们来看看如何根据条件决定是否执行某段代码。

比较运算符

不过在讲条件之前,我们得先回到运算符上。之前我们主要讲的是用来做计算的运算符,而要攻克条件,就得先认识用来做比较的运算符。

这些运算符和我们已经见过的那些有点不同。 比如你已经知道,在 LeekScript 中,表达式“4 + 6”的结果是 10。结果是一个整数,一个数字。这是一个表示计算的数学表达式。

比较运算符则可以用来写出表示某种关系的数学表达式。假如我们写下表达式“2 ”,也就是“严格小于”和“严格大于”。 (如有需要:在法语 AZERTY 键盘上,这两个符号的按键位于“W”左边,一个要按住 Shift,另一个不用。)

总之,这些运算符用来检验两个元素之间的大小关系。 例如:

var resultat = a b;

如果“a”的值严格大于“b”的值,结果就是 true,并赋值给变量“resultat”;反之则为 false

这里说的确实是“严格”关系。如果 a 和 b 的值相同,结果就是 false,因为谁也不比谁小,谁也不比谁大。

非严格关系运算符

接下来是关系运算符的非严格版本。

比如大于或等于运算符,只需把相等运算符和关系运算符组合起来,就得到了“>=”!也就是大于号后面跟一个等号。

例如:

var resultat = a >= b;

如果“a”的值大于或等于“b”的值,结果就是 true,并赋值给变量“resultat”;反之(也就是严格小于)结果为 false

同理,“小于或等于”的运算符就是“

A B A && B

falsefalse->false

falsetrue->false

truefalse->false

truetrue->true

用这段代码,你可以测试全部四种取值组合:

debug("false AND false : " + (false && false) ); // 显示:false debug("false AND true : " + (false && true) ); // 显示:false debug("true AND false : " + (true && false) ); // 显示:false debug("true AND true : " + (true && true) ); // 显示:true

OR

也就是“逻辑或”。在 LeekScript 中有两种写法:写成“or”,或者使用符号“||”(两个“|”,在法语 AZERTY 键盘上按住 AltGr 再按数字键 6 输入)。

用刚才的代码再测一次:

var A = true; var B = false; debug(A || B); // 显示:true debug(A or B); // 显示:true

这一次,结果是 true! 只要两个值中至少有一个为 true,逻辑或的结果就是 true

于是我们得到:

A B A || B

falsefalse->false

falsetrue->true

truefalse->true

truetrue->true

同样,如果你想测试一下:

debug("false OR false : " + (false || false) ); // 显示:false debug("false OR true : " + (false || true) ); // 显示:true debug("true OR false : " + (true || false) ); // 显示:true debug("true OR true : " + (true || true) ); // 显示:true

NOT

也就是“逻辑非”。在 LeekScript 中有两种写法:写成“not”,或者使用符号“!”(就是一个普普通通的感叹号)。

前面的运算符比较的是两个值,而它只作用于一个值:它的作用是把布尔值取反

来试一下:

var A = true; var B = false; debug(!A); // 显示:false debug(!B); // 显示:true

逻辑非的结果就是原值的反面:值为 true 就变成 false,反之亦然。

简单来说就是:

Anot A

false->true

true->false

当然,如果你想测试一下:

debug("!false : " + (!false)); debug("!true : " + (!true));

相信我,运算符真的非常有用。无论是逻辑运算符还是算术运算符,很快你就会在代码里到处用到它们。

条件

呼,运算符总算讲完了。 也许你还不太清楚它们能派上什么用场,接下来就会慢慢清楚了。

IF

if 是用来编写条件的关键字。 “if”在英语里的意思是“如果”。 它让你可以对你的韭葱说:如果这样,就做那件事。

语法如下:

if (condition) instruction;

这里的 condition 是一个“表达式”。如果这个表达式的值为 true,也就是为真,那么这条指令就会执行。 反之,如果表达式为假(值为 false),这条指令就不会执行。

但这种语法只能执行一条指令。

如果你想写多条指令,就要用下面这种语法:

if (condition) { instruction; instruction; instruction; }

用这种语法,你想写多少条指令都行,甚至只写一条或者一条都不写也可以。 这种语法也比前一种更易读、更清爽。

如果“condition”这个表达式的结果为 true,那么花括号“{”和“}”之间的代码块就会被执行。 如果条件不满足,也就是值为 false,那就什么也不会发生。

试试这段代码:

if (false) { debug("条件为真!"); }

什么都没发生!由于条件为假,debug 指令没有执行。 试着把条件里的 false 换成 true,你会看到这次消息出现了。

ELSE

else 这个关键字让你可以在条件不满足时执行代码。 “else”在英语里的意思是“否则”。 它让你可以对你的韭葱说:如果这样,就做那件事;否则,就做这件事。

使用它的语法如下:

if (condition) { // 指令 } else { // 其他指令 }

和前面一样,如果条件为真,就执行 IF 后面花括号里的代码。 但如果条件不为真,执行的就是 ELSE 后面花括号里的代码。

我们来改进一下前面那段代码:

if (false) { debug("条件为真!"); } else { debug("条件为假!"); }

搞定!条件为 true 时,你会看到提示条件为真的消息; 条件为 false 时,你会看到提示条件为假的消息。

ELSE IF

可以把关键字 ifelse“合并”起来,以区分不同的情况。 写出来大致是这样:

if (condition) { // "condition" 为真 } else if (condition2) { // "condition" 为假,但 "condition2" 为真 } else { // "condition" 和 "condition2" 都为假 }

明白是怎么回事了吗?没明白?别慌! 看几个例子你就懂了。 是时候把你学过的各种运算符付诸实践了!

三元运算符

三元运算符是编写条件的另一种方式。我们先来看一个用 if/else 写的基本条件:

if (condition) { action1(); } else { action2(); }

用三元运算符写同样的代码,就是这样:

(condition) ? action1() : action2();

它也可以用于赋值,例如:

var maVariable = (condition) ? valeur1 : valeur2;

三元运算符的缺点是可读性比 if 结构差很多,不过它消耗的操作数会少一点。

如果你刚入门,还不需要去优化代码里的每一个操作数。所以刚开始的时候,还是优先使用经典的 if 结构吧。

几个例子

来比较一下!

你已经看到了,值是可以比较的。 那比较的结果是什么呢?没错,是一个布尔值! 所以我们可以轻松写出这样的代码:

if (3 < 4) { debug("3 小于 4!"); }

好吧,这算不上什么世纪大发现,但你也许已经开始想象能用它做些什么了。 我们来做一个更有意思、也更有用的比较…… 获取你和对手之间的距离!

var distance = getCellDistance(getCell(), getCell(getNearestEnemy()));

if (distance < 10) { debug("报告长官,敌人正在靠近!"); }

搞定!现在你可以根据与对手之间的距离来执行代码了。 在这里,只有当敌人离你不到 10 格时,才会显示这条消息。

如果你不太理解这一行:

var distance = getCellDistance(getCell(), getCell(getNearestEnemy()));

下面是一个更容易理解的版本:

var maCellule = getCell(); // 获取自己韭葱所在的格子 var ennemi = getNearestEnemy(); // 然后获取敌人的 id var celluleEnnemi = getCell(ennemi); // 接着获取这个敌人所在的格子 var getCellDistance(maCellule, celluleEnnemi); // 最后得到两个格子之间的距离

你还可以把条件嵌套起来,比如这样:

var enemy = getNearestEnemy(); var distance = getCellDistance(getCell(), getCell(enemy));

if (distance < 11) { if (distance < 8) { useWeapon(enemy); } else { useChip(CHIP_SPARK, enemy); } }

我们的朋友:布尔值

以函数 lineOfSight 为例:如果作为参数传入的两个格子之间有视线,它就返回 true

我们来测试一下你的韭葱能不能看到对手:

var enemy = getNearestEnemy(); var los = lineOfSight(getCell(), getCell(enemy));

if (los) { debug("看到了,长官!我看到它了!"); } else { debug("它跑哪儿去了!?这胆小鬼躲起来了!"); }

就这样,你可以知道你的韭葱能不能看到对手,也就知道它能不能朝对手开火。

别忘了这个函数返回的是布尔值,像下面这样写完全是多此一举:

var myCell = getCell(); var enemyCell = getCell(getNearestEnemy());

if (lineOfSight(myCell, enemyCell) == true) { debug("看到了,长官!我看到它了!"); }

IF 本来就会检查条件是否为真,这样写就好比你在问你的韭葱:“有视线”这个条件为真,这件事为真吗? 这纯属重复,小心我敲你手板。

反过来,如果你关心的是相反的条件,你可能会想这样写:

var myCell = getCell(); var enemyCell = getCell(getNearestEnemy());

if (lineOfSight(myCell, enemyCell) == false) { debug("它跑哪儿去了!?这胆小鬼躲起来了!"); }

这也好不到哪儿去!lineOfSight 的返回值是 truefalse。 代入返回值后,你的条件就成了 (true == false) 或 (false == false),实在没什么意义。

那正确的做法是什么呢? 答案是使用逻辑非!

var myCell = getCell(); var enemyCell = getCell(getNearestEnemy());

if (lineOfSight(myCell, enemyCell)) { debug("看到了,长官!我看到它了!"); }

if (!lineOfSight(myCell, enemyCell)) { debug("它跑哪儿去了!?这胆小鬼躲起来了!"); }

这才是布尔值的正确用法。 不再重复,漂亮又干净,简直让人垂涎欲滴。

对于布尔值,你不需要用到 ==、!=、=== 和 !== 这些运算符。 它们主要用来比较数字和常量。

例如:

if (getWeapon() != WEAPON_PISTOL) { setWeapon(WEAPON_PISTOL); }

有了这段代码,如果你手里没有武器,或者拿的不是手枪,你的韭葱就会装备上它。

实战演练

你脑子里冒出的第一个想法,也许会是这样:

“嗯,能用手枪的时候我就用手枪,用不了就用火花。”好主意,为什么不呢?

首先要确定使用手枪需要满足哪些条件。

它的射程是 1 到 7。所以先用 getCellDistance 检查距离:

if (getWeapon() != WEAPON_PISTOL) { setWeapon(WEAPON_PISTOL); }

var enemy = getNearestEnemy(); var distance = getCellDistance(getCell(), getCell(enemy));

if (distance <= 7) { useWeapon(enemy); useWeapon(enemy); useWeapon(enemy); }

但这还不够。绝大多数武器和芯片都受所谓“视线”的限制。 简单来说,要使用手枪,你的韭葱必须能看到目标。 要检查这一点,就要用到函数 lineOfSight

if (getWeapon() != WEAPON_PISTOL) { setWeapon(WEAPON_PISTOL); }

var enemy = getNearestEnemy(); var distance = getCellDistance(getCell(), getCell(enemy)); var los = lineOfSight(getCell(), getCell(enemy));

if (distance <= 7 && los) { useWeapon(enemy); useWeapon(enemy); useWeapon(enemy); }

条件有了!可以把它读作“如果距离小于或等于 7,并且有视线”。

剩下的就是加上火花的使用了。

if (getWeapon() != WEAPON_PISTOL) { setWeapon(WEAPON_PISTOL); }

var enemy = getNearestEnemy(); var distance = getCellDistance(getCell(), getCell(enemy)); var los = lineOfSight(getCell(), getCell(enemy));

if (distance <= 7 && los) { useWeapon(enemy); useWeapon(enemy); useWeapon(enemy); } else { useChip(CHIP_SPARK, enemy); useChip(CHIP_SPARK, enemy); useChip(CHIP_SPARK, enemy); }

有视线且在射程内时,这段代码会使用手枪,否则使用火花。 不需要检查火花的射程:如果你的韭葱离得太远,它只是用不出来而已。

小结

现在,你可以让你的代码变聪明了:你已经能让它根据局势随机应变。

下一章会讲循环,这是编程中另一个非常重要的概念。