北大侠客行MUD论坛

 找回密码
 注册
搜索
热搜: 新手 wiki 升级
查看: 117184|回复: 158

从零开始学lua(2015.3.12更至4.5)(初级·仅针对MUSHclient)

[复制链接]
发表于 2014-12-4 16:49:21 | 显示全部楼层 |阅读模式
本帖最后由 lzkd 于 2015-3-12 08:30 PM 编辑

.
目录

第0章 序言
 0.1 自序
 0.2 本文的使用者
 0.3 相关资源
 0.4 写作日志
第1章 起点
 1.1 第一个可运行的lua代码及一些准备工作
 1.2 多行Lua代码的书写
 1.3 全局变量和局部变量
 1.4 词法约定
第2章 类型和值
 2.1 被放弃的部分
 2.2 数字
 2.3 字符串
 2.4 北京遇上西雅图(字符串及数字的生成与切换)
  2.4.1 谁的眼角触了谁的眉(字符的生成)
  2.4.2 谁的笑容抵了谁的泪(数字的生成)
  2.4.3 谁的掌纹赎回谁的罪(在字符串和数字之间切换)
  2.4.4 谁的心载了谁的轮回(一个小结)
第3章 表达式
 3.1 算术运算符
 3.2 关系运算符
 3.3 逻辑运算符
 3.4 连接运算符
 3.5 表的构造(本文仅讲数组)
第4章 基本语法
 4.1 赋值语句
  4.1.1 变量
   4.1.1.1 变量的定义
   4.1.1.2 变量名
   4.1.1.3 变量命名技巧
  4.1.2 赋值
  4.1.3 表域(可以理解为数组)
   4.1.3.1 什么是数组
   4.1.3.2 数组和机器人的关系
   4.1.3.3 数组的生成
   4.1.3.4 数组的遍历及注意点
 4.2 局部变量
 4.3 if
  4.3.1 回顾和小结
  4.3.2 if的几种形式
  4.3.3 if+end解析
  4.3.4 if+else+end解析
  4.3.5 if+elseif+else+end解析
 4.4 for
 4.5 break和return
第5章 函数
 5.1 函数的定义及作用
 5.2 告诉新手的函数分类
 5.3 寻找适合的函数
 5.4 返回多值
第6章 综合叙述
 6.1 良好的书写习惯
 6.2 代码出错后的处理办法

相关资源
-------------------------
MUSHclient4.94压缩版 ---- 这个是网盘提供下载,里面有安装版的
4.90以后的MUSHclient汉化文件
Lzkd版MUSHclient教程(相当多人的首选)
静电版MUSHclient教程(写的不错)
MUSHclient中文(Lzkd呕制作说是mush宝典也不为过)
打造属于自己的MUSHclient脚本环境(for Lua)

-------------------------

写作日志
-------------------------.....
2015.03.12 完成4.5 break和return
2015.03.10 完成4.4 for(我了个去,跨年度更新)
2014.12.27 完成流程图,诸君可仔细琢磨
2014.12.25 因为又要出差,暂停更新。诸君圣诞节快乐
2014.12.24 完成·4.3.5 if+elseif+else+end解析(欠了个流程图)
2014.12.23 感谢诸君对小刀的理解和支持
2014.12.23 完成·4.3.4 if+else+end解析
2014.12.22 因为年底了,事情比较多。而且晓晓出门学习,家里就我一个人。尽量保持更新吧,请诸君见谅。
2014.12.22 完成·4.3.3 if+end解析
2014.12.19 完成·4.3.2 if的几种形式
2014.12.18 完成·4.3.1 回顾和小结
2014.12.17 完成·4.2 局部变量
2014.12.11 因有事出差停更,回来后恢复
2014.12.11 完成·4.1.3.4 数组的遍历及注意点
2014.12.10 完成·4.1.3.3 数组的生成
2014.12.09 完成·4.1.3.2 数组和机器人的关系
2014.12.08 完成·4.1.3.1 什么是数组
2014.12.08 增补了4.1.2 赋值的内容,增加了往MUSH存取变量的说明
2014.12.07 完成·4.1.2 赋值
2014.12.07 完成·4.1.1 变量
2014.12.07 完成·3.5 表的构造(本文仅讲数组)
2014.12.07 完成·3.4 连接运算符
2014.12.07 完成·3.3 逻辑运算符
2014.12.07 完成·3.2 关系运算符
2014.12.07 完成·3.1 算术运算符
2014.12.07 完成·2.4.4 谁的心载了谁的轮回(一个小结)
2014.12.06 完成·2.4.3 谁的掌纹赎回谁的罪(在字符串和数字之间切换)
2014.12.06 完成·2.4.2 谁的笑容抵了谁的泪(数字的生成)
2014.12.06 完成·2.4.1 谁的眼角触了谁的眉(字符的生成)
2014.12.06 完成·2.3 字符串
2014.12.06 完成·2.2 数字
2014.12.05 完成·2.1 被放弃的部分
2014.12.05 完成·1.4 词法约定
2014.12.05 完成·1.3 全局变量和局部变量
2014.12.05 完成·1.2 多行Lua代码的书写
2014.12.04 居然许多人过来捧场,很是感动。尽量努力写的好一些,虽然这个工作量是相当大。
2014.12.04 完成·1.1 第一个可运行的lua代码及一些准备工作
2014.12.04 添加了相关资源中的资源内容。
2014.12.04 完成·0.2 本文的使用者。
2014.12.04 完成·0.1 自序。
2014.12.04 开始动笔,设计大纲并完成。
2014.12.02 开始考虑,是否要写一个无任何经验学lua的教程。
-------------------------


北大侠客行MUD,中国最好的MUD
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2014-12-4 16:49:25 | 显示全部楼层

第0章 序言

本帖最后由 lzkd 于 2014-12-5 05:29 PM 编辑

0.1 自序
  『三招一拆,旁观众人面面相觑,只见陈家洛擒拿手中夹着鹰爪功,左手查拳,右手绵掌,攻出去是八卦掌,收回时已是太极拳,诸家杂陈,乱七八糟,旁观者人人眼花缭乱。这时他拳势手法已全然难以看清,至于是何门派招数,更是分辨不出了。

  原来这是天池怪侠袁士霄所创的独门拳术“百花错拳”。……这拳法不但无所不包,其妙处尤在于一个“错”字,每一招均和各派祖传正宗手法相似而实非,一出手对方以为定是某招,举手迎敌之际,才知打来的方位手法完全不同,其精微要旨在于“似是而非,出其不意”八字。旁人只道拳脚全打错了,岂知正因为全部打错,对方才防不胜防。须知既是武学高手,见闻必博,所学必精,于诸派武技胸中早有定见,不免“百花”易敌,“错”字难当。』

                         ——金庸《书剑恩仇录》


  天下万物,皆有成法。而我们所谓的经验,只是用自己的内心来解释我们所不熟悉的事物。如上文中的陈家洛,便是利用了这一点,当别人以为自己正确时,他便获胜了。

  最近北侠颇有一些想学机器人而不得其法的人出现,其代表人物便是清水群中81#渡向同学。看着这位基础N差,对编程中的基本概念几乎一点都不了解的同学,努力学习机器人的样子,实在不能不为这种精神所感动。
  但,渡向同学的学习效率实在让人无语。当一个人用自己的内心来解释自己完全不了解的事物时,便有了各种让人无法想象的错误的出现。

  经过几天的思索,小刀认为,渡向同学这种情况,需要对编程有一个基本的认识。不然的话,花再多精力,也不能有比较大的进步。无奈的是,找遍了网上的教材,哪怕是再基本的,也不适合他这种情况。
  Lua,在国内目前还是属于比较小众语言(我的意思是,还没到全国人民一起学Lua的程度),这导致低端教程的极度不足。细想来,这个也不奇怪,要去学Lua了,想必是对写代码有一定基础的,所谓低端教材,也不过看看函数,看看有哪些东西不能用而已。
  Basic,20年前几乎所有人的启蒙教材,但现在已经被淘汰。想在网上当个Basic环境都很难。
  php,这个倒是有许多从零开始的低级教材。但有一个问题很难解决,写代码,总是要测试吧。你没php环境,学什么php代码?在自己电脑架一个吗?Apache+Php不是那么好配置吧。最终,也放弃了。
  ……
  其实,放弃以上所有种种的最终理由是——哪怕是Lua,现在的教材中,也仅有20%是和写机器人有关的。而要让一个完全没有编程基本的人,把那20%找出来,无疑是不可能完成的任务。

  正好,这几天有点空。就决定写这个教程,给所有想学机器人,却没有任何编程经验的人。
  说一下本教程的设定。
0、本文所有红色粗体标出部分,都一定要记住并领会,实在不行就硬记吧。
1、让没有任何编程经验的人,对编程有一个直观的了解;
2、所有内容,都针对在MUD中使用MUSHclient写机器人,作者认为无关部分,都舍掉(减少学习量);
3、计划包含类型,变量,表达式,if,for,函数(可能会按实际时间、情况调整);
4、仅讨论初级内容,高级的东西请自己找书看(相关资源部分会给出一些链接);
5、不在本教程中讨论机器人的具体做法;
6、欢迎讨论,谢绝拍砖;
7、因为结构很庞大,为操作方便,先放在竹林版,完成后再转机器人版;
8、本文所有加上色加粗的观察,请大家要注意这些地方,虽然看起来可能很不起眼。但相信大家都知道,成功源自细节,这些都是容易出错的地方。
9、还没想好,待定吧(^_*)。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2014-12-4 16:49:27 | 显示全部楼层
本帖最后由 lzkd 于 2014-12-4 06:08 PM 编辑

0.2 本文的使用者

  很明显,从列出的目录来看,小刀是在刻意模仿《Programming_In_Lua》这本书。包括那个自序,都有抄一段金庸的小说(其实一段计算机语言书的初级部分都是差不多这个样子)。所以说,这个教程,大家可以理解为,这是用一个完全不懂写程序的人的角度,并且是抱着玩MUD写机器人的态度,来重新诠释这本书的部分内容。

  说说,对本文使用者的要求:
1、小刀假设,各位都是在现实中有所成就,阅读本文,不需要编程知识,但需要悟性,有些地方,更可能需要人生阅历(高看各位一头,相来不会有人有意见);
2、本文的目的,在于能够让大家看明白一般的机器人代码,请注意是一般(很高端的东西,基本上在本文找不到);
3、小刀会把自己的学习心得和一些方法都放入本文。因为这些,对于那些高手、老手来说,都是如呼吸般自然的事情。但小刀有这个能力,把这些整理出来,并且用各位能看明白的话,来告诉大家;
4、相信大家都明白,想把任何一件事情做好,都不是容易的。写机器人同样也是如此。学习的过程可能会是饱受挫折和孤独的,要拥有耐心、刻苦、反复尝试和经得起失败。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2014-12-4 16:49:30 | 显示全部楼层

第1章 起点

本帖最后由 lzkd 于 2014-12-5 06:44 PM 编辑

.
  所谓起点呢,就是说,这一章的东西,如果都看不懂,或者照着做也做不来,那就可以换个方式玩MUD了,呵呵,开个小玩笑。

1.1 第一个可运行的lua代码及一些准备工作

  到本帖资源区,下载目前最新的MUSH客户端,下载最新汉化文件。按Lzkd版MUSHclient教程中安装汉化好。然后新建一个lua文件,输入如下代码(可使用论坛提供的代码复制功能),存放到你的MUSH安装目录的worlds目录下,取个名字叫xuexi.lua。然后按照Lzkd版MUSHclient教程中7楼的方法,将这个lua文件载入到MUSH。
  1. print("##### 大家好,欢迎开始Lua的学习之旅!! #####")
复制代码

  然后,我们就可以看到如下效果。

lua001.jpg

  一般的教程,到这里就结束了。但小刀不同,现在才是针对没有任何经验的人讲注意点的地方。按子襄同学的话就,这些属于——在coder看起来很自然的事——根本没办法讲的,呵呵。那,如果你已经跟着操作到这里了,那应该会有一个问题,这个动作,到底有什么含义,下面就是解答,小刀相信,任何一本Lua书都不会有这样的解释,并且不会解释到这么详细且易懂(先小吹一下哈)。
1、输入代码后,载入到MUSH,并且在屏幕输出我们所希望的字符。这个操作,证明了我们已经搭建了一个可以正常运行的Lua环境。以后我们所有的代码,都可以通过这种方式进行测试
2、测试Lua代码的步骤:①将代码输入Lua文件;②保存;③将Lua文件重新载入④代码自动运行(可能会有人说,这不完全对。说明一下,小刀是故意的。从个人带了无数新人入行的经验来说,新人最怕的一件事,就是有太多可能。这样也行,那样也行,然后新人就傻了,不知道怎么动才是对的。所以,一开始,宁可把所有情况都cut掉,就一种可能,就一种解决方案。等有些熟悉了才慢慢开始展开。相信许多人学不下去的一个很重要的原因,就是没有一个统一的标准。不扯太多,打住了。)
3、我们学到了第一个命令print(),这是一个屏显命令,可以将几乎所有东西都显示在屏幕上。这个命令,可以起到检查我们所希望的数据是否正确的作用。
4、仔细观察,我们可以发现,第3条,我写的是print()。也就是说,这个命令不是单独一个print就可以起到效果的,需要加上(),而且是一对()不是单个。以后在代码复杂的时候,多一个少一个括号都会报错。
5、另外,再观察一下,我们可以发现,代码中的()两边,是有""这样的符号,但在输出的图片中,""是不存在的。这个状况,我们先不进行详细的分析,放到后面的章节。

1.2 多行Lua代码的书写

  多行Lua代码的书写,有两种方式:
  1. print("大家好,这里是多行书写,请注意行末没有加;")
  2. print("       -- by lzkd")
复制代码

  这种书写方式行未不加;

  1. print("大家好,这里是多行书写,请注意行末加了;");
  2. print("       -- by lzkd");
复制代码

  这种书写方式行末加;

  这两种书方式效果相同,都能正确运行。根据《Programming_In_Lua》这本书中的代码实例及MUSHclient作者Nick书写的代码,我们统一不加;。

1.3 全局变量和局部变量

  所谓变量,比较coder的解释是——变量即在程序运行过程中它的值允许改变的量。小刀认为,我们可以把变量理解成一个一个的盒子。没错,就是盒子,试想一下,我们生活中,买了两斤肉,没人会抱在怀里带回家吧?总得弄个包装,盒子也好,包也好。同样,在MUD里,我们抓取到的各种数据,比如说盗宝人的名字之类,也得找个盒子装吧。——这个盒子,就是变量。好了,关于变量,我们先讲到这里,以后还会再更多的聊起它。
  Lua中的变量分成全局变量和局部变量。全局变量在所有的地方起作用,局部变量只能在特定的地方起作用。这两者的区别,我们可以理解为全国粮票和地方粮票。全国粮票很牛,哪里都认;地方粮票就比较差一点,出了当地就没人搭理了。
  可能有同学会提问——既然这样,那我们都用全局变量就好了,还要局部变量干什么?话不是这么说的,上天安排每样东西出现,其实都是有用的。区别在于,我们能不能清楚它的用法。不过,按教程的设计,我们先不在这里讨论这些。在第1章,我们知道有这个概念就可以了。

1.4 词法约定

  这部分内容没有什么特别的,大家知道一下就可以了。
⑴ 尽量不要使用下划线加大写字母来命名变量和函数,因为Lua的保留字也是这样的。
⑵ 注意:Lua是大小写敏感的。
⑶保留字:以下字符为Lua保留字,不能用做变量名及函数名
andbreakdoelseelseif
endfalseforfunctionif
inlocalnilnotor
repeatreturnthentrueuntil
while    
⑷ 注释:分为两种
  1. --print("这里是单行注释")
复制代码
  1. --[[
  2. print("这里是多行注释")
  3. --]]
复制代码
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2014-12-4 16:49:32 | 显示全部楼层

第2章 类型和值

本帖最后由 lzkd 于 2014-12-7 01:51 PM 编辑

.
  这部分的内容有6个,但被小刀砍掉4个,就留了2个。因为小刀觉得,就初学者而言,知道就两个就足够了。毕竟我们是目的是为了玩MUD写机器人,而不是去做程序员。

2.1 被放弃的部分

  nil这个小刀认为,写机器人没帮助,就直接过掉了。
  true、false这两个,琢磨半天,也放弃了。原因有两个:一是,返回值的判断,可以用1和0来代替,相信这个对于普通人更直观一些;二是,想了半天,实在想不,怎么用浅显易懂的话来描述这两个概念。so……
  functions这种将函数存入变量的灵活方式,就不要拿来折腾新手了吧。
  Userdata可以将C数据存放在Lua变量中,Threads就是所谓线程。这种一看就是高大上的东西,就先不要来折磨我们的心灵了吧。

2.2 数字

  在玩MUD写机器人的过程中,数字是必不可少的。试举例如下,打坐时,我们需要抓取自己当前的气值,当前内力值,最大内功值,以确定我们这次打坐,应该打多少;战斗中,我们需要抓取自己的受伤程度,来判断是否需要吃药等等。我们都知道,数字的一个特点,是可以计算,可以比较大小。以上的内容,都是可以计算和比较的。(请注意一下,后面会有说明,为什么在这里加上这句
  在Lua中,数字很简单,就是0-9,外加小数点。
  在MUD里,还有另外一种情况——有些数字,不需要计算。比如说,做领悟机器人的时候,我们可能希望增加一个小窗口,来看一下领悟技能,效果大致如下图。
lua002.jpg

  好了,现在到了需要各位生活阅历的时候了。作为在生活中都有所成就的各位,在工作中一定明白了一个道理——有些人,有些事根本是没办法按照正常的思维来对待。明明说过无数遍的事情,却总是一次一次的犯错,一次的挑战着我们的极限。
  而能解决这个问题的办法是——彻底把那些人当成白痴,给他们做出最详细、最严密的规定,并且经常过去检查。
  如果各位对上面那段话心有同感的话,小刀现在可以告诉大家,其实计算机语言(这里指Lua)也是这样的。不把东西给它规定死了,它是不会干活的
  所以,在这里小刀跟诸君做个约定,所有不需要计算的数字,我们都不视为数字,而视为字符串

2.3 字符串

  说一下,什么是字符串。试举例如下,做慕容任务时,抓取的地址;做胡一刀任务的时候,抓取的盗宝人名字和id,抓取skills时技能名称、等级(注意,等级是数字的样子)……这些都是字符串。我们的代码,就是根据这些,来进行分析、判断,机器人应该怎么跑。
  看到这里,有些喜欢动脑筋的同学,应该会有疑问了——上面说过,计算机语言是个白痴,既然汉字、字母、数字都有可能成为字符串。那别的还好说,那些需要计算的数字,和不需要计算的,怎么区分呢?
  这个问题提的很好,我们来拆分解决一下。
  首先,根据简单原则,我们来做一个约定(事实上在写所有机器人代码上,这也是可行的)——在写MUSH机器人的时候,所有需要计算的部分,我们都视为数字。再加上2.2节中,关于字符串的约定,什么时候是数字,什么时候是字符串,我们就清楚了。
  接下来的问题是——我们怎么让电脑也清楚这一点。解决这个问题方案,请阅读2.4节——北京遇上西雅图。

2.4 北京遇上西雅图(字符串及数字的生成与切换)

  其实小刀知道,这个名字跟严肃的教程不搭(旁白:何止是不搭。)。但请各位原谅小刀小小的任性吧,周六大家都在玩的时候,写这种枯燥的教程,如果不给自己找点乐子,是会发疯的。其实这节讲的是字符串及数字的生成与切换。

2.4.1 谁的眼角触了谁的眉(字符的生成)

  基本上,除了极特殊的情况下,我们从MUD中抓到的内容,Lua都认为是字符串。但还有另外一种情况,我们需要在代码中写一个字符串。比如说,慕容任务中,复同学让你去满地图找叛徒,但我们不可能一下就把所有城市的数据都完成。这种情况下,就需要做一个判断,看一下复同学给的任务,是不是在我们已经有资料的城市中。
  比如说,我们要检查,复同学给的城市,是不是扬州(怎么判断,后面再说)。我们如何得到一个字符串,内容是扬州呢?直接写扬州行不行?不行!
  之前我们说过,计算机其实是个白痴,不按它的规定来,它是不会干活的。聪明的同学,可能已经想到了,在1.1节中留了一个问题,为什么要加""。事实上,几乎所有的计算机都认为,两边同时加了"的(一边一个就可以了),就是字符串。另外,需要注意的是——一定要是英文半角的",绝对不能是中文全角的“”
  结论是,写成"扬州"就可以了。我们可以写一段代码来测试一下。
  1. print("扬州") --就是可以正确输出的
  2. print(扬州)  --这里就不能正确输出了
复制代码

  大家可以看一下,两者的区别。顺便说一下,这是一个很容易出错的地方,后面我们会继续讲到。

2.4.2 谁的笑容抵了谁的泪(数字的生成)

  代码中数字的生成则简单多了,如果我们需要一个值为123的数。那我们直接写成123就可以了。结合2.4.1节,如果需要一个值为123的字符串,我们需要这样写"123"
  2.4.1节有一段话——我们从MUD中抓到的内容,Lua都认为是字符串。所以,有时候,我们需要进行两者的切换,这是2.4.3的内容。
  另外,可能有同学会问——数字加上"",就成了字符串,不加""就是数字;字母、汉字加上"",就是字符串,那如果不加呢?会成为什么。这个问题,我们放在变量一章中讲解。

2.4.3 谁的掌纹赎回谁的罪(在字符串和数字之间切换)

  先说明一下,这部分内容解决什么问题。我们知道,从MUD中抓到的内容,Lua都认为是字符串(有特例,但不考虑,小刀提供的方案可以自然解决问题)。我们要计算dazuo多少气血,要判断战斗中的当前气血是否需要吃药,这些情况我们需要把字符串转换成数字。而有的时候,我们有另一种需求,比如说,我们想用小窗口统计押镖过程中的掉宝、遇怪等一系列数据,需要进行计算后再变成字符串输出到小窗口中(效果见下图)
.
lua003.jpg

  将字符串转化成数字:tonumber() ——注意,这是一个Lua内置函数,跟print()类似,用法也类似。下面用一些代码来说明问题。
  1. print(1)  --这里输出一个1
  2. print(1+2) --这里输出一个3
  3. print(1+"2") --这样会出错,注意"2"是字符串
  4. print(1+tonumber("2")) --这样又正确了,有余力的可以注意一下写法
复制代码

  将数字转化成字符串:tostring() 注意点同上。下面用一些代码来说明问题。
  1. print("a" .. tostring(1)) --连接a和数字1
复制代码

  简单说明一下,字符串和数字连接可以不这么麻烦,但有某种情况之下,直接连接会报错的。而且这种错是很难查出来的。试想一下,一个你以前一直认为正确的写法,事实也一直证明是正确的,因为某个特殊情况,就变的不对了,那得有多逆天才能查出来。为了避免这种情况出现,建议各位初学者,在连接字符串和数字的时候,统一做一下转化吧。俗话说的好,行走江湖,安全第一,安全第一。

2.4.4 谁的心载了谁的轮回(一个小结)

  花了几天时间了,想尽办法的写了一堆东西,自问也算是将一些东西尽力表达了(是表达了,至于是不是表达清楚了,这个要问诸君自己了)。现在要做一个小结,然后再引出一些新的东西。这个打算用图表的形式来表达,原因是以前上过的课课告诉我,人类对图形的记忆要数十倍、上百倍于文字。所以,苦逼的小刀在周六的晚上,还得折腾图表软件。

lua004.jpg

  这个图画的还是挺漂亮的,对吧。虽然可能不符合各种标准,但小刀觉得,还是可以说明我的一些想法。对照着图,我们简单把这个理一下:
1、机器人发送命令到MUD;
2、MUD接到命令后开始处理,并将结果以字符串的形式返回(注意,返回的都是字符串);
3、Lua通过alias或者tri接收了数据(注意,这里是有选择的接收),在这里需要注意Lua接收数据的方法,我们后面会讲到;
4、Lua用函数(还有别的方法,但本文就讲函数)将收到的数据加工、分解(有的需要切割,有的需要变成数字,方法后面会讲到),变成我们需要的数据,在这里需要注意函数的书写、格式、命名等;
5、加工完的数据,有些是我们需要保存的,就保存起来。保存可以选择保存在Lua,或者MUSHclient。以前小刀觉得Lua更好(其实现在也是),但最近发现MUSHclient变量对于新手有一个独特的优越性,所以打算大力介绍一下;
6、数据保存完毕后,Lua再用函数对最新数据及以前保存的数据进行分析判断,最终得到结果;
7、将计算后的结果,按自己的需要进行保存(图中省略了向MUSHclient保存数据的线),然后再向MUD发送新的命令。
  至此,构成了一个完整的结构和循环。建议大家将这张图下载后保存,黄色的标注框中“-”后部分,是该步的要点,这里的要点意思是——如果这步出了错,就检查这里,往往可以找出问题来。具体每个应该怎么检查,本文后面还会详细讲到。

  随着这张图的完成,整个《从零开始学lua》整个框架结构已经完成,后面的工作就是往里面填充血肉了。后面写作会更艰难,但也更精彩,希望大家继续给我支持。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2014-12-4 16:49:34 | 显示全部楼层

第3章 表达式

本帖最后由 lzkd 于 2014-12-7 06:07 PM 编辑

.
  表达式,是计算机语言中的术语,诸君如果不明白,那也没关系,反正咱们也不用考试,把下面一些东西看懂就好。本章还是比较简单的。

3.1 算术运算符

  这个是最简单,我们就直接Pass了。
  二元运算符:+ - * / ^  (加减乘除幂)
  一元运算符:-  (负值)

3.2 关系运算符

  所谓关系运算,诸君理解为比较就可以了。
  < 小于
  > 大于
  <= 小于等于
  >= 大于等于
  == 等于(注意,这个跟现实算术运算的不一样)
  ~= 不等于

3.3 逻辑运算符

  诸君需要了解的,只有两个 and or 关于这两个,我们会在if相关的小节中详细说明。

3.4 连接运算符

  这个更简单 .. 用于连接两个字符串。
  需要注意的是,虽然使用 .. 连接字符串和数字的时候,Lua会将数字转为字符串。但在有些特殊情况下,这种转换会失效,所以为安全计,建议都进行转化。

3.5 表的构造(本文仅讲数组)

  表是Lua特有的功能强大的东西。但对于诸君来说,想彻底了解这个强大且灵活到没那么容易掌握的事物,绝对不是这个小小的教程所能完成的事。那么,还是按以前所定的简单原则——太复杂并且不影响基本Lua学习的,都暂时放弃。
  下面,讲一下数组的定义,在这一节,诸君只要看看就好。具体的内容,小刀会放在基本语法中能变量一起对照着讲,这样更清晰。
  所谓数组,即是一个特殊的变量,能够同时保存一个或一个以上的值。
  能看懂吗?看不懂没关系,后面有详细的说明。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2014-12-4 16:49:37 | 显示全部楼层

第4章 基本语法

本帖最后由 lzkd 于 2014-12-17 10:46 AM 编辑

.
  Lua像C和PASCAL几乎支持所有的传统语句:赋值语句、控制结构语句、函数调用等,同时也支持非传统的多变量赋值、局部变量声明。

4.1 赋值语句

  赋值是改变一个变量的值和改变表域的最基本的方法。
  好了,之前几乎所有累积的疑问,在这里都会有一个解决(多么熟悉的台词呀,是不是有那句"I'll be back."的味道?)。可如果你认为这里是终极大Boss,那你就错了。充其量,这只是一个武装自己的地方。不相信?那接着看就是了。
  在本章开头那句话里,我们需要解决的问题如下:
  什么是变量?
  什么是赋值?
  什么是表域?

4.1.1 变量

4.1.1.1 变量的定义

  1.3节讲过,变量即在程序运行过程中它的值允许改变的量。小刀也将变量比喻为一个盒子,这个盒子装的,是各种数据。这个比喻,相信大家肯定能理解,关于定义就不多说了。

4.1.1.2 变量名

  所有人都应该有一个名字,变量也不例外,每个变量都应该有自己的名字,说一下变量名的要求。这个在前面已经讲了一部分,除去一些特定的字不能用、不要使用下划线加大写字每之外,还有不要用数字做变量名的起始字符,不能使用中文做为变量名。另外,Lua的变量名大小写敏感,意思就是A和a是两个不同的变量。我们来看一段代码。
  1. A = 1 --让A的值为1
  2. a = 2 --让a的值为2
  3. print(A) --显示A的值
  4. print(a) --显示a的值
复制代码

4.1.1.3 变量命名技巧

  简单说一下,变量命名的技巧。很显然,aa这个变量名,过一段时间,作者自己都会忘掉是什么。相比之下,skillsName,SkillsName,skills_name之类的名字,就要好多了。结论是,充分利用大小写和下划线来命名变量是个好方法。
  另外一个小技巧,是关于变量性质的。前面说过,MUD中所有的数据,不是字符串,就是数字。但将数据存入变量后,从外观上,是无法判断出哪个变量存的是字符串,哪个变量存的是数字。这个时候,如果对变量加上前缀就可以一目了然看出来了。一般情况下,n_变量名,表示存放的是数字(number);s_变量名,表示存放的是字符串(string);a_变量名,表示该变量是数组(array);t_变量名,表示该变量是临时变量(tmp)。

4.1.2 赋值

  赋值本身比较简单,就是将一个值给到一个变量。具体的方法看代码:
  1. t_abc = "这是一个测试"
复制代码

  在这里做一个比较详细的解释, = 这个符号,在现实中,是等于号,意思是 = 两边是相等的。但在计算机世界中,这个称为“赋值”号。意思是——将等式右边的值赋予等式左边的变量。上面代码,计算机理解为——将"这是一个测试"赋予t_abc变量。
  然后,我们跟3.2节 关系运算符 中 == 放在一起比较一样。 == 和现实中的 = 比较接近。但两者意义是完全不同的。诸君可以仔细体会一下。
  如果还是有些混乱,我们可以这么来记忆。 = 肯定是单独使用,而 == 一般会和 if 一起使用(具体见下面的章节)

  既然已经说到了赋值,顺带讲一下变量在MUSH中的存取。我们看代码。

  1. t_test1 = "这是一个测试" --测试用字符串
  2. t_test2 = 20141208  --测试用数字(注意前缀)
  3. SetVariable ("t_test", "直接输入") --直接将字符串存入mush
  4. SetVariable ("t_test", 444) --直接将数字存入mush,注意后一条命令,把前一条数据覆盖
  5. SetVariable ("t_test1", t_test1) --将变量t_test1存入mush中的变量test1
  6. print(GetVariable("t_test1")) -- 直接输出mush中变量t_test1的内容
  7. SetVariable ("t_test1", t_test2) --注意,这后面是t_test2
  8. print(GetVariable("t_test1")) -- 同上一个print()中的内容是一样的,但输出结果不同

复制代码

  我们来做一个说明。从这句可以看出,存入变量到MUSH是用这个命令,SetVariable ("t_test1", t_test1),前面的"t_test1"是MUSH中的变量名,后面的是Lua中的变量名。可能有人会不明白,为什么前面一个一定要加"",在这里简单解释一下。在前面的学习中,我们已经知道,Lua中带""的,会被视为字符串;不带""的数字,会被视为数字;而不带""的非数字,都会被视为变量。大家可以做一个测试,输入print(中文测试),会导致错误。原因就是,所有不带""的非数字,都被视为变量,所以Lua就去找——中文测试——这个变量的值了,但这是找不到的,之前讲过Lua不支持中文变量名,所以只能报错了。所以,前面那个一定要带上"",表明这是一个字符串
  从MUSH取值的命令很简单GetVariable("t_test1"),这个t_test1是MUSH中的变量,同样要加上"",理由同上。另外需要注意的是,所有取出的值,都是字符串,所以如果需要计算从MUSH中取出的值,一定要转化(以前低版本4.3左右的时候,是一直强调这一点的,不知道高版本有没有修正,但不管如何,加上总是不错的,至少兼容性要好一些)
  最后说一下,为什么建议新人使用MUSH变量,因为MUSH的值,可以在不操作任何Lua代码的情况下,直接在MUSHclient客户端里看见,这一点,实在是方便极了。

4.1.3 表域(可以理解为数组)
  Lua的表(table)是极其灵活和强大的,但因为特别灵活、强大的部分,对于一个普通的机器人没有太大帮助。为了让教程更通俗易懂,在本文仅仅将其当成数组来看待(本来table的设定跟数组几乎就一样)

4.1.3.1 什么是数组

  3.5节已经讲了一下数组的定义,即是一个特殊的变量,能够同时保存一个或一个以上的值。
  如果不明白的话,我们继续想象。之前我们把变量解释为盒子,看一下数组的定义,里面有这么一句——一个特殊的变量——既然是变量,那当然也是盒子了。不知道,大家对集装箱有没有概念,就是那种很大的铁柜子,一般做对外贸易用的比较多,铁柜子打开以后,里面可以放许多纸箱。(我想不需要真的放一张集装箱的图片上来吧?)数组呢,就跟那集装箱差不多,别的盒子里是装东西,它这盒子里装的是盒子,看起来比较厉害的样子,但不变的是,盒子里的盒子,还是装东西用的。
  数组在生活中,其实无处不在,比如说出门买菜,买了2斤青菜、2斤米、半斤肉,然后你把这三样,分别拿塑料袋装好(一般店家都提供),然后你拿出一个大一点的环保袋(多低碳,赞一个),把这三样都装进去。OK,这其实就是一个数组。你就环保袋就是数组,里面有三个数组元素,分别是——青菜、米、肉。
  讲到这里,诸君都应该明白数组是怎么回事了。但可能还是有人会有疑问,这么麻烦的东西有什么用?如果要存放数据的话,用普通的变量不就好了吗?如果数量比较多一点,完全可以a1、a2、a3……然后一路a下去。
  没错,这样想当然也不是不可以,但总是有些情况是需要数组来解决的。不然的话,小刀为什么费这么大劲想把数组概念解释清楚呢?至于什么情况用数组,请看4.1.3.2节。

4.1.3.2 数组和机器人的关系

  什么时候用数组呢,小刀来举两个例子。相信诸君都用过领悟机器人,没用过的,至少也领悟过。在领悟之前,是不是要做一个动作——输入cha命令——这么做的目的,是为了将机器人的使用者的原始数据抓入,以便程序进行判断。在这种情况下,如果使用数组,一个类似a_skills的数组就可以搞定了(至于怎么抓的,我们后面会讲到)。
  如果使用普通变量,那就麻烦了——s_skills01,s_skills02,s_skills03……这一个一个装,那也就算了,重点来了,每个人的技能数量都不一样吧?哪怕是同门同派,也会因为对北侠的理解不同,所学技能会有所偏差。那,我们放几个变量合适呢?这个问题,还真是……今天天气,哈哈哈。

  第二个例子。比如说,要做胡一刀机器人,老胡发任务的时候,我们需要记录,任务地点,盗宝人姓名,盗宝人id,有些无聊人士,还会把这是第几次任务,今天一共完成了多少次任务,放弃了多少次任务,等等一些资料都做进去。
  如果使用普通变量,这一个一个的写过来,写过去的,难道不是很麻烦吗?而且一个不小心,还会有错有漏的说。如果放在一个数组里,直接拎包走人,岂不是很爽?4.1.3.1节中不是说,数组就是一个用来装盒子的大盒子嘛。

  好了,两个例子讲完,相信诸君已经很清楚数组的好处了,那我们下节就开始学习如果生成数组。在这里,强调一点,数组也不是随意生成的,应该把具有相关性的数据放进一个数组。如之前的skills,胡一刀任务相关数据等。

4.1.3.3 数组的生成

  要想生成数组,得先了解数组的结构,来看一段代码。
  1. require "tprint"
  2. t_days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
  3. tprint(t_days)
  4. print("-------------------这是为了看清楚一点的分割线-----------------------")
  5. t_quests = {["hyd_city"] = "扬州", ["hyd_name"] = "尤金龙", ["hyd_id"] = "suxxacd"}
  6. tprint(t_quests)
复制代码

  运行后,大致是这个样子。
  1. 1="Sunday"
  2. 2="Monday"
  3. 3="Tuesday"
  4. 4="Wednesday"
  5. 5="Thursday"
  6. 6="Friday"
  7. 7="Saturday"
  8. -------------------这是为了看清楚一点的分割线-----------------------
  9. "hyd_city"="扬州"
  10. "hyd_id"="suxxacd"
  11. "hyd_name"="尤金龙"
复制代码

  先说一下,代码开头那行——require "tprint"——这是MUSHclient自带的一个查看数组的扩展,使用很简单,看一下就会,效果不错。
  诸君都知道,每个变量都会有一个名字,这是为了让计算机找的时候不会出错。同样,数组内的每个值,也需要有一个名字,这个术语称为“下标”。
  Lua中数组下标有两种(见运行效果)。一种是连续自然数的排列(t_days数组),有点象以前学校里的学号,是吧。另一种是可以自己定义下标(t_quests数组),这样的好处是使用时更灵活、更方便记忆。
  但类似t_quests格式也不是完全没有缺点,因为Lua默认的数组下标是从1开始的(这点跟绝大多数的编程语言不同),而且许多内置的操作都是仅针对下标从1开始的数组。当然,解决方案也不是没有,这个请放心。

  说一下这两种格式一般在什么情况下使用。类似t_days格式,比较适合用在大批相同格式数据抓取的情况下,可以理解成输入cha抓取skills,呼一下就都抓下来了;或者用在大量数据输入的情况,因为不需要输入下标,方便一些。
  类似t_quests格式,一般用在程序中处理一组有类似性质数据上,可以随时添加,随时使用。
  类似t_days的数组的生成,直接按代码中所示就可以了,没什么技术含量。说一下类似t_quests格式数组的生成。本来想放出一个例子,但考虑到需要跟函数结合起来,才是比较完整的代码。不然的话,会有破坏结构的味道,所以到函数时再放出吧。诸君请看代码及注释。
  1. t_quest = {}  --使用数组,必须先定义,这就是定义的格式
  2. t_quest["hyd_city"] = "xxxx"  --将城市信息存入数组,xxx的意思是用某种方法得到的数据,具体见后面章节
  3. t_quest["hyd_name"] = "xxx"  --同上
  4. ----下面是使用的例子
  5. print(t_quest["hyd_city"] )  --显示出城市名
  6. print(t_quest.hyd_name) --显示出任务人名,这里用了另外一种方法,两者是等价的,小刀最近看论坛代码,发现这两种都有人用,特此指出
复制代码


4.1.3.4 数组的遍历及注意点

  先要说明一点,这里的遍历,是指读取数组内每一个值,而不是北侠论坛机器人版上一直比较神秘的遍历。按北侠机器人守则,这个是不允许讨论了,抱歉了。
  数组的遍历,是一个实用性比较强的功能,但因为Lua比较坑爹的table功能,在使用过程中需要比较小心,不然的话会出一些很麻烦的错误,下面会详细说明。
  另外,说明一下,本论坛有bug,有时候使用复制功能粘下来的代码,会出现不应该有的字符,会给诸君的测试造成不便。解决方法是手输或者直接复制,选哪个就随意了。

  为写好这个教程,最近把一些基本的东西又仔细梳理了一下。关于数组遍历,网上有好多个版本,研究下来,适合北侠的,有3种,其余要不效率低下,要不太麻烦,就不介绍了。来看代码:

  1. --第一种方案(命名为方案A)
  2. --key是键值(也就是教程中的下标),下同
  3. --value是该key的值,下同
  4. --tbl为数组,下同
  5. for key, value in ipairs(tbl) do  
  6.     --这里是别的代码
  7. end

  8. --第二种方案(命名为方案B)
  9. for key, value in pairs(tbl) do
  10.     --这里是别的代码
  11. end

  12. --第三种方案(命名为方案C)
  13. for i=1, #tbl do
  14.     --这里是别的代码
  15. end
复制代码

  我们来看一下,这三种方案应该在什么情况下使用。
  解释一下方案A的作用——该方案的循环必须要求tbl中的key为顺序的,而且必须是从1开始,ipairs只会从1开始按连续的key顺序遍历到key不连续为止。来看代码。
  1. tbl = { [1] = 1, [2] = 2, [3] = 3, [4] = 4 }

  2. for key,value in ipairs(tbl) do  
  3.   print("循环内取值 ==> "..value)  
  4. end
  5. print("循环外取值")
  6. print(value)
复制代码

  运行结果是这样的。
  1. 循环内取值 ==> 1
  2. 循环内取值 ==> 2
  3. 循环内取值 ==> 3
  4. 循环内取值 ==> 4
  5. 循环外取值
  6. nil
复制代码

  这里有几个需要注意的地方。
  首先,是循环内取值的问题,可以看见,运行结果中,最后的print(value)输出的结果是nil(可以理解为没有值),而之前的print(value)都是有值的(另外几个方案也同样)。所以,以后记得要在循环结束时将需要的值取出
  其次,如果数组下标不是从1开始,又或者当中断了,又或者使用了非数字下标,那就会断掉。篇幅所限,诸君可以自己写代码测试。

  关于方案C,其实方案C和方案A的使用要求和输出结果是一样的。来看代码。
  1. tbl = { [1] = 1, [2] = 2, [3] = 3, [4] = 4 }

  2. for i=1, #tbl do
  3.   print(tbl[i])
  4. end
复制代码

  输出结果略,希望诸君自己试一下。另外,也试一下,如果将下标改为不连续,或者改为非数字,会有什么结果。只有自己测试过了,写代码的时候,才能做到心中有数。

  在实际工作中,一般建议使用方案C来代替方案A。一来,两者使用效果基本一样,方案C的书写更简单一些。二来,细心的同学可能会发现,方案A和方案B实在太接近了,两者就差了一个字符。哪怕是为了减少误写的可能,也是选择方案C比较好一些。

  好了,现在我们已经解决了下标为数字的数组的遍历问题,就余下一个下标非数字的遍历了。使用方案B,看代码。
  1. tbl = { [1] = 1, [2] = 2, ["a"] = 3, [4] = 4 }

  2. for key,value in pairs(tbl) do  
  3.   print("循环内取值 ==> "..key.." --- "..value)  
  4. end
  5. print("循环外取值")
  6. print(value)
复制代码

  运行结果如下:
  1. 循环内取值 ==> 1 --- 1
  2. 循环内取值 ==> 2 --- 2
  3. 循环内取值 ==> 4 --- 4
  4. 循环内取值 ==> a --- 3
  5. 循环外取值
  6. nil
复制代码

  在这里给诸君留一个作业,根据上面的代码和运行结果,能分析出什么注意点吗?

4.2 局部变量

  来说一下局部变量。1.3节中已经提到了局部变量的概念,只是没有展开,本节我们来进行比较详细的学习。
  一直这样认为,想学好一样东西,前提是对这样事物有比较深入的了解。而所谓深入了解,无非是这几样——怎么来的、能解决什么问题、如何组成、怕什么(喜欢什么)。诸君可以看到,整个教程的核心思路就是如此。学习的时候,诸君也抱着这个试看看,效果会好许多。

  局部变量,是指在特定过程或函数中可以访问的变量。如在for或者函数中可以定义一个变量,出了这个for或者函数,这个变量就没用了。来看代码
  1. t_aaaa = 1000

  2. function tta()
  3.         local t_aaaa
  4.         t_aaaa = 999
  5.         print(t_aaaa)
  6. end
复制代码

.
  直接运行print(t_aaaa)的话,输出1000,而运行tta()函数的话,输出999。从这个例子可以看出一些两者的区别。

  说一下使用局部变量的好处:
1、可以加快程序运行速度。简单解释一下,在整个机器人运行过程中,所有的全局变量Lua会一直记住(放内存里),而局部变量用完就销毁了,更节省资源;
2、不怕同变量名重命名。不同的区域的局部变量是允许同名的,不影响使用;
3、减少变量名记忆量。因为用完就扔,很省心。而全局变量前面说过,需要知道是表示什么意思。
  说一下局部变量的特点及不足:
1、局部变量可以与全局变量同名,但是局部变量会屏蔽全局变量。在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。(具体见上面的例子)
2、在程序调试过程中,使用局部变量会造成一定程度的不便。具体表现为,一般出错的情况下,我们会试着将变量结果输出,看看是否为我们所预期的值。这一点上,使用局部变量会有一定的麻烦,因为无法直接print出来。但也不是没办法解决,这个就做为思考题留下,诸君开动一下思路,想想怎么解决。

北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2014-12-4 16:49:40 | 显示全部楼层
本帖最后由 lzkd 于 2014-12-27 03:57 PM 编辑

4.3 if

4.3.1 回顾和小结

  针对所有真正初次接触编程的朋友,如果认真学习了前面所有的确内容,现在应该对程序的最基本的组成有一定的了解(概念部分)和直观的认识(代码部分)。在这里,小刀给诸君再做一个小小的总结。
  通过上面的学习,诸君应该有以下认识:
1、计算机其实是很笨的,而且是个死心眼,一定要按照它明白的方式来书写代码,不然的话,它不会认帐;
2、编程和诸君目前手上的工作没有任何区别,如果非要找出一个区别来的话,那只是诸君目前对编程这件事还没有属于自己的认识。一旦有了,编程完全可以和诸君手中的工作一样,变得非常简单。
  好了,如果有哪位同学,还没能得到以上结论,建议再回去复习上面的教程。因为后面我们会开始一些新的东西。

  从上面的学习,我们可以让程序得到一些值,并且计算,然后再得到结果。但诸君有没有想过——这个世界不是一个完全的线性世界——也就是说,我们会在某种情况下,需要做一个判断。根据判断的结果,来做不同的安排。
  试举个例子,假设每次dazuo 400,那我们就需要在每次dazuo完成的时候,检测气血的当前值,如果小于400,就执行复气命令;如果大于400,则继续dazuo 400。
  这里引进了一个判断的概念,有了这个概念以后,程序就会变层次丰富起来,下面请诸君和我一起来学习。

4.3.2 if的几种形式

  根据实际的需求,分成几种不同的情况,具体的表现就是if的几种形式,下面的章节会进行详细讲解。
  先简单熟悉一下,if的形式,看代码,请注意注释的文字
if+end 型
  1. -- if 是if语句的开始,表示以下开始为判断语句(if后面紧接着为判断条件),每个条件判断含且仅含一个if,下同
  2. -- then 表示判断条件的结束,每个条件判断含且仅含一个then,下同
  3. -- end 表示整个条件判断的结束,每个条件判断含且仅含一个end,下同
  4. if 判断条件 then

  5.     这里的代码在判断条件成立时运行(!!!注意是成立)

  6. end
复制代码

if+else+end

  1. -- else 表示的意思为——当所有条件不成立的时候,应该怎么做,每个条件判断含且仅含一个else,下同
  2. if 判断条件 then

  3.     这里的代码在判断条件成立时运行(!!!注意是成立)

  4. else

  5.     这里的代码在判断条件不成立时运行(!!!注意是!!不成立)

  6. end
复制代码

if+elseif+else+end 型

  1. -- elseif 表示多条件并存判断,每个条件判断可含多个elseif,!!!注意是多个
  2. if 判断条件A then

  3.     这里的代码在判断条件A成立时运行(!!!注意是A)

  4. elseif 判断条件B then

  5.     这里的代码在判断条件B成立时运行(!!!注意是B)

  6. ..            --->多个elseif

  7. else

  8.     这里的代码在所有判断条件不成立时运行(!!!注意是!!所有)

  9. end
复制代码


4.3.3 if+end解析

  我们可以这样来理解if+end。假设我们要从甲地到乙地,正常的情况我们是走路过去,但如果身上有超过10元钱的话,就可以打的过去。
  if+end是条件判断的最基本型,大家需要结合我上节给出的代码注释仔细体会。这种型的要点在于,本身不影响程序的走向,只是在正常的过程中,加入一个判断
  举一个在mud中的例子。看代码(注意,认真看注释)。
  我们假设这样一种情况——在任何任务开始之前,我们需要检查自己的状态,按照简单原则,例子中仅检查武器有没有装备。具体的思路是这样,领取任务之前,先检查自己的武器是否正常装备,如没有装备则装备武器,如已经装备就跳过装备武器的代码,继续运行。

  1. -- 这里只是一个简单的演示,为了更好的说明if+end的情况
  2. -- 这段代码应该是在整个任务机器人中的一小段
  3. -- mysword是放置是否装备了武器的变量,这里设置为:0,未装备;1,已装备
  4. -- 怎么取得是否已经装备武器,这个诸君应该都会,跳过了
  5. -- 如果mysword == 1,那这个if+end之间的代码,就会不运行了.
  6. if mysword == 0 then
  7.     Send("wield sword")   -- 这里是装备武器的命令,这部分可以放许多别类似相关东西,诸君可以课后思考
  8. end
复制代码


4.3.4 if+else+end解析

  通过对if+end的学习,诸君已经掌握了基本的判断。但有些比较复杂的情况,是无法用if+end来解决。比如说,生活中孩子们的学习成绩(最近是小刀在管儿子学习,顺手拿这个举例),成绩为80以上的,是一种处理方式,成绩为80以下的,是另一种处理方式。这种按不同的情况分别处理,需要用到if+else+end。
  想了一下,在mud里,很少有纯粹使用if+else+end的,因为分割的条件极少有一种(就是所谓两分)。所以,代码就用生活中孩子成绩来展示。另外,else相关有一个很实用的技巧,会在if+elseif+else+end的解柝中给出。诸君请认真看注释

  1. -- Results 放入成绩
  2. -- >= 80 将成绩等于80的也列入
  3. -- 重点在else,大家可以看到给出的判断条件中,仅仅列出了">= 80"的情况
  4. -- 在条件语句中,else表示的是!!!除了以上条件以外(!!注意是以外)的所有情况。
  5. -- 在本例中,因为考试成绩永远只能是在0-100之间。所以,除去了">= 80"的情况之外,就是"< 80"了。以后我们会更多的用到这个特性
  6. if Results >= 80 then
  7.     -- 进行表扬处理的代码
  8. else
  9.     -- 进行批评处理的代码
  10. end
复制代码


4.3.5 if+elseif+else+end解析

  终于到了这里,其实if+elseif+else+end是代码中用到最多的,但如果不讲前面那些,无法把这个说的很清查晰。在这里小小吐槽一下,如果是有编程基础的,只要一句——类似case——就可以解决问题。但在本教程,会花了这么多时间和篇幅才到这里。

  if+elseif+else+end可以解决更复杂的判断及筛选问题。直接以mud中的实际应用来举例。
  假设要写一个慕容机器人。小复一般这么给任务“到扬州东大街找回XXX”(没时间进mud去抓一个真正的任务数据,诸君领会精神就好)。当然,这里涉及到如何把“扬州”和“东大街”分开,但这个涉及到的东西太多了,先放一下吧。
  假设诸君已经能正确将任务数据中的城市名提取,需要按照不同的城市进行相应的操作,看代码。

  1. -- mr_city为变量,存放任务城市名
  2. -- elseif 可以理解为并列条件判断,即众多条件中满足一个即可,相信诸君学习到现在,应该可以想明白了,就不详细展开了
  3. -- elseif 的形式,非常适用于任务领取时的分析判断,诸君一定要认真掌握
  4. if mr_city == "扬州" then
  5.     --当任务数据所在城市为扬州时,执行代码放在这里,(下同)
  6. elseif mr_city == "白陀" then
  7.     --白陀
  8. elseif mr_city == "岳王墓" then
  9.     --岳王墓
  10. else    --这里非常重要,请认真看下面的文字!!!!
  11.     -- 这里应该放的是机器人保护代码!!!!!
  12. end
复制代码

  先考虑一个问题。作为一个没学过编程的新手,写机器人最痛苦的是什么?当然,这个问题各人都有不同的答案。就小刀自己来说,初写机器人时,觉得最受不了的是各种情况层出不穷,让人疲于奔命。
  现在给出一个解决思路,诸君可以参考。具体思路是,基于简单原则,能搞清楚(或者已经完成的)归为一类,未完成(或没整理到的)归为另一类单独处理。结合上面的慕容任务例子,做一个详细的说明。
  假设诸君已经完成了“扬州,白陀,岳王墓”这三个城市的行走及相关问题,自然可以在相关地方写上代码,让机器人运行。
  但我们不可能一开始就拥有详细且完整的慕容任务库,就算是有任务,每个任务的行走之类的,还得自己做的。
  在这里,可以使用else的特性——当所有条件都不满足时,执行代码。
  说一下,这么做的好处:
1、哪怕永远就做了“扬州,白陀,岳王墓”这三个城市,这机器人也一样可以运行,因为没完成的城市都过滤了(当然,这个效率就谈不上了);
2、可以收集未完成城市的数据;
3、机器人在运行的过程中,可以更好的调试代码。因为只有不停运行的机器人,才能进一步发现问题,解决问题。这样机器人才能不停的长大。

  最后给出一个流程图,诸君可以沉下心来仔细琢磨一下。 流程图out.png
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2014-12-4 16:49:42 | 显示全部楼层
本帖最后由 lzkd 于 2015-3-10 11:38 AM 编辑

4.4 for

  好久不见,大家还好吗?人生总是有各种各样的说不明白,呵呵。最近忙的要命,不过这个教程不会烂掉,尽量抽时间写一点,时间上估计比较难保证了。

  for是循环的一种,具体的代码,在前面的教程中已经出现了一些。所差的,只是没有做一个系统的分析,我们现在就来做这个工作。
  来看代码:
  1. for var=exp1,exp2,exp3 do
  2.     loop-part
  3. end
复制代码
  官方的解释是——for将用exp3作为step从exp1(初始值)到exp2(终止值),执行loop-part。其中exp3可以省略,默认step=1——是不是很不明觉厉?没关系,我们是实用派的,诸君来想一下,我们在什么情况下,需要用到循环。这个清楚了,我们只要让循环输出的结果符合我们的要求即可。
  按穷举原则,可能产生的需要如下:
1、需要运行次数确定的一段代码(如10次);
2、需要运行次数不确定的一段代码(如确定当前房间的各方向房间内容,数量不能确定);
3、需要得到从1-10的数字,并且参与代码运行(可用于数组下标);
4、需要得到从10-1的数字,并且参与代码运行(可用于路径返转);
5、还有的就不考虑了,如可以得到2、4、6、8……的数据排列。
  下面给出解决第2,第4种情况的代码,诸君可以试运行一下,然后再推导出其余情况的代码,这样比较有利于诸君的进步。
  1. --第2种情况
  2. x = 5
  3. for i = 1, x do
  4.     print(i)  --这里是需运行的代码
  5. end
复制代码
  1. --第4种情况for i = 10, 1, -1 do
  2.     print(i)  --这里是需运行的代码
  3. end
复制代码

注意点:
1、三个表达式只会被计算一次,并且是在循环开始前。也就是说,如果在循环的过程中,x发生了变化,不会影响到循环。
2、控制变量var是局部变量自动被声明,并且只在循环内有效。也就是说,i这个变量的值,在循环结束就就会自动消失,如果想保留这个值的话,需要在循环中进行赋值。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2014-12-4 16:49:44 | 显示全部楼层
本帖最后由 lzkd 于 2015-3-12 08:21 PM 编辑

4.5 break和return

  break和return都可以理解成,中断、或者结束某样东西,所以放在一起讲述,当然,也是因为这个比较简单。
  break语句用来退出当前循环(比如说for)。在循环外部不可以使用。看代码:
  1. for i = 1, 10 do
  2.   print i
  3.   if i > 5 then break end
  4. end
复制代码
  return用来从函数返回结果,lua支持返回多个值,当然这部分我们会在后面讲。看代码:
  1. function foo(x)
  2.     return x
  3. end
复制代码

  好了,这一节就到这里结束了。目的就是要让大家知道一下这两个语句。再下一章,我们要开始函数的讲解。个人认为,函数是初学者最实用,也最需要掌握的工具,希望诸君可以认真学习。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|北大侠客行MUD ( 京ICP备16065414号-1 )

GMT+8, 2022-10-3 04:09 PM , Processed in 0.016111 second(s), 17 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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