Algorithm 以最少的移动同时解决所有4x4迷宫

Algorithm 以最少的移动同时解决所有4x4迷宫,algorithm,path-finding,maze,Algorithm,Path Finding,Maze,我遇到了一个非常有趣的问题,我们有一个4x4迷宫,里面有一个机器人试图到达目标。问题是,您必须找到一系列预定义的命令,这些命令将始终导致机器人达到目标 假设我们有一个这样的迷宫: x . . . . # # . . # # . . . . g 例如,可以使用命令序列DDDRRR或RRRDDD来解决这个特定的迷宫,其中R=right,L=left,U=up,D=down(duh) 然而,这两个序列都不能解决这个迷宫: x . # . . . . . # . . . . . . g 0 1 0

我遇到了一个非常有趣的问题,我们有一个4x4迷宫,里面有一个机器人试图到达目标。问题是,您必须找到一系列预定义的命令,这些命令将始终导致机器人达到目标

假设我们有一个这样的迷宫:

x . . .
. # # .
. # # .
. . . g
例如,可以使用命令序列
DDDRRR
RRRDDD
来解决这个特定的迷宫,其中R=right,L=left,U=up,D=down(duh)

然而,这两个序列都不能解决这个迷宫:

x . # .
. . . .
# . . .
. . . g
0 1 0 0
0 1 0 0
0 0 0 0
0 1 0 0

机器人总是从左上角开始,目标总是在右下角,迷宫总是一个2D 4x4矩阵

我已经实现了一个算法,使我获得了78条命令的成功序列。我确信至少存在29条命令的解决方案(这是由其他人完成的)

这个问题实际上已经存在了几年,因此我丢失了当时使用的算法,但是基本思想是搜索我生成的所有迷宫,并始终选择导致解决最多迷宫的路线。这实际上给了我一个长度略大于78的序列;我用手减少了一些多余的命令

是的,暴力强迫将像往常一样需要几年的时间

如果我能记起的话,可能的迷宫不到4000个(可能的迷宫是在左上角和右下角之间存在一条路径)

在执行命令期间,机器人只需访问目标至少一次就足够了。也就是说,它不必在最后一次命令后坐在球门上

我有没有引起任何人的兴趣?我应该如何处理这个问题以获得更有效的答案?感谢您的考虑:)


有趣的事: 这是一个(非常)匆忙拼凑起来的Java。它应该编译并运行:) 该程序可以同时播放约4000个迷宫。程序接受上、左、下和右的输入(w、a、s、d),然后模拟移动,显示一些统计信息。如果您尝试,您可以在屏幕上看到每个迷宫中每个位置的障碍物总数,以及每个迷宫当前位置的总数。很难解释:)如果你有问题问我

再次。。。不要介意那些可怕的代码。它是在20分钟内写成的


进展 我间接地从中得到了这个想法,并在聊天中对其进行了进一步的建模。这个想法是找到一个序列来解决迷宫的右侧。也就是说,解决至少一半迷宫的解决方案,当镜像并从一开始再次运行时解决剩余的迷宫

说明:

首先找到一个序列,其第一个命令是正确的,该序列可以解决以下问题,例如:

x . # .
. . . .
# . . .
. . . g
0 1 0 0
0 1 0 0
0 0 0 0
0 1 0 0
一个这样的序列是
RDDRRRD
。此序列的镜像对应项是这样的:

R -> D
D -> R
L -> U
U -> L
这意味着
RDDRRRD
->
DRRDDDR

现在,这个镜像序列解决了迷宫吗?不,它卡住了。因此,即使对于这个迷宫,它也不是一个有效的序列。我们必须找到这样一个序列,它解决了至少一半的迷宫,当从一开始再次运行时,它的镜像对应解决了其余的迷宫

在简单地强制所有可能的R、D和L排列之后,我得到了一些可能的序列

一个这样的序列是
rrdrdrldrdr

现在下一个问题是,在运行这个序列之后,剩余的迷宫处于随机混乱中。我们需要得到最短的(最佳的)可能的序列,这将使所有剩余的迷宫回到起始位置(0,0)。这部分我只是手工做的(现在)。我的答案绝对不是最优的,但它让所有的迷宫回到了起点

此序列是
ldlulull

在此之后,我们只需运行镜像序列,
ddrdrdrdrd
,就解决了所有的难题

这一特定序列的整体:

rrdrdrldrdrludlululululullddrdrdrdrdrdrd
-41移动

虽然这是一个有希望的里程碑,但距离最佳解决方案还有12步之遥。欢迎有任何见解!同时,感谢迄今为止帮助我的所有人:)

序列缩小 到目前为止,我还无法通过编程获得比58步长序列更好的答案。然而,使用上面描述的方法,只需手工研磨字符,我就能够将序列缩短到只有33个字符长。这一顺序如下:

RRDRRDRLDRDLULLLLDDRDDRRRDDR
-33步


虽然序列现在非常接近29目标,但我仍然在寻找一种以编程方式获得的相同质量的解决方案。在从序列中删除字符时,我没有使用任何逻辑-我只是删除了一个字符,然后检查它是否解决了所有迷宫,冲洗并重复。

听起来你可以在这里使用*搜索,将所有迷宫中的最大启发式作为启发式。这保守地近似于解决方案的距离,可能会给出合理的第一种方法

由于所有迷宫都很小,因此可以通过从每个迷宫的末端反向运行BFS来为每个迷宫构建一个完美的启发式,以预计算从每个点到每个迷宫目标的距离。如果您将其缓存在查找表中,您可能会有一个每个迷宫的启发式算法,它可以完美地告诉您剩余的最小移动次数

我还没有真正尝试过,所以这仍然有待实验验证,但我认为这将是解决方案的一个很好的起点

编辑我刚刚读到一张便条,上面说每个机器人必须至少访问目标一次,而不一定要在目标上结束。在这种情况下,将启发式修改为距离任何尚未移动的机器人的最大距离
x # * *    . x * *
* * * *    * * * *
* * * *    * * * *
* * * g    * * * g
. # * *    . x * *    . . * *
x * * *    * # * *    * x * *
* * * *    * * * *    * * * *
* * * g    * * * g    * * * g
x # * *
. # * *
. # # *
. . . g
xx#x
x#xx
xxxx
xx#x
x#xx
#xxx
xxxx
xxxx 
xx#x
x#xx
xxxx 
xxxx 
xxx#
xx#x
xxxx
xxxx
xxxx    xxxx    xxxx    xxxx    xxxx    xxxx
xxx#    x#xx    xx#x    xxxx    xxxx    xxxx
xxxx    #xxx    x#xx    xxx#    x#xx    xx#x
xxxx    xxxx    xxxx    xxxx    #xxx    x#xx
xxxx
xxx#
xx#x
xxxx
xxxx    xxxx
xxxx    xxxx
xxx#    xxxx
xx#x    xxx#
RRDRRDRLDRDLDLULLLDDRDDRDRURRDRD (32 characters)
RRDRRDRLDRDLDLULLLDDRDDRDURRDRRD (32 characters)
RRDRRDRLDRDLDLULLLDDRDDDURDRRDR (31 characters)
        //// 33 char solution
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURRRDDR", 33); // 33 chars, 00:00:00.0032911 Finished, 1 solution, best 33, visitedList length 0

        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURRRDD", 33); // 32 chars, 00:00:00.0308543 Finished, 1 solution, best 33, visitedList length 3
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURRRD", 33); // 31 chars, 00:00:00.0871429  Finished, 2 solutions, best 33, visitedList length 14
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURRR", 33); // 30 chars, 00:00:00.2536057  Finished, 2 solutions, best 33, visitedList length 49

        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURR", 33); // 29 chars, 00:00:01.0540762  Finished, 8 solutions, best 32, visitedList length 205
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRUR", 33); // 28 chars, 00:00:03.8993877  Finished, 7 solutions, best 32, visitedList length 771
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRU", 33); // 27 chars, 00:00:10.4225150  Finished, 7 solutions, best 32, visitedList length 2069
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDR", 33); // 26 chars, 00:00:24.2552908  Finished, 7 solutions, best 32 visitedList length 4484
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRD", 33); // 25 chars, 00:01:44.3295165  Finished, 14 solutions, best 32, visitedList length 16600
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDR", 33); // 24 chars, 00:16:18.6666045  Finished, 14 solutions, best 32, visitedList length 77106

        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRURR", 32); // 29 chars, 00:00:00.3134699  Finished, 1 solution, best 32, visitedList length 66
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRUR", 32); // 28 chars, 00:00:01.1053798  Finished, 1 solution, best 32, visitedList length 238
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDRU", 32); // 27 chars, 00:00:03.5172143  Finished, 1 solution, best 32, visitedList length 730
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRDR", 32); // 26 chars, 00:00:07.1336796  Finished, 1 solution, best 32, visitedList length 1413
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDRD", 32); // 25 chars, 00:00:26.4906874  Finished, 2 solutions, best 32, visitedList length 5084
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDDR", 32); // 24 chars, 00:02:52.8134463  Finished, 2 solutions, best 32, visitedList length 24623
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDD", 32); // 23 chars, cancelled after 6 seconds, finds RRDRRDRLDRDLDLULLLDDRDDDURDRRDR (31 chars)

        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRDD", 31); // 23 chars, 00:01:58.4861802  Finished, 1 solution, best 31, visitedList length 18835
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDRD", 30); // 22 chars, 00:00:34.6602434  Finished, 0 solution, best distance 44, visitedList length 21084  
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDDR", 30); // 21 chars, 00:04:32.2439241  Finished, 0 solution, best distance 44, visitedList length 78500
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLDD", 30); // 20 chars, cancelled after 10 minutes, found no solution, best distance 44
        //var aStarSearch = new AStarSearch("RRDRRDRLDRDLDLULLLD", 30); // 19 chars, cancelled after 10 minutes, found no solution, best distance 44

        //var aStarSearch = new AStarSearch("R", 29); // Complete search, would take waaay too long and consume much memory 
RRDRRDRDLDLDULLDLDRDDURDRRDRR
import Data.List(tails,nub)
import Data.Bits
import Numeric(showHex)
import System.Environment(getArgs)

data Lit = Lit Bool [Char]

type Wall = Int -- [Bool]

lit s = Lit True s
litS s = lit (s "")

inv (Lit b s) = Lit (not b) s

instance (Show Lit) where
  showsPrec _ (Lit b s) = showString (if b then "" else "~") . showString s
  showList = showString . unwords . (map show)

showDir d = showChar ("NESW"!!d)
dir n d = litS $ showChar 'D' . shows n . showDir d

showStuff n s p = showHex n . showChar (['A'..]!!p) . shows s
pos n s p = litS $ showChar 'P' . showStuff n s p
posh n s p h = litS $ showDir h . showStuff n s p

opdir :: Int -> Int
opdir d = (d+2) `mod` 4

(<-&) :: Lit -> [Lit] -> [[Lit]]
l <-& ls = lt : lf where 
  lt = l : map inv ls                   --      l or ~l1 or ~l2 ...
  lf = [ [ inv l, li ] | li <- ls ]     --      ~l or li , all i

(<-|) :: Lit -> [Lit] -> [[Lit]]
l <-| ls = lf : lt where 
  lf = (inv l) : ls                     --      ~l or l1 or l2 ...
  lt = [ [ l, inv li ] | li <- ls ]     --      l or ~li , all i

atmostone l = [ [inv a, inv b] | (a:bs) <- tails l, b <- bs ]

dirconds n = concat [ atmostone [ dir i d | d <- [0..3]]
                    | i <- [0..n-1] ]

boundary p = (p<5) || (p>24) || (p `mod` 5 == 0)
positions = [ p | p<-[0..24], not (boundary p) ]
start = head positions
stop = last positions
wp = [ if boundary p then 0 else p - 4 - p `div` 5 | p <- [0..23]]
       ++ [1,0,0,0,0,0]

wallat :: Wall -> Int -> Bool
wallat w p = testBit (4*w+1) (wp!!p) -- (True:False:w) !! (wp!!p)

jump:: Int -> Int -> Int
jump pos dir =  pos + ([-5,1,5,-1]!!dir)

freestep :: Wall -> Int -> Int -> Maybe Int
freestep w pos dir = let np = jump pos dir in 
           if wallat w np
              then Nothing
              else Just np

reach :: Wall -> Int -> [Int]
reach w p = [ np | Just np <- map (freestep w p) [0..3] ]

reachable :: Wall -> [Int]
reachable w = go [start] [start] where
                 go seen [] = seen
                 go seen front = let new = nub [ n | p <- front,
                                                     n <- reach w p,
                                                     n `notElem` seen ]
                                 in go (seen++new) new

nicereachable :: Wall -> Maybe [Int]
nicereachable w =
  let r = reachable w
  in if and [ p `elem` r || wallat w p | p <- positions]
       then Just r
       else Nothing

mazestepdirposconds w n p d =
  let ph = posh w (n+1) p d
      conds = case freestep w p d of
                (Just np) -> ph <-& [ pos w n np, dir n (opdir d) ]
                Nothing   -> ph <-& [ pos w n p, dir n d ]
  in (ph,conds)

mazestepposconds w n p =
  let cnds = map (mazestepdirposconds w n p) [0..3]
      ps = pos w (n+1) p
  in ( ps <-| (map fst cnds)) ++ (concatMap snd cnds)

mazestepconds w r n = concatMap (mazestepposconds w n) r

mazeconds w len r = [ pos w 0 start ] :
                    [ pos w i stop | i <- [6..len] ] :
                    (concat [ atmostone [ pos w s p | p <- positions ] 
                                          | s<-[0..len] ]) ++
                    (concatMap (mazestepconds w r) [0..len-1])

conds l = dirconds l ++ 
          concat [ mazeconds w l r |
                   (w,Just r) <- [(i,nicereachable i)|i<-[0..2^14-1]]]

main = do
         [n] <- getArgs
         mapM_ print $ conds (read n)