北大侠客行MUD论坛

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

CMUD Lua也疯狂

[复制链接]
发表于 2015-8-24 22:35:46 | 显示全部楼层 |阅读模式
本帖最后由 oolong 于 2015-8-25 01:16 PM 编辑

一直以来使用CMUD2.37很顺手,可以稳定运行一个月都没事。
最近手痒想实现以下CMUD里面调用Lua来计算。
我的初始设定:
1,一个玩mud的,习惯 触发-命令 结构了
2,完全不懂编程...

首先为啥要用Lua,众所周知CMUD map可以自动算出两点之间的最短路径,参考函数%pathfrom(),%walk().
但是有时候我们要遍历一个房间比如“青石大道”,周围10格的所有房间。zscript的迭代计算实在低啊,所以产生了一个用lua来解决迭代计算的想法。

需求产生了,实现可复杂了,(it精英,mc机器作者可以忽略难度了)。

首先用zscript 的com 调用数据库xxx.mdb这个过程本文省略了,详细见sg的技术文档。还有以前我也提到过一部分。那么我的第一步就是用com sql计算出所有房间的相连房间信息,将信息存入一个cmud list变量里面。这个没啥难度吧,啥?这你也有难度,那么你手动打开mdb,一条一条copy吧。
list格式如下:
1="2|3"
2="1|3"
3="2|4|5"
...
cmud里面很简单#var list.1 "2|3" 或 #addkey list 1 "2|3"即可。
使用的时候:
#sh @list.1
结果: 2|3
#sh %db(@list,1)
结果:2|3

那么CMUD要实现计算房间"1"周围3步的所有房间。需要迭代三次,每次把得到的房间重新变成一个list,然后去除已经计算过的房间,继续计算剩余房间周围的房间。一般情况计算10步大概0.5秒吧。蛋疼的问题是如果是“青石大道”这种很多房间的要计算10步,估计也要2-3s吧。一个cmud没关系,如果20个cmud问题就比较突出了。如果你还挂在vps上面。问题就更大了。

寻求Lua解决?各种Lua书籍很多,非it人士看的头疼,从自己需要的找吧,别的就不看了。CMUD里面#help 看看Lua方面的内容吧,很简单,不过英文的...

一)首先要解决如何在Lua中获取CMUD的一切...
先做几个实验吧!
1.1 Lua获取一个CMUD的变量
新建一个alias,名称a--最喜欢的名称了!,同时#var a 1
选择Lua的脚本
local a=zs.var["a"]
print(a)
好了你可以看到屏幕显示了?
注意要开启信息显示,相当于#echo @a

alias脚本改成:
local a=zs.var["a"]
a=a+5
print(a)
没错屏幕显示你得到了6

1.2将你的Lua数值传递给CMUD
local a=zs.var["a"]
a=a+5
zs.var["b"]=a
去cmud变量里面看看是不是多了一个b,值是6.

当然lua还能访问所有其他的cmud命令函数等,由于我用不到就不展开了,举一个例子吧。
你在创建一个alias b--我第二个喜欢的名字。
#alias b {haha}
local a=zs.var["a"]
a=a+5
print(a)
zs.cmd.show(a)
zs.cmd.execute("xixi;b")
没错:
相当于显示#sh @a
xixi;haha

1.3 cmud使用lua 的语法
向上面说的alias里面直接用lua写,就可以。要不设置一个函数function里面用lua写。或者看看#lua 命令也行。
好吧,我选择用function的lua写好#function myfunction {}
然后在zscript里面:
#var a @myfunction()

二)解决我要解决的问题

2.1 在Lua中如何利用我得到的list 数据结构见上文。
首先先用Lua来分析一下这个list。
为了便于分析,我很无耻的使用了一个以后的tprint.lua文件,我甚至不知道里面写的是啥,抱歉非it精英...,也许不需要这个玩意吧不管了。
同样创建一个alias a:
require "tprint"--这个tprint.lua位置随意,我喜欢在cmud里面建立一个lua文件夹,放进去。
local a=zs.var["list"]
print(a)
结果:
{{2,3},{1,3},{2,4,5},6,.....................}
显然CMUD得到一张表,我们来遍历这样表吧。
local a=zs.var["list"]
for k,v in ipairs(a) do
print(a)
end
这是copy的一个例子,使用for的,不过这个不管用。原因是你的list 1="2|3", 2="1|3" 作为一个"key" 1,2未必连续。也就是说你的房间号不能确保中间不漏掉。
也许应该用其他的list规则不要1="2|3",用"room1"="room2|room3"
不过...由于自己太懒了不想改之前的了。换一种遍历方式吧。
local a=zs.var["list"]
local b=table.maxn(a)
for i=1,b do
print(a)--
end
好吧基本表里面元素全出来了,有三种:
1,还是一个table,比如 {2,3}
2,一个数值,比如6
3,nil,也就是空的意思
可能这个遍历的效率有人说不高,遍历了很多的nil出来。由于本人的房间号基本连续,断点很少,所以无所谓了。另外实际过程中也不需要遍历整个表格。

2.2 如果要实现我的功能需要做几个工作。
第一,为了保证我的程序简单可行,我先要将这个list所有的元素全变成table表。那么我需要一个自己定义的函数。
函数很丑,it精英绕道。

function to_table(tab)--函数名字to_table,参数tab
local to_table={} --建立一个空的table叫to_table
if type(tab)=="nil" or type(tab)=="string" then --如果传递过来的这个参数tab是nil或string,那么不管他:(
--
else if type(tab)=="number" then
to_table={tab}--如果传递过来的参数是一个数值number,比如100,那么把这个数值100变成{100}
else if type(tab)=="table" then --进入正题,如果是table,那么开始转换
local n=table.maxn(tab)
for i=1,n do--for
if type(tab)=="nil" or type(tab)=="string" then --在转换过程中,这个tab中的nil,string 都不管
--
else if type(tab)=="number" then --在转换过程中,遇到数字转换成 {100}格式,传递到to_table 中去
to_table={tab}
else if type(tab)=="table" then -- 遇到table 传递到新的to_table 中去
to_table=tab
end
end
end
end--for
--
end
end
end
return to_table --最后得到一个to_table 所有元素都是table 类型的。
end
好了,自己定义的to_table已经好了,虽然土了一点,但是应该能用了。

2.3 非常可悲的是你如果遍历这个list 表,每次出来的value都是一个table,由于本人不知道还有啥好的办法,这能再次土一把,建立一个函数来合并所有的表

function table_merge(tab_a,tab_b)--暂定table_merge,用来合并tab_a,tab_b
for i,v in ipairs(tab_b) do -- 循环tab_b
table.insert(tab_a,v) --在tab_a 中插入tab_b
end
--tab_b=nil
return tab_a -- 返回新的tab_a
end
由于我要循环的tab肯定是{2,3}这种,我有再次使用了范例介绍的for ipairs的方法..

2.3 当你合并完成的时候发现一个新的问题,就是表中可能同时出现好多3,比如2,3,2,3,4. 你需要一个合并同类value的方法,当然你可以继续将这个table传递给cmud,然后cmud用%dups()来合并。不过你现在在lua中呢,还是lua里面搞吧,没到最后一步还是别进cmud里面吧。
function table_dumps(tab)--暂定table_dumps,sorry应该是dups算了笔误我也就不管了
local new_tab={} --新的空表
local temp_tab={}--新的临时表
for k,v in ipairs(tab) do --循环tab
if temp_tab[v]~=1 then --如果临时表中value的数值不是1
temp_tab[v]=1 --那么临时表中的数值写1,
table.insert(new_tab,v) --新的表加入value值
end
end
--temp_tab=nil
--tab=nil
return new_tab --返回新的表
end

2.4 按照刚才遍历的思路,你已经遍历的过表,下次不想遍历,那么你要从下次遍历中删除吧,吐血再次要实现一个功能。从表tab_a中删除表tab_a中的元素。

function table_delete(tab_a,tab_b)
local temp_tab = {}--临时表
local new_tab={}--新的表
for k,v in ipairs(tab_b) do --在tab_b中循环
temp_tab[v]=1 --所有tab_b中的value值,在临时表中变成key,value为1
end
for k,v in ipairs(tab_a) do --在tab_a中循环
if temp_tab[v]~=1 then --如果value,在刚才临时表中的valu不是1
table.insert(new_tab,v) --那么在新的表中加入 这个 value,也就是说只要tab_b中出现的,新表一律不含有
end
end
--tab=nil
--item=nil
return new_tab --返回一个新的表
end

2.5 还有一个函数,这个应该是必须的就是从一个表中remove一个数值value,比如已有表tab中有{1,2,3...}我要删除"3"这个功能也必须的。毕竟搜到的房间未必都想去吧。。。
function table_remove(tab,item) --叫remove吧
local new_tab = {}--建立新的表
for k,v in ipairs(tab) do --tab中循环
if v~= item then --如果数值value不等于item
table.insert(new_tab,v) --那么将这个item加入到新的表中
end
end
--tab=nil
--item=nil
return new_tab --返回新的表
end
我想要的功能都有了,以上函数出自一个完全不同lua的,就看看cmud的介绍啊,各位不要喷了,效率也从未考虑...

三)进入正题,开始着手解决我的最终目标。
3.1 首先就是将这些自定义函数存在一起,命名一下,随便。我命名为sj_functions.lua
CMUD中建立一个函数名字a?

require "sj_functions" --刚才那个存起来的.lua文件
require "tprint" --这个有用么?无所谓加也require一下
local target=zs.var["job_room_list"] --首先从cmud变量读取"job_room_list" 给target。这个是预先得到的,比如你用%mapquery([name]="青石大道")他总会给你一个list吧
local range=zs.var["job_range"]--读取cmud job_range,比如青石大道周围 5个房间,那么不就是range=5?
local data=zs.var["list"]--还记得刚才那个list么,没错就是他保存了所有房间之间的信息
local roomcost=zs.var["room_cost"] --这个是另外一张表记录roomcost的了解cmud的都知道有一个%roomcost(),这是一个路径权重,如果cost 3,那么进过这个房间的路径长度加3,也就是同样两条路r1,r2,如果路径长度一样,r1中间有房间cost=4,那么r2就是最优路径,当然如果一个房间cost无穷大,那么这个房间是无法进入的。
--好吧,你可以忽略cost这档事了,如果你用不到
--print(data[51])
data=to_table(data)--将得到的list变成 元素全是table的表
--print(data[51][1])
local rooms_searched={} -- 新的表记录已经搜到的房间
if type(target)=="number" then -- target就是你的"青石大道"的房间,他可能是一个数值不是表呢,一起做了他,也变成表吧
target=to_table(target)
else if type(target)=="table" then
end
end
local rooms_searching=target -- searching 就是每次要搜的房间表,显然第一次应该就是targt"青石大道"
local rooms_get=target -- 每次搜索得到的表get
local rooms_find={} -- find就是最后找到的表,现在空的
---------------
for j=1,range do -- range 循环,周围5格
---range loop
print(rooms_searching)
--print("------------------")
--rooms_searching=rooms_get
local n=#rooms_searching -- 从1-searching表的总数
for i=1,n do --开始循环了,比如房间1开始
table.insert(rooms_searched,rooms_searching) --在已经搜过的房间加入进searched,房间1加入到searched
table.insert(rooms_find,rooms_searching) --加入到find里面,房间1加入到find
--print(rooms_searching[1])
--print("---------------------------")
local new_tab=data[rooms_searching] -- new新表等房间1,周围的房间,比如2|3
rooms_find=table_merge(rooms_find,new_tab) --把find表和这个2|3 合并
rooms_get=table_merge(rooms_get,new_tab) --把get表和这个2|2合并
end
rooms_get=table_dumps(rooms_get) --执行完一次searching的时候将get 相同元素合并一下
rooms_get=table_delete(rooms_get,rooms_searched) -- 从get 中删除 已经搜过的searched
rooms_searching=table_delete(rooms_get,rooms_searched) --将这个剔除元素get表给searching,做下一次搜索用,好像这里写错了,不管了
end--range loop --周围5个都遍历好了
rooms_find=table_dumps(rooms_find) --将最后的find表里面的相同元素合并一下
---以下可以不管,主要用另外一张表zonerooms来剔除房间的,很多时候我们只要当前区域的房间,用zonerooms剔除一下
---包括剔除cost大于10000的房间等等
if type(zonerooms)=="table" then
new_tab={}
rooms_searched={}
for k,v in ipairs(zonerooms) do
rooms_searched[v]=1
end
for k,v in ipairs(rooms_find) do
if rooms_searched[v]==1 and roomcost[v]<=10000 then
table.insert(new_tab,v)
end
end
rooms_find=new_tab
table.sort(rooms_find)
end
if type(zonerooms)~="table" then
new_tab={}
for k,v in ipairs(rooms_find) do
if roomcost[v]<=10000 then
table.insert(new_tab,v)
end
end
rooms_find=new_tab
table.sort(rooms_find)
end
print("ok")
print(rooms_find)
return rooms_find --返回rooms_find

Lua结束了嘛,远没有结束,这只是开始,由于不习惯在notepad里面写在到软件里面调试,而且只习惯 触发--命令模式。那么CMUD还是不错的选择。
如果用Lua table写一个地图数据库,实现cmud %pathfrom() 功能就好了。
想想而已,基本不可能,就一个roomcost功能估计lua都很难实现吧。有时间就研究一下不带cost权重的寻路map模块吧。
最好呼唤大牛出现,直接利用cmud的地图,能实现%pathfrom()功能,这种基础性研究还是缺乏啊。

后记:
自从用了lua计算以后,挂很多cmud腰也不疼了,吃饭也香了:)

北大侠客行MUD,中国最好的MUD
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2015-8-25 06:05:10 | 显示全部楼层
膜拜
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2015-8-25 07:22:46 | 显示全部楼层
回复 1# oolong

这也叫编程零基础,楼主你简直是高端黑
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2015-8-25 07:51:28 | 显示全部楼层
就是cmud #help里面介绍即可啊
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2015-8-25 08:49:31 | 显示全部楼层
看到上面”完全不懂编程“,再看看下面大段大段的程序,不明真相的群众顿时表示只能掩面泪奔了。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2015-8-25 10:10:46 | 显示全部楼层
看怎么定义编程了,如果是zmud的机器人制作也叫编程那么,我应该算精通编程了。。。
zmud 里面 #loop n 其实就和 for i=1,n do 一样
#if 和 Lua 的if 一样的
...
所以看cmud的介绍就能轻易写出lua机器人了,只是这个机器人很原始而已
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2015-8-25 11:18:33 | 显示全部楼层
看怎么定义编程了,如果是zmud的机器人制作也叫编程那么,我应该算精通编程了。。。
oolong 发表于 2015-8-25 10:10 AM



    看到这句,满满的都是泪。。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2015-8-25 11:35:30 | 显示全部楼层
看怎么定义编程了,如果是zmud的机器人制作也叫编程那么,我应该算精通编程了。。。
zmud 里面 #loop n 其 ...
oolong 发表于 2015-8-25 10:10 AM


痛苦的把头别到一边。。。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2015-8-25 11:45:59 | 显示全部楼层
如果timer也算编程,我也是编程大师了。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
 楼主| 发表于 2015-8-25 12:57:50 | 显示全部楼层
各位编程大师好啊
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-24 05:38 AM , Processed in 0.011900 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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