生活是迷宫:我们学会走路之前走错了路


30

输入:

包含以下字符的迷宫:

  • -- (水平墙);
  • | (垂直墙);
  • + (连接);
  • (步行空间);
  • I (入口);
  • U (出口)。

即输入看起来像这样:

 +--+--+--+--+--+--+--+--+--+--+ 
I               |     |        | 
 +  +--+--+--+  +  +  +  +--+  + 
 |           |     |  |  |     | 
 +--+--+--+  +--+--+  +  +  +--+ 
 |           |     |     |     | 
 +  +--+--+  +  +--+--+  +--+  + 
 |     |     |     |     |     | 
 +--+  +  +--+--+  +--+--+  +  + 
 |     |        |        |  |  | 
 +  +--+--+--+  +--+--+  +  +  + 
 |     |     |     |        |  | 
 +--+  +  +--+--+  +--+--+--+--+ 
 |  |  |                 |     | 
 +  +  +--+--+--+  +--+  +  +  + 
 |     |        |  |  |  |  |  | 
 +--+--+  +  +--+  +  +  +--+  + 
 |        |     |     |  |     | 
 +  +--+--+--+  +  +  +  +  +--+ 
 |           |     |  |         U
 +--+--+--+--+--+--+--+--+--+--+ 

输出:

最有效的,你应该走的路径从入口到迷宫的出口(通过迷宫),由字符表示得到指示向左,向右,向上和向下(即>; <; ^; v)。

挑战规则:

  • 您可以采用任何合理的格式输入。字符串数组,带换行符的单个字符串,2D字符数组等都是可能的输入格式。
  • 输出可以包含任何四个不同的字符。即><^v; →←↑↓; ⇒⇐⇑⇓; RLUD; 0123; ABCD; 等等。)。
  • 如果愿意,可以在输出中添加空格或尾随换行符;这是可选的。
  • 步数是按每平方计算的(请参见四+符号-正方形),而不是按字符计数。
  • 迷宫的大小可以从5x5到15x15,并且始终是正方形(因此不会有5x10迷宫的任何测试用例)。
  • 您可以假设每个迷宫从头到尾都有一条或多条有效路径,并且始终输出最短的路径(请参见测试用例4和5)。
  • 如果存在多个具有相同长度的路径,则可以选择要输出的路径(请参见测试用例6)。
  • 您不能“走出”迷宫的边界(请参见测试用例7和8)。

一般规则:

  • 这是,因此最短答案以字节为单位。
    不要让代码高尔夫球语言阻止您发布使用非代码高尔夫球语言的答案。尝试针对“任何”编程语言提出尽可能短的答案。
  • 标准规则适用于您的答案,因此允许您使用STDIN / STDOUT,具有适当参数的函数/方法,完整程序。你的来电。
  • 默认漏洞是禁止的。
  • 如果可能,请为您的代码添加一个带有测试的链接。
  • 另外,如有必要,请添加说明。

测试用例:

1. Input:
 +--+--+--+--+--+--+--+--+--+--+ 
I               |     |        | 
 +  +--+--+--+  +  +  +  +--+  + 
 |           |     |  |  |     | 
 +--+--+--+  +--+--+  +  +  +--+ 
 |           |     |     |     | 
 +  +--+--+  +  +--+--+  +--+  + 
 |     |     |     |     |     | 
 +--+  +  +--+--+  +--+--+  +  + 
 |     |        |        |  |  | 
 +  +--+--+--+  +--+--+  +  +  + 
 |     |     |     |        |  | 
 +--+  +  +--+--+  +--+--+--+--+ 
 |  |  |                 |     | 
 +  +  +--+--+--+  +--+  +  +  + 
 |     |        |  |  |  |  |  | 
 +--+--+  +  +--+  +  +  +--+  + 
 |        |     |     |  |     | 
 +  +--+--+--+  +  +  +  +  +--+ 
 |           |     |  |         U
 +--+--+--+--+--+--+--+--+--+--+ 

1. Output:
>v>>>vv<v>>v>v>>vvv>>>

2. Input:
 +--+--+--+--+--+ 
I   |        |  | 
 +  +--+--+  +  + 
 |        |  |  | 
 +  +--+  +  +  + 
 |  |  |     |  | 
 +  +  +--+  +  + 
 |        |     | 
 +--+  +  +--+--+ 
 |     |         U
 +--+--+--+--+--+ 

2. Output:
>vvv>>v>>>

3. Input:
 +--+--+--+--+--+ 
U      |        | 
 +  +  +--+--+  + 
 |  |     |     | 
 +--+--+  +  +--+ 
 |        |     | 
 +  +--+--+--+  + 
 |  |     |     | 
 +  +  +  +  +--+ 
 |     |         I
 +--+--+--+--+--+ 

3. Output:
<<<^<v<^^>>^<^<<

4. Input (test case with two valid paths):
 +--+--+--+--+--+ 
U      |        | 
 +  +  +--+--+  + 
 |  |           | 
 +--+--+  +  +--+ 
 |        |     | 
 +  +--+--+--+  + 
 |  |     |     | 
 +  +  +  +  +--+ 
 |     |         I
 +--+--+--+--+--+ 

4. Output:
<<^>^<^<<^<<     (<<<^<v<^^>>^<^<< is less efficient, and therefore not a valid output)

5. Input (test case with two valid paths):
                               I
+--+--+--+--+--+--+--+--+--+--+  +--+--+--+--+
|     |              |                    |  |
+  +  +  +--+--+--+  +  +--+--+  +--+--+  +  +
|  |     |        |     |        |     |     |
+--+--+--+  +--+  +  +--+--+--+--+  +--+--+--+
|     |  |  |  |     |     |           |     |
+  +  +  +  +  +--+  +  +  +  +--+--+  +--+  +
|  |        |        |  |     |        |     |
+  +--+--+--+  +--+--+  +  +--+  +--+--+  +--+
|  |     |     |        |  |     |     |     |
+  +--+  +  +--+  +--+--+  +--+--+  +  +--+  +
|  |     |        |     |           |        |
+  +  +--+--+--+--+  +  +--+--+--+  +--+  +--+
|     |     |        |        |  |     |     |
+--+--+--+  +  +--+--+  +--+  +  +--+  +--+  +
|              |     |     |        |  |  |  |
+  +--+--+--+--+  +  +  +--+--+--+  +  +  +  +
|     |  |     |  |  |        |        |  |  |
+--+  +  +  +  +  +  +--+--+  +  +  +--+  +  +
|     |     |  |  |  |           |  |     |  |
+--+  +--+--+  +  +  +  +--+--+--+  +  +  +  +
|     |        |  |  |     |        |  |  |  |
+  +--+  +--+--+  +  +--+--+  +  +--+  +  +  +
|        |     |  |     |     |  |     |  |  |
+--+--+--+  +  +  +--+  +  +--+--+  +--+  +  +
|  |        |        |     |        |     |  |
+  +  +--+--+--+--+  +--+--+  +--+--+  +--+  +
|  |              |              |     |     |
+  +  +  +--+--+--+--+--+--+--+--+  +--+  +--+
|     |                                |     |
+--+--+--+--+--+--+--+--+--+  +--+--+--+--+--+
                            U

5. Output:
v<<<v<vv<<v<v>>^>>^^>vvv>>>v>vv<vv<<v<v<^<^^^^<vvvvv<^<v<<v>v>>>>>>>v     (v<<<v<vv<<v<v>>^>>^^>vvv>>>v>vv<vv<<v<v<^<^^^^<vvvvv>v>>>^>>^>^^>vvv<v<v<<v is less efficient, and therefore not a valid output)

6. Input:
 +--+--+--+--+--+
I               |
 +  +  +  +  +  +
 |              |
 +  +  +  +  +  +
 |              |
 +  +  +  +  +  +
 |              |
 +  +  +  +  +  +
 |               U
 +--+--+--+--+--+

6. Output:
>>v>v>v>v> or >v>v>v>v>> or >>>>>vvvv> or etc. (all are equally efficient, so all 10-length outputs are valid)

7. Input:
 I  U
+  +  +--+--+--+
|  |        |  |
+  +--+--+  +  +
|     |     |  |
+--+  +  +--+  +
|        |  |  |
+  +--+  +  +  +
|     |        |
+--+  +--+--+  +
|     |        |
+--+--+--+--+--+

7. Output:
vv>v>^>^<<^

8. Input:
 +--+--+--+--+--+
 |     |        |
 +  +--+  +--+  +
I   |     |  |  |
 +  +  +--+  +  +
U   |     |  |  |
 +--+--+  +  +  +
 |     |     |  |
 +  +--+--+--+  +
 |               
 +--+--+--+--+--+

8. Output:
>v<

使用此工具生成的迷宫(在某些情况下会稍作修改)。


10
我发现第三个测试用例的解决方案更短!v<<<<<<^^^^^(始终在框外思考)
Leo

2
如果有足够的时间和内存可以证明他们的代码将产生最短的解决方案,那么它是否具有竞争力?即使在运行时间很长的情况下(宇宙终结)?
Yytsi'2

1
@JackBates这是一个笑话。他从字面上绕着箱子走到出口:D
Yytsi

1
我认为第一个测试用例是错误的,应该是>v>>>vv<v>>v>v>>vvv>>>
smls

1
@KevinCruijssen例如,一种解决方案,它测试“ v ^ <>”的每个组合的长度直至迷宫内的空盒子的数量。正确的解决方案就在那里,但是要花费大量的时间才能计算出来。
Yytsi'2

Answers:


7

视网膜338个 281 275 273 261字节

¶U
¶&
+`·(\w.+)$
|$1
((.)+I.+¶.+¶(?<-2>.)+)·
$1v
+`((.)*)\+(.).*(¶(?<-2>.)*.)((\w)|·)·?
$1$4$.4$3$6
·v
-v
G`1
·U
&
{`\B·\d+.(\w+)
$1K$&
(\w+)·\d+.\B
$&$1r
(?<=\D\2.(\w+).+?¶.*\D(\d+)[·&])\B
$1v
)`\D(\d+).\B(?=.+¶.*\D\1·(\w+))
$&$2A
^.+\d·(\w+)
&$1A
M!`&\w+
I|&

在线尝试!


笔记

  • 由于存在大量空格,因此在此答案和TIO链接中,所有空格(0x20)均被点间()替换·。如果恢复了空格,该程序将正常运行。
  • 分别AvKr用于上,下,左和右。这些可以与任何被替换字母除外I
  • 15×15测试用例的TIO大约需要40s。耐心一点。重新设计零件以找到路径最短的路径。原来那要花很多时间。
  • 可以完全打破66个或更多单元格宽度的迷宫,但可以处理任意高度的迷宫。固定任意宽度需要+1字节。

说明

该计划包括3个阶段:

  • 将迷宫转换为易于使用的紧凑格式的构建阶段(详细信息如下)。
  • 一个填充阶段实际使用解决洪水填充算法的迷宫。
  • 一个恢复阶段,以在出口恢复的最短路径。

格式

由于原始的迷宫格式非常笨拙,因此程序的第一部分将其转换为其他格式。

细胞

在原始格式中,每个单元格都表示为2×3区域:

+               <top wall>      <top wall>
<left wall>     <data/space>    <space>

由于右列不包含任何信息,因此该程序将单元格标识为任何2×2区域,并+在左上方。

这给我们留下了3种细胞:

  • I细胞:正确位于迷宫内的细胞。
  • R细胞:位于迷宫右侧的细胞。这些由用于容纳入口或出口的填充物创建。例如,U测试案例1中的出口位于R-Cell中。
  • B细胞:迷宫下方的细胞。像R单元一样,它们是通过填充创建的。

在新格式中,单元格表示为可变长度的字符串:

<left wall> <column number> <top wall/exit marker> <path>

左壁和顶壁是从原始格式复制的。列号基于单元格的水平位置,用于对齐(识别单元格彼此之间直接位于顶部/下方)。路径是在填充阶段用于保存到达该单元格的最短路径的字母字符串。路径和出口标记将进一步说明。

半电池

尽管大多数迷宫是细胞,但迷宫中的某些区域不是细胞:

  • R Half-cells:如果没有右填充,则+沿右墙的s不会形成单元,因为它们位于最后一列。
  • L Half-cells:如果有左侧填充,则由于+左侧没有填充,因此无法形成填充。例如,I测试案例1中的入口位于L Half-cell中。

从技术上讲,在迷宫上方有T个半格(有顶部填充时),在迷宫上方有B个半格(没有底部填充时沿着底壁),但它们没有以新格式表示。

作为在同一行中构造完整单元格的一部分,将删除半单元格的第一行,因此半单元格以新格式表示为

<wall/exit marker>? <path>

R半格是|。L个半格I像路径一样,只有出口标记和空路径,或者只有空墙。

出入口

如果入口位于迷宫的左侧,右侧或底部,则入口标记I自然会作为路径包含在(半)单元格中,在返回最终路径时可以将其删除。

如果入口在迷宫上方,则在施工阶段进行第一步(向下),因为在施工过程中会除去T个半电池。这样可以在整个单元格中保持可行的路径。顶壁随后关闭。

如果出口位于迷宫的左侧,右侧或底部,则U自然会包含在(半)单元格中。为避免被误认为是路径,请使用非字母数字的退出标记&代替U。出口标记嵌入到单元格或半单元格中(如上所述)。

如果出口在迷宫上方,则它将是唯一可以越过顶部单元格孔的孔(因为用于入口的孔(如果存在)将已经关闭)。任何到达该孔的路径都可以通过向上移动而离开迷宫。

最后,任何包含入口或出口的B单元必须关闭其左壁,以防止沿着B单元行走而“解决”迷宫。R单元或L半单元的入口和出口不需要进一步处理,因为洪水填充算法不允许垂直进出它们。

例如,第一个测试用例

·+--+--+--+--+--+--+--+--+--+--+·
I···············|·····|········|·
·+··+--+--+--+··+··+··+··+--+··+·
·|···········|·····|··|··|·····|·
·+--+--+--+··+--+--+··+··+··+--+·
·|···········|·····|·····|·····|·
·+··+--+--+··+··+--+--+··+--+··+·
·|·····|·····|·····|·····|·····|·
·+--+··+··+--+--+··+--+--+··+··+·
·|·····|········|········|··|··|·
·+··+--+--+--+··+--+--+··+··+··+·
·|·····|·····|·····|········|··|·
·+--+··+··+--+--+··+--+--+--+--+·
·|··|··|·················|·····|·
·+··+··+--+--+--+··+--+··+··+··+·
·|·····|········|··|··|··|··|··|·
·+--+--+··+··+--+··+··+··+--+··+·
·|········|·····|·····|··|·····|·
·+··+--+--+--+··+··+··+··+··+--+·
·|···········|·····|··|·········U
·+--+--+--+--+--+--+--+--+--+--+·

I·3-·6-·9-·12-·15-|18-·21-|24-·27-·30-|33·
·|3··6-·9-·12-|15··18·|21·|24·|27-·30·|33·
·|3-·6-·9-·12·|15-·18-|21··24·|27··30-|33·
·|3··6-|9-·12·|15··18-|21-·24·|27-·30·|33·
·|3-·6·|9··12-·15-|18··21-·24-|27·|30·|33·
·|3··6-|9-·12-|15··18-|21-·24··27·|30·|33·
·|3-|6·|9··12-·15-·18··21-·24-|27-·30-|33·
·|3··6·|9-·12-·15-|18·|21-|24·|27·|30·|33·
·|3-·6-·9·|12··15-|18··21·|24·|27-·30·|33·
·|3··6-·9-·12-|15··18·|21·|24··27··30-·33&

以新格式。您可以在此处转换其他迷宫。


施工阶段

构建阶段构成了程序的前13行。

¶U
¶&

将L半格中的出口转换为出口标记

+`·(\w.+)$
|$1

在B单元的入口和出口左侧添加墙

((.)+I.+¶.+¶(?<-2>.)+)·
$1v

如果入口在迷宫上方,则采取第一步

+`((.)*)\+(.).*(¶(?<-2>.)*.)((\w)|·)·?
$1$4$.4$3$6

执行实际的转换

·v
-v

封闭顶部入口孔

G`1

仅保留带有的行1。由于迷宫的宽度至少为5个单元格,并且列号以3的增量出现,因此具有新格式单元格的行的列号必须在10到19之间。

·U
&

将R Cell或B Cell中的退出转换为退出标记


填充阶段

填充阶段构成程序的后8行。它使用泛洪填充算法,以最短路径填充所有单元,以从入口到达那里。

{`

将整个填充阶段置于一个循环中以填充整个迷宫。

\B·\d+.(\w+)
$1K$&

每个能够向左移动的单元格都这样做。一个单元能够向左移动

  1. 它具有非空路径
  2. 它有一个空的左墙;和
  3. 左侧的单元格或L半单元格具有空路径
(\w+)·\d+.\B
$&$1r

然后,每个能够向右移动的单元格都会这样做。一个单元格能够向右移动

  1. 它具有非空路径
  2. 右边的单元有一个空的左壁;和
  3. 右边的单元格具有空路径
(?<=\D\2.(\w+).+?¶.*\D(\d+)[·&])\B
$1v

然后,每个能够向下移动的单元格都会这样做。一个单元能够向下移动

  1. 它具有非空路径
  2. 它的右边至少有一个像元或半像元(即它不是R像元)
  3. 其下方的单元格(即,下一行具有相同列号的单元格)的顶壁为空或具有退出标记;和
  4. 它下面的单元格具有空路径

请注意,L个半单元格没有列号,因此无法向下移动。

\D(\d+).\B(?=.+¶.*\D\1·(\w+))
$&$2A

然后,每个能够向上移动的单元格都会这样做。一个单元能够向上移动

  1. 它具有非空路径
  2. 它有一个空的顶壁
  3. 其上方的单元格在其右侧至少有一个单元格或半单元格;和
  4. 上方的单元格具有空路径

返回阶段

返回阶段组成程序的最后5行。此阶段搜索并返回填充到退出单元格中的路径。

出口处的路径模式取决于出口位置:

  1. 如果出口在L半格中,则该半格为 & <path>
  2. 如果出口在R单元格或B单元格中,则该单元格为 <left wall> <column number> & <path>
  3. 如果出口在T Half-cell中,则如上所述,通往出口的I Cell将<left wall> <column number> · <path>在顶部。
^.+\d·(\w+)
&$1A

在顶线上找到一个具有空顶壁和非空路径的单元格。通过添加最后一步和退出标记来处理最后一种情况。

M!`&\w+

匹配并返回退出标记后的非空路径。

I|&

删除出口标记和I路径的前缀。


为什么AvKr呢?它们是否具有含义/是使用您的母语使用的上,下,左和右的缩写,还是您选择这些特定字符的另一个原因?
凯文·克鲁伊森

@KevinCruijssen仅仅因为我必须使用字母数字字符,并且它AvKr是字母数字中最接近箭头的东西。
TwiNight

12

Perl 6的259个 295字节

{my \a=S:g/(.)$0+/{$0 x($/.comb+.5)*2/3}/;sub f (\c,\v,*@p) {with (c ne any v)&&a.lines».comb[+c[0];+c[1]] ->$_ {for (/\s/??10011221!!/I/??a~~/^\N*I|I\N*$/??2101!!1012!!'').comb X-1 {f [c Z+$^a,$^b],(|v,c),@p,chr 8592+$++}
take @p if /U/}}
[~] (gather f a~~/(\N+\n)*(.)*I/,[]).min(+*)[1,3...*]}

怎么运行的

  1. my \a = S:g/ (.) $0+ /{ $0 x ($/.chars + .5) * 2/3 }/;

这会挤压迷宫,使每个单元的内部为1x1而不是2x1的空格字符:

 +-+-+-+-+-+ +-+-+-+-+-++ 
我 | | 我 | |
 + +-+-+ + + +-+-+ + + 
 | | | | | | | |
 + +-+ + + + +-+ + + + 
 | | | | | -> | | | | |
 + + +-+ + + + +-+ + + 
 | | | | | |
 +-+ + +-+-+ ++ + +-+++ 
 | | U | | ü
 +-+-+-+-+-+ +-+-+-+-+-++

  1. sub f (\c,\v,*@p) {
        with (c ne any v) &&                   # If the coordinate wasn't visited yet
             lines».comb[+c[0];+c[1]] -> $_ {  # and a character exists there...
            for (                          # For each vector...
                 /\s/ ?? 10011221 !!       #  from a cell: (0,-1), (-1,0), (0,1), (1,0)
                 /I/  ?? a~~/^\N*I|I\N*$/
                          ?? 2101          #  from a top/bottom entrance: (1,0), (-1,0)
                          !! 1012          #  from a left/right entrance: (0,-1), (0,1)
                      !! ''                #  otherwise: none
                ).comb X-1 {
                f                       #   Recurse with arguments:
                    [c Z+ $^a, $^b],    #     c plus the vector
                    (|v, c),            #     v with c appended
                    @p, chr 8592 + $++  #     p with the correct Unicode arrow appended
            }
            take @p if /U/
        }
    }

这是递归的路径查找功能。它包含三个参数:当前坐标c=(y,x),已经访问过的坐标列表v以及p到目前为止所采用的路径(作为箭头字符列表)。

如果当前坐标处的字符是一个空格,它将递归到其四个邻居。
如果当前坐标处的字符是a I,则它将递归到非“沿边”的两个邻居,以迫使解决方案穿过迷宫而不是绕迷宫。
如果当前坐标处的字符是a U,则调用take累积的路径字符串。

  1. [~] (gather f a ~~ /(\N+\n)*(.)*I/, []).min(+*)[1,3...*]

最初使用字母的坐标调用递归函数I,使用正则表达式找到该字母。

gather关键字的收集上的所有值take被称为函数内部,即通过迷宫的所有有效的非循环路径。

选择了最短路径,将第二个箭头放下以说明以下事实:从一个单元格到下一个单元格需要进行两次相同的移动,然后将其余的箭头连接起来,形成从lambda返回的字符串。


首先,做好第一个完成挑战的工作非常出色!:)聪明地将两个空格更改为一个,以简化实际的移动/计数。向我+1。无论如何,在发表评论后,添加了两个新的测试用例。您还能通过您的解决方案验证这些工作吗?(此外,Perl 6是否具有可以添加链接的TIO或其他在线编译器?)
Kevin Cruijssen

@KevinCruijssen:在新的测试用例中,它绕过迷宫。:(我现在修复了代码。tio.run支持Perl 6,但是由于某些原因,它在那里不起作用...也许它的Perl 6版本太旧了?
smls

修复代码的出色工作。很抱歉,在您发布答案后指定必须经过迷宫的规则,但是对开头这么快地进行修复是起首字母。关于TIO版本,我不知道。不是真的我的专业知识..
凯文Cruijssen

由于您是四个月前第一个回答我的挑战的人,因此我向您提供了赏金。:)并且“接受”用于稍短的视网膜答案。
凯文·克鲁伊森'17

5

Python 2:302个字节

from re import*
r=lambda x:[''.join(_)for _ in zip(*x)][::-1]
z=',l)for l in s]'
def f(s,b=1,o=0,n=0):
 exec("s=[sub('(..).(?!$)',r'\\1'%s;"%z+"s=r([sub(' I ','+I+'%s);"%z*4)*b+"t=[sub('I  ','@@I'"+z
 if'I U'in`s`or n>3:return`o%4`+n/4*`s`
 return min(`o%4`+f(t,0,o,4*(t==s)),f(r(s),0,o+1,n+1),key=len)

将输入作为所有长度相同的字符串数组。0向右,1向下,2向左和3向上打印。

说明

我采取了与其他答案不同的方法。总体思路:通过查找直线前进和将板旋转90度之间的最短路径来进行递归搜索。

from re import*
r=lambda x:[''.join(_)for _ in zip(*x)][::-1] #Rotates the board counterclockwise
z=',l)for l in s]'    #Suffix for hacky exec golfing
def f(s,b=1,o=0,n=0): #b is 1 on initial call, 0 on every recursion
                      #o is orientation
                      #n is number of rotations
 exec("s=[sub('(..).(?!$)',r'\\1'%s;"%z  #Squeeze the maze
      +"s=r([sub(' I ','+I+'%s);"%z*4)   #Add walls around the I to keep it in the maze
      *b                                 #Only if b is 1
      +"t=[sub('I  ','@@I'"+z            #Attempt to move right

 if'I U'in`s`or n>3:return`o%4`+n/4*`s`  #If the I is next to the U, return the orientation
                                         #If there were 4 rotations, return a long string
 return min(                             #Return the path with the shortest length:
            `o%4`+f(t,0,o,4*(t==s)),       #Moving forward if possible
            f(r(s),0,o+1,n+1),             #Rotating the board
        key=len)

在线尝试!


3
欢迎来到PPCG!这是一个很好的第一个答案,给您留下深刻的印象,您决定在第一个挑战时就面临一个艰巨的挑战。同样聪明的是如何围绕墙壁放置I以防止路径从迷宫中移出。祝您逗留愉快,并向我+1。:)
凯文·克鲁伊森

2

JavaScript(ES6),356字节

a=>(a=a.map(s=>s.filter((_,i)=>!i|i%3)),g=([x,y])=>a[y]&&a[y][x],o=[],c=([x,y],m="",v=[])=>[[0,1],[1,0],[0,-1],[-1,0]].map(([j,k],i)=>(p=[x+j,y+k],!m&(!y|y>a[l="length"]-2)==i%2|v.includes(""+p)||(g(p)<"!"?c(p,m+"v>^<"[i],[...v,""+p]):g(p)=="U"?o.push(m.replace(/(.)\1/g,"$1")):0))),a.map((h,i)=>h.map((k,j)=>k=="I"&&c([j,i]))),o.sort((a,b)=>a[l]-b[l])[0])

将输入作为2D字符数组。无论起点/终点在何处,每行都必须在左边填充一个空格,并且没有尾随空格。

使用smls的想法,即挤压迷宫使每个单元格为1x1,并从输出中删除重复的箭头。

脱胎换骨和解释

a=>(
    a=a.map(s=>s.filter((_,i)=>!i|i%3)),    // squish the maze to 1x1 cells
    g=([x,y])=>a[y]&&a[y][x],               // helper func to get maze value
    o=[],                                   // resulting movesets
    c=([x,y], m="", v=[]) =>                // recursive func to search
                                            // takes current point, moves, and visited spots
        [[0,1],[1,0],[0,-1],[-1,0]].map(([j,k],i)=>(// for each direction
            p=[x+j,y+k],
            !m & (!y | y>a[l="length"]-2) == i%2 |  // if first move, prevent moving out of maze
                v.includes(""+p) || (               // also prevent if already visited
                    g(p)<"!" ?                      // is this a space?
                        c(p, m+"v>^<"[i], [...v,""+p]) // check this spot recursively
                    : g(p)=="U" ?                   // if this the end?
                        o.push(                     // add moves to moveset
                            m.replace(/(.)\1/g,"$1")) // with double arrows removed
                    : 0
                )
        )),

    a.map((h,i)=>h.map((k,j)=>      // find the starting "I" and
        k=="I" && c([j,i])          // begin recursion at that point
    )),

    o.sort((a,b)=>a[l]-b[l])[0]     // get shortest path
)

测试片段


1

视网膜,416字节

T` `+`^.*| ?¶.|.*$
I
#
{+` (\w)
d$1
+`(\w) 
$1a
+`(¶(.)*) (.*¶(?<-2>.)*(?(2)(?!))\w)
$1s$3
}+m`(^(.)*\w.*¶(?<-2>.)*(?(2)(?!))) 
$1w
^
w¶
w((.|¶)*(¶(.)*#.*¶(?<-4>.)*(?(4)(?!))(s)|#(d)|(a)#))
$4$5$6¶$1
{`^(.*d)(¶(.|¶)*)#(\w)
$1$4$2 #
^(.*a)(¶(.|¶)*)(\w)#
$1$4$2# 
^(.*s)(¶(.|¶)*¶(.)*)#(.*¶(?<-4>.)*(?(4)(?!)))(\w)
$1$6$2 $5#
}`^(.*w)(¶(.|¶)*¶(.)*)(\w)(.*¶(?<-4>.)*(?(4)(?!)))#
$1$5$2#$6 
s`U.*

(a|d)\1\1?
$1
ss
s
ww
w

在线尝试!如果在最初发布时看到了这个问题,这可能就是我会给出的答案,所以无论如何我都会在发布它,即使Retina中有更好的答案。说明:

T` `+`^.*| ?¶.|.*$

填写边框。这样可以避免在迷宫的外部走动(例如,对于测试用例7)。

I
#

在入口处放置一个非字母标记。

{+` (\w)
d$1
+`(\w) 
$1a
+`(¶(.)*) (.*¶(?<-2>.)*(?(2)(?!))\w)
$1s$3
}+m`(^(.)*\w.*¶(?<-2>.)*(?(2)(?!))) 
$1w

从出口到入口都充满水。在每个步骤中,都使用字母表示最佳的前进方向(很糟糕-这可能是游戏玩家所熟悉的;我也考虑过hjkl,但我发现它太令人困惑了)。另外,喜欢重复相同的方向;这样可以避免在两个垂直相邻的单元格之间左右移动。

^
w¶

假设第一步已结束。

w((.|¶)*(¶(.)*#.*¶(?<-4>.)*(?(4)(?!))(s)|#(d)|(a)#))
$4$5$6¶$1

但是,如果在入口上方,左侧或右侧上方有一个字母,请将其更改为第一步。

{`^(.*d)(¶(.|¶)*)#(\w)
$1$4$2 #
^(.*a)(¶(.|¶)*)(\w)#
$1$4$2# 
^(.*s)(¶(.|¶)*¶(.)*)#(.*¶(?<-4>.)*(?(4)(?!)))(\w)
$1$6$2 $5#
}`^(.*w)(¶(.|¶)*¶(.)*)(\w)(.*¶(?<-4>.)*(?(4)(?!)))#
$1$5$2#$6 

沿最后移动的方向移动标记,从标记所移动的正方形读取下一移动的方向,并将其添加到方向列表中。重复此过程,直到U达到为止。

s`U.*

删除指示后的所有内容,因为不再需要了。

(a|d)\1\1?
$1
ss
s
ww
w

原始网格为3×2布局。在垂直移动时,如果我们水平曲折,则洪水填充将优化移动,并且仅水平移动3n-1个字符,因此,除以三时,我们需要四舍五入。纵向上,我们只除以2。

我还研究了真正的正方形网格解决方案,即字符矩阵本身是正方形,而不是带有可选边框的3×2布局。尽管可能不符合该问题,但转置的能力将字节数减少到350:在线尝试!


好答案,+ 1!我确实在您的TIO链接中看到,您已经-在入口和出口字符周围添加了两个。由于挑战主要是通过迷宫,所以我想这很好,但我很好奇:如果您没有将墙放置在Iand 上方或以下,会出现U什么问题?另外,您是否可以使用IU而不是侧面来验证测试用例7的工作原理?TIO超过了60秒的限制,所以我无法自己测试。尽管阅读了您对默认情况下首先尝试下降的解释,但我认为它应该可以正常工作。
凯文·克鲁伊森

@KevinCruijssen“第二”答案适用于测试用例7,但需要额外的字符:在线尝试!继续...
尼尔

@KevinCruijssen“主要”答案存在一个错误,即它根本无法应对最上面一行的出口。它也具有与“次级”答案类似的错误,即如果可能的话,它更喜欢在迷宫的外部走动。(另外,我没有达到60秒的限制。)
Neil

实际上,我可以通过填写边框来解决这两个答案。有时间我会再做。
尼尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.