北大侠客行MUD论坛

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

[转]mush版本推车机器人教学贴 作者:huacuoh

[复制链接]
发表于 2015-3-3 20:15:29 | 显示全部楼层 |阅读模式
厕 所蹲坑   无聊手机上网  推车的人不少  推车的难点好像就是解决乱入he寻找伙计   打算写个解决这两个问题得教学贴  不知道违规否?也不知道需求有多大!如果不违规明天开始慢慢写了就。

声明:自己本身纯业余 代码极度不规范 大家凑合看把   主要好多代码自己都忘了什么意思了   正好利用这个机会自己整理下思路

北大侠客行MUD,中国最好的MUD
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-3-3 20:16:00 | 显示全部楼层
先以接到左二把那里推往南昌的镖为例说一下我的护镖流程:
1 实现需要录制两个路径:一个是从左二把走到南昌的路径;另一个是遍历所有南昌城房间的路径。
   zuo_nc="s;s;sw;s;s;s;s;s;s;s;s;nw;n;nw;n;n;n;n;set action 第一阶段结束,赶快点开始找伙计"-------最后一个的目的是为了设置一个标志,提示自己此时第一阶段形成结束   
blnc="n;e;w;w;e;n;n;nw;ne;w;n;n;s;s;su;se;s;s;s;e;n;s;s;enter;w;e;e;w;out;n;e;e;eu;eu;wd;wd;w;w;w;w;n;s;s;n;w;w;wu;wu;nu;enter;w;e;e;w;n;s;out;sd;wu;ed;ed;ed;e;e;e;s;w;e;e;w;s;s;n;n;n"

现在的两个路径为字符串形式,为了方便一步一步走,需要将他们分解成数组。也就是将"n;w;s"形式的路径,分解成{"n","w","s"}的形式,此时用到下面的函数
function Split(szFullString, szSeparator)
local nFindStartIndex = 1
local nSplitIndex = 1
local nSplitArray = {}
while true do
   local nFindLastIndex = string.find(szFullString, szSeparator, nFindStartIndex)
   if not nFindLastIndex then
    nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, string.len(szFullString))
    break
   end
   nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, nFindLastIndex - 1)
   nFindStartIndex = nFindLastIndex + string.len(szSeparator)
   nSplitIndex = nSplitIndex + 1
end
return nSplitArray
end

举例:Split(zuo_nc,";"),函数返回值就为已经分解为数组的zuo_nc的路径。

   由于推车的时候,gan che to n这种命令是无效的,必须写成gan che to north这种形式,所以还要把{"n","w","s"}这种形式转化成{"north","west","south"}这种形式,用到一下函数:
-------------------------------简化方向转完整方向----------------------
function zhfx(fx)
       local fx=fx
       if fx=="u" then return "up"   end
       if fx=="d" then return "down"   end
       if fx=="s" then return "south"    end
       if fx=="e" then return "east"   end
       if fx=="w" then return "west"   end
       if fx=="n" then return "north"   end
       if fx=="su" then return "southup"   end
       if fx=="sd" then return "southdown"   end
       if fx=="wu" then return "westup"   end
       if fx=="wd" then return "westdown"   end
       if fx=="eu" then return "eastup"   end
       if fx=="ed" then return "eastdown"   end
       if fx=="nu" then return "northup"   end
       if fx=="nd" then return "northdown"   end
       if fx=="nw" then return "northwest"   end
       if fx=="ne" then return "northeast"   end
       if fx=="sw" then return "southwest"   end
       if fx=="se" then return "southeast"   end
       return fx
end
-------------------------------简化方向转完整方向   
   
-------------------------------简化方向的路径转完整方向的路径----------------------
function zhfxlj(lj)
    local lj=lj
    local temi=1
    for i,v in ipairs(lj) do lj=zhfx(v) end
    return lj
end

总结:接到推往南昌的镖,之后:
       lj1=zuo_nc----推镖车走的第一阶段
       lj2=blnc-----推镖车走的第二阶段
       lj1=zhfxlj(Split(lj1,";"))-------在需要用到某个路径走之前要先做一步这个工作。
      
到目前为止实际上只是接到镖之后,推车走之前的准备工作。下面才开始推车流程的第一阶段:
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-3-3 20:16:56 | 显示全部楼层
无论是推车行程的那个阶段,我都是利用按照顺序遍历执行数组的方向完成的:
用到的函数:
  1.     lj=........------------------lj是bianli函数要遍历的数组,比如到nc的镖,要先将转化完的路径赋值给lj这个遍量
  2.     function bianli()
  3.         local i=tonumber(GetVariable("bianli_i"))-------bianli_i是个计数器,表明现在走到数组的哪一个元素了。
  4.       
  5.            if tonumber(GetVariable("hubiao"))==1 then ------------hubiao个作为一个标志:如果为1就表明现在不带着镖车走,如果为0就得带着镖车走。
  6.                    if lj==nil then Note("已经走完了,还走个屁啊") Execute  return end -------数组遍历完成之后就不要遍历了再
  7.                    local s1="当前行走段一共"..tostring(table.getn(lj)).."步,现在为 第"..GetVariable("bianli_i").."步"..",当前命令:"..lj
  8.     [i]              
  9.                    Note(s1)---------以上两行是用来提醒自己的。
  10.                    Execute(lj[i])------这才是行走的命令
  11.            elseif tonumber(GetVariable("hubiao"))==0 then
  12.                    if lj==nil then Note("已经走完了,还走个屁啊") return end
  13.             
  14.                    local s1="当前行走段一共"..tostring(table.getn(lj)).."步,现在为 第"..GetVariable("bianli_i").."步"..",当前命令:"..lj[i]
  15.                    Note(s1)
  16.                    Execute("gan che to "..lj[i]..";xixi")
  17.            end
  18.     end
复制代码
具体使用方法:开始走的时候bianli_i赋值为1,然后执行函数bianli(),触发里每当看到出口,就证明该步行走成功,然后继续执行bianli(),这样当数组lj遍历执行完毕后就走到目的地了,
ps:中间遇到劫匪时候,需要将劫匪打跑后继续执行bianli()

走到目的地之后,也就是从左二把走到了南昌了,下面该步入正题了,也就是该寻找伙计了。
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-3-3 20:19:19 | 显示全部楼层
寻找伙计的基本原理:
         1 放下镖车 ,遍历该城市的每个房间直到找到伙计,也就是遍历执行blnc这个路径直到找到伙计。找到伙计停止后,截取从起点到伙计房间走的所有方向,也就是对 blnc的第一个元素,到找到伙计后的bianli_i之间截取。由于这中间的很多房间是无效房间,比如本来n e就走到了,但是路径当中可能走的是n n n s s e,这时候需要将截取后的路径最简化。
         2 翻转路径回到镖车所在地,继续按照刚才简化后的推到伙计那里
         3 回到左二把那里继续下一次任务
具体的函数实现:
  1. 当收到第一阶段结束,到了第二阶段找伙计时候:
  2. SetVariable("hubiao","1")-----表示下一步走的时候不带车走。
  3. zzlj=lj------把刚才已经走过的路径储存起来,因为现在lj要被赋值第二阶段走的路径了。
  4. zzbianli_i=GetVariable("bianli_i")-----把刚才已经走过了多少步储存起来
  5. lj=Split(lj2,";")---最开始接到镖的时候lj2已经被赋值blnc了
  6. lj=zhfxlj(lj)
  7. SetVariable("bianli_i","1")---以上四行是做遍历找伙计的准备工作
复制代码
然后就可以执行函数bianli()开始找伙计了,方法前一篇帖子说过了,捡到出口就执行bianli()
当发现了伙计之后,停止执行bianli()
先记录从起点到现在走了那些方向找到伙计了
  1.     local templj={}
  2.     for i=1,tostring(GetVariable("bianli_i")) do
  3.          table.insert(templj,lj[i])
  4.          i=i+1
  5.     end
复制代码
然后该将步数最简化,
  1. lj=templj
  2. lj=jhlj(lj)
复制代码
用到的jhlj()函数代码如下

  1.     function jhlj(nowlj)
  2.         local nowlj=nowlj
  3.         local inowlj=1
  4.         if nowlj[inowlj]==nil then Note("空的简化个P啊") return end
  5.       
  6.         local function jhlj1()
  7.            if nowlj[inowlj+1]==nil then  return
  8.            elseif nowlj[inowlj]==revfx(nowlj[inowlj+1]) then table.remove(nowlj,inowlj) table.remove(nowlj,inowlj) inowlj=1 jhlj1() end
  9.                inowlj=inowlj+1
  10.                jhlj1()
  11.         end
  12.         jhlj1()
  13.         return  nowlj
  14.     end
复制代码
将得到的简化路径添加到第一阶段的路径里,得到从左二把一直的伙计的完整路径(目前存储在zzlj变量里),以便于交镖之后翻转路径回到左二把那里
  1. for i=1,table.getn(lj) do
  2.     table.insert(zzlj,lj[i])
  3.     i=i+1
  4. end
复制代码
然后该翻转路径回到镖车所在点。
  1. lj=revlj(lj)
复制代码
revlj是个翻转路径函数,也就是将n w s 变为 n e s ,代码如下
  1. function revlj(nowlj)
  2.    local lj=nowlj
  3.    local i=table.getn(lj)
  4.    local newlj={}
  5.    for newi=1,i do
  6.         newlj[newi]=revfx(lj[i+1-newi])
  7.    end
  8.    return newlj
  9. end

  10. function revfx(fx)
  11.        if fx=="enterbj" then return "outbj"    end
  12.        if fx=="outbj" then return "enterbj"    end
  13.        if fx=="swboxiaolu" then return "boxiaolune"    end
  14.        if fx==nil then return     end
  15.        if fx=="south" then return "north"    end
  16.        if fx=="east" then return "west"   end
  17.        if fx=="west" then return "east"   end
  18.        if fx=="north" then return "south"   end
  19.        if fx=="southup" then return "northdown"   end
  20.        if fx=="southdown" then return "northup"   end
  21.        if fx=="westup" then return "eastdown"   end
  22.        if fx=="westdown" then return "eastup"   end
  23.        if fx=="eastup" then return "westdown"   end
  24.        if fx=="eastdown" then return "westup"   end
  25.        if fx=="northup" then return "southdown"   end
  26.        if fx=="northdown" then return "southup"   end
  27.        if fx=="northwest" then return "southeast"   end
  28.        if fx=="northeast" then return "southwest"   end
  29.        if fx=="southwest" then return "northeast"   end
  30.        if fx=="southeast" then return "northwest"   end
  31.        if fx=="enter" then return "out"   end
  32.        if fx=="out" then return "enter"   end
  33.        if fx=="up" then return "down"   end
  34.        if fx=="down" then return "up"   end

  35.        if fx=="u" then return "d"   end
  36.        if fx=="d" then return "u"   end
  37.        if fx=="s" then return "n"    end
  38.        if fx=="e" then return "w"   end
  39.        if fx=="w" then return "e"   end
  40.        if fx=="n" then return "s"   end
  41.        if fx=="su" then return "nd"   end
  42.        if fx=="sd" then return "nu"   end
  43.        if fx=="wu" then return "ed"   end
  44.        if fx=="wd" then return "eu"   end
  45.        if fx=="eu" then return "wd"   end
  46.        if fx=="ed" then return "wu"   end
  47.        if fx=="nu" then return "sd"   end
  48.        if fx=="nd" then return "su"   end
  49.        if fx=="nw" then return "se"   end
  50.        if fx=="ne" then return "sw"   end
  51.        if fx=="sw" then return "ne"   end
  52.        if fx=="se" then return "nw"   end
  53.        return fx
  54. end
复制代码
如果到目前为止你看懂了,那找伙计的就不用再说了,回到镖车起点继续SetVariable("bubiao","0")推着车就走到伙计那里去了,然后hubiao为1,翻转路径,就回到左二把那里去了
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-3-3 20:19:56 | 显示全部楼层
所谓的乱入,就是本来我设计好的行走路线是a b c d e,结果在走到c房间的时候却被系统推到m房间去了。
所以解决乱入的基本思路就是以m房间为中心点进行深度遍历,一直找到c房间时遍历停止。记录从m到c的路径,添加到原来的路径当中。
也就是1, 当在c房间时候记录下c房间的所有信息。
        2,乱入到m房间,打完劫匪后,镖车放下,深度遍历,、每走到一个房间和以前记录的正确的c房间信息作对比,如果相 同遍历停止,找到c房间,记录下从m到c房间的路径为n e的话,那么修正原来的路径(变量lj)为a b c (w s n e) d e,然后回到m房间从lj的第bianli_i+2步开始行走就ok了,
具体的代码实现:---------------深度遍历-------------------------------------------------------------
------------------------------------------------------------------------------------
  1. allchukou={}
  2. cengshu=0
  3. gotorightlj={}
  4. gotorightljb={}
  5. goforward=1
  6. ---------------触发每前进一步层数加1并抓取当前出口,出口列表去除来的反方向以及不可行走方向
  7. ---------------如果回退一步层数减1
  8. ---------------所有走的方向存在数组gotorightlj里
  9. ---------------最后简化路径、反转路径
  10. function sdbianli()
  11.     maxcengshu=tonumber(GetVariable("maxcengshu"))
  12.     if allchukou==nil then Execute("say 遍历结束")  return
  13.     elseif cengshu==maxcengshu or allchukou[cengshu+1][1]==nil then
  14.             goforward=0
  15.      Note("会退一步")
  16.             if gotorightlj[1]~=nil then
  17.              Execute(revfx(gotorightlj[table.getn(gotorightlj)]))
  18.              table.remove(gotorightlj,table.getn(gotorightlj))
  19.      else
  20.           Execute("set action 遍历全部结束")
  21.      end
  22.      cengshu=cengshu-1
  23.      return
  24.     else
  25.        Note("前进一步")
  26.        -------------------------------------------------------碰到挡路或者过不去
  27. ---table.remove(gotorightlj)
  28. ---sdbianli()
  29. ---cengshu=cengshu-1
  30.        goforward=1
  31.        Execute(allchukou[cengshu+1][1])
  32.        table.insert(gotorightlj,allchukou[cengshu+1][1])
  33.        table.remove(allchukou[cengshu+1],1)
  34.        cengshu=cengshu+1
  35.     end
复制代码
不知道这个当贴不当贴
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-3-3 20:20:08 | 显示全部楼层
乱入深度少,所以环形不容易出现
找伙计深度太深了

1 信息一摸一样的房间。事先录制路径时候,尽量避开信息一样的地方。
2 环形。把深度遍历稍微搞下变成广度遍历几率就会低很多。

难的是迷宫的处理,就是那种n之后s回不到原来地方的。。。。
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-3-3 20:20:47 | 显示全部楼层
我这是壮大推车队伍
另外给学mush的增加点信心
只用用最简单的几个语句也能写出机器人。

(完)
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-3-3 20:34:44 | 显示全部楼层
回复 8# suzhige


    我不是老师,我只是老师的搬运工~

                                  —— Cappuccino
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
发表于 2015-3-3 20:52:04 | 显示全部楼层
回复 8# suzhige


    解决办法,开始推出密信以前,不接那边的镖,或者不走那条路。


   over
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
发表于 2015-6-1 17:15:30 | 显示全部楼层
看了一遍不是很懂
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-3-28 05:31 PM , Processed in 0.010887 second(s), 14 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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