cappuccino 发表于 2015-3-3 20:15:29

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

厕 所蹲坑   无聊手机上网推车的人不少推车的难点好像就是解决乱入he寻找伙计   打算写个解决这两个问题得教学贴不知道违规否?也不知道需求有多大!如果不违规明天开始慢慢写了就。

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

北大侠客行MUD,中国最好的MUD

cappuccino 发表于 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 = string.sub(szFullString, nFindStartIndex, string.len(szFullString))
    break
   end
   nSplitArray = 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,";"))-------在需要用到某个路径走之前要先做一步这个工作。
      
到目前为止实际上只是接到镖之后,推车走之前的准备工作。下面才开始推车流程的第一阶段:

cappuccino 发表于 2015-3-3 20:16:56

无论是推车行程的那个阶段,我都是利用按照顺序遍历执行数组的方向完成的:
用到的函数:    lj=........------------------lj是bianli函数要遍历的数组,比如到nc的镖,要先将转化完的路径赋值给lj这个遍量
    function bianli()
      local i=tonumber(GetVariable("bianli_i"))-------bianli_i是个计数器,表明现在走到数组的哪一个元素了。
      
         if tonumber(GetVariable("hubiao"))==1 then ------------hubiao个作为一个标志:如果为1就表明现在不带着镖车走,如果为0就得带着镖车走。
                   if lj==nil then Note("已经走完了,还走个屁啊") Executereturn end -------数组遍历完成之后就不要遍历了再
                   local s1="当前行走段一共"..tostring(table.getn(lj)).."步,现在为 第"..GetVariable("bianli_i").."步"..",当前命令:"..lj
                
                   Note(s1)---------以上两行是用来提醒自己的。
                   Execute(lj)------这才是行走的命令
         elseif tonumber(GetVariable("hubiao"))==0 then
                   if lj==nil then Note("已经走完了,还走个屁啊") return end
            
                   local s1="当前行走段一共"..tostring(table.getn(lj)).."步,现在为 第"..GetVariable("bianli_i").."步"..",当前命令:"..lj
                   Note(s1)
                   Execute("gan che to "..lj..";xixi")
         end
    end具体使用方法:开始走的时候bianli_i赋值为1,然后执行函数bianli(),触发里每当看到出口,就证明该步行走成功,然后继续执行bianli(),这样当数组lj遍历执行完毕后就走到目的地了,
ps:中间遇到劫匪时候,需要将劫匪打跑后继续执行bianli()

走到目的地之后,也就是从左二把走到了南昌了,下面该步入正题了,也就是该寻找伙计了。

cappuccino 发表于 2015-3-3 20:19:19

寻找伙计的基本原理:
         1 放下镖车 ,遍历该城市的每个房间直到找到伙计,也就是遍历执行blnc这个路径直到找到伙计。找到伙计停止后,截取从起点到伙计房间走的所有方向,也就是对 blnc的第一个元素,到找到伙计后的bianli_i之间截取。由于这中间的很多房间是无效房间,比如本来n e就走到了,但是路径当中可能走的是n n n s s e,这时候需要将截取后的路径最简化。
         2 翻转路径回到镖车所在地,继续按照刚才简化后的推到伙计那里
         3 回到左二把那里继续下一次任务
具体的函数实现:当收到第一阶段结束,到了第二阶段找伙计时候:
SetVariable("hubiao","1")-----表示下一步走的时候不带车走。
zzlj=lj------把刚才已经走过的路径储存起来,因为现在lj要被赋值第二阶段走的路径了。
zzbianli_i=GetVariable("bianli_i")-----把刚才已经走过了多少步储存起来
lj=Split(lj2,";")---最开始接到镖的时候lj2已经被赋值blnc了
lj=zhfxlj(lj)
SetVariable("bianli_i","1")---以上四行是做遍历找伙计的准备工作然后就可以执行函数bianli()开始找伙计了,方法前一篇帖子说过了,捡到出口就执行bianli()
当发现了伙计之后,停止执行bianli()
先记录从起点到现在走了那些方向找到伙计了    local templj={}
    for i=1,tostring(GetVariable("bianli_i")) do
         table.insert(templj,lj)
         i=i+1
    end然后该将步数最简化,lj=templj
lj=jhlj(lj)用到的jhlj()函数代码如下
    function jhlj(nowlj)
      local nowlj=nowlj
      local inowlj=1
      if nowlj==nil then Note("空的简化个P啊") return end
      
      local function jhlj1()
         if nowlj==nil thenreturn
         elseif nowlj==revfx(nowlj) then table.remove(nowlj,inowlj) table.remove(nowlj,inowlj) inowlj=1 jhlj1() end
               inowlj=inowlj+1
               jhlj1()
      end
      jhlj1()
      returnnowlj
    end将得到的简化路径添加到第一阶段的路径里,得到从左二把一直的伙计的完整路径(目前存储在zzlj变量里),以便于交镖之后翻转路径回到左二把那里for i=1,table.getn(lj) do
    table.insert(zzlj,lj)
    i=i+1
end然后该翻转路径回到镖车所在点。lj=revlj(lj)revlj是个翻转路径函数,也就是将n w s 变为 n e s ,代码如下function revlj(nowlj)
   local lj=nowlj
   local i=table.getn(lj)
   local newlj={}
   for newi=1,i do
      newlj=revfx(lj)
   end
   return newlj
end

function revfx(fx)
       if fx=="enterbj" then return "outbj"    end
       if fx=="outbj" then return "enterbj"    end
       if fx=="swboxiaolu" then return "boxiaolune"    end
       if fx==nil then return   end
       if fx=="south" then return "north"    end
       if fx=="east" then return "west"   end
       if fx=="west" then return "east"   end
       if fx=="north" then return "south"   end
       if fx=="southup" then return "northdown"   end
       if fx=="southdown" then return "northup"   end
       if fx=="westup" then return "eastdown"   end
       if fx=="westdown" then return "eastup"   end
       if fx=="eastup" then return "westdown"   end
       if fx=="eastdown" then return "westup"   end
       if fx=="northup" then return "southdown"   end
       if fx=="northdown" then return "southup"   end
       if fx=="northwest" then return "southeast"   end
       if fx=="northeast" then return "southwest"   end
       if fx=="southwest" then return "northeast"   end
       if fx=="southeast" then return "northwest"   end
       if fx=="enter" then return "out"   end
       if fx=="out" then return "enter"   end
       if fx=="up" then return "down"   end
       if fx=="down" then return "up"   end

       if fx=="u" then return "d"   end
       if fx=="d" then return "u"   end
       if fx=="s" then return "n"    end
       if fx=="e" then return "w"   end
       if fx=="w" then return "e"   end
       if fx=="n" then return "s"   end
       if fx=="su" then return "nd"   end
       if fx=="sd" then return "nu"   end
       if fx=="wu" then return "ed"   end
       if fx=="wd" then return "eu"   end
       if fx=="eu" then return "wd"   end
       if fx=="ed" then return "wu"   end
       if fx=="nu" then return "sd"   end
       if fx=="nd" then return "su"   end
       if fx=="nw" then return "se"   end
       if fx=="ne" then return "sw"   end
       if fx=="sw" then return "ne"   end
       if fx=="se" then return "nw"   end
       return fx
end如果到目前为止你看懂了,那找伙计的就不用再说了,回到镖车起点继续SetVariable("bubiao","0")推着车就走到伙计那里去了,然后hubiao为1,翻转路径,就回到左二把那里去了

cappuccino 发表于 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了,
具体的代码实现:---------------深度遍历-------------------------------------------------------------
------------------------------------------------------------------------------------allchukou={}
cengshu=0
gotorightlj={}
gotorightljb={}
goforward=1
---------------触发每前进一步层数加1并抓取当前出口,出口列表去除来的反方向以及不可行走方向
---------------如果回退一步层数减1
---------------所有走的方向存在数组gotorightlj里
---------------最后简化路径、反转路径
function sdbianli()
    maxcengshu=tonumber(GetVariable("maxcengshu"))
    if allchukou==nil then Execute("say 遍历结束")return
    elseif cengshu==maxcengshu or allchukou==nil then
            goforward=0
   Note("会退一步")
            if gotorightlj~=nil then
             Execute(revfx(gotorightlj))
             table.remove(gotorightlj,table.getn(gotorightlj))
   else
          Execute("set action 遍历全部结束")
   end
   cengshu=cengshu-1
   return
    else
       Note("前进一步")
       -------------------------------------------------------碰到挡路或者过不去
---table.remove(gotorightlj)
---sdbianli()
---cengshu=cengshu-1
       goforward=1
       Execute(allchukou)
       table.insert(gotorightlj,allchukou)
       table.remove(allchukou,1)
       cengshu=cengshu+1
    end不知道这个当贴不当贴

cappuccino 发表于 2015-3-3 20:20:08

乱入深度少,所以环形不容易出现
找伙计深度太深了

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

难的是迷宫的处理,就是那种n之后s回不到原来地方的。。。。

cappuccino 发表于 2015-3-3 20:20:47

我这是壮大推车队伍
另外给学mush的增加点信心
只用用最简单的几个语句也能写出机器人。

(完)

cappuccino 发表于 2015-3-3 20:34:44

回复 8# suzhige


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

                                  —— Cappuccino

hkyyxss 发表于 2015-3-3 20:52:04

回复 8# suzhige


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


   over

kman 发表于 2015-6-1 17:15:30

看了一遍不是很懂
页: [1] 2
查看完整版本: [转]mush版本推车机器人教学贴 作者:huacuoh