我想看着你渴死


12

您是在两个城镇之间穿越沙漠的旅行者。您不能携带足够的水不停地穿越。这是经典拼图的变体。

规则

沙漠看起来像这样:一个WxH网格,其中大部分是空白空间。标S有空格的地方是您开始的地方,E是您要结束的地方,一个标有数字N的正方形容纳N单位水。标有.保持零水的方块。

.....................................
........S............................
.....................................
.........7...........................
.....................................
.......................3.............
.....5...............................
................................2....
.....................................
.....................................
.....................................
...............................E.....
.....................................
....................7................
.....................................
.....................................

您以5单位水开始于S。

您最多可以携带5单位水。

每转你

  1. 向上,向下,向左或向右移动一个方块,
  2. 消耗1单位水,
  3. 拿起或放下一定数量的水。

这样会标出一个转弯:(direction)(+|-)(units of water)+表示您正在拿水,-正在放水。

示例变为:

D+0        Move Down
R+0        Move Right
D+2        Move Down, pick up two units of water.
U-1        Move Up, drop one unit of water.

如果在上面的示例中从S开始执行这些移动,则沙漠看起来像这样。

.....................................
........S............................
.........1...........................
.........5...........................
.....................................
.......................3.............
.....5...............................
................................2....
.....................................
.....................................
.....................................
...............................E.....
.....................................
....................7................
.....................................
.....................................

您只能拿起广场上已经没有的水。当您拿起水时,请从瓷砖的计数中减去该单位数量。

您只能拿起水最多容纳5个单位。

除了S可以容纳无限个单位外,任何瓷砖都不能容纳9个以上的单位。

您只能滴下当前所握的水量。

地面上的水保持不变,直到您再次将其捡起。

如果返回到S,则可以吸收任何数量的水而不消耗水。

如果达到E,那么您就赢了。如果您在E上消耗了最后一单位水,您仍然会赢。

转弯后,如果您的水量为零,而您不在E上,则您将死亡

输入输出

您的程序将以STDIN上述格式以ASCII艺术形式接收任意大小的起始图。您可以假设它是矩形,即所有线的长度相同,正好有一个S和一个E正方形,所有线都以终止\n,并且整个STDIN都将符合此正则表达式:/^[SE1-9\.\n]+$/

您的程序会将以下输出写入STDOUT:

  1. 动作清单
  2. 地图的最终状态。

您可以以任何方便的格式输出动作列表。

地图的最终状态将在相同的格式输入要打印的不同之处在于它会另外给你穿越沙漠所走的路线通过标记所有访问过的瓷砖#,如果瓷砖不含水,而不是S或E(即是.)。

输入示例

.....S.
.......
.......
E......
....8..

获胜示例

D+0
D+0
D+0
D+0
L+5
L+0
L+0
L+0
L+0
U+0
.....S.
.....#.
.....#.
E....#.
####3#.

不平凡

发布代码时,请发布示例地图输入,您的代码将找到满足以下非平凡条件的解决方案:

  • S和E至少相距10步。
  • 最初包含N单位水的任何正方形都必须被N宽度的边界包围,其中所有正方形都位于其中.(没有水,没有S或E)

........2.
..........
..........
S.1..2....
..........
..........
........1.
..3.......
.........E

如果您增加任何瓷砖上的水量,以上内容将变得微不足道。

要求

大概您的程序在找到解决方案(如果有)之前会遇到许多失败的尝试。

  1. 您的程序最终必须解决任何可解决的输入。
  2. 我想看着你死掉 -您的程序将为每次寻找解决方案的失败尝试输出通往死亡之路的路线和最终地图。
  3. 如果遇到成功的解决方案,请打印该解决方案的完整输出并终止。
  4. 运行直到找到一个解决方案,但不要两次尝试相同的解决方案 -所有死亡应通过不同的途径进行。
  5. 使用它作为测试输入:

(至少需要一招才能在某个中点放水缓存)。

 S........
 .........
 .........
 ........E

最短的代码与解决问题的非平凡的演示输入一起发布


需要澄清这一点,以指定程序是否需要能够解决任何可解决的地图,或者它是否只需要为一张地图工作。我绝对会鼓励前者;在一张地图的情况下,对解决方案进行硬编码比对其进行计算要容易。

为清楚起见进行了编辑。是的,如果水量大于零,那么您将获胜;是的,您的程序必须解决所有可解决的输入问题。
spraff

是什么让您停止使用A *之类的算法,并且在您连续走到没有5个水的瓷砖上的情况下,在您依次进入的每个瓷砖上放置5个单位的路径,然后又回到起点?
蓝色

没有。前进。
spraff

“从S运走所有水”策略应该起作用,尽管这将非常乏味。考虑S。,。,。,。e .... E其中,和e确实是点。逗号是沿途存放的地方,“ e”是要让E运转需要5杯水的位置。4个步骤将1颗水移动到第一个逗号(E + 0 E-1 W + 0 W + 4)。16个步骤将1个水移动到第二个逗号。52至第三,160至第四,484将1滴水降落到e并返回至S. 1926步骤,而您在e处载有5股水,再加5到E,则升至1931步骤。每走两步,有效地将解决方案长度增加了三倍。
Sparr

Answers:


12

Perl,299 + 1 = 300254 + 1 = 255字节

当人们看到我的算法时,这几乎肯定会被一种高尔夫球语言所击败:-)

运行-n(1个字节的罚款)。

先前的版本不太符合规范,因为它在地图上留下了多余的水,并且没有在地图的最终版本中显示;在更改算法以应对这种情况的同时,我设法在此过程中将其缩小了一些。

push@a,[split//];($s,$t)=(length$`,$.)if/S/;($e,$f)=(length$`,$.)if/E/}{$_.=$s<$e?($s++,R):$s>$e?($s--,L):$t<$f?($t++,D):($t--,U);$\=reverse$";$".=y/LRUD/RLDU/r.Y.reverse.($"=~y/Y/X/r);$a[$t-1][$s]=~y/./#/;$\.=$s-$e||$t-$f?redo:$_;print map{join'',@$_}@a

示例(为了避免滚动和显示结构,我在输出中添加了换行符):

E .....
#.....
#.....
#.....
##### S
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUXDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUUYDDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUYDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUYDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLYRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLYRRRR
 LXR LLXRR LXR LLLYRRR LXR LLYRR LYR LLLLLUUUU

在由该程序所使用的符号,运动经由表示LRU,和D对于左,上,右,下分别。默认情况下,每次移动后您会拾取1单位水,但是可以通过添加一个字符来进行修改:

  • X:滴2单位水,而不是拿起1单位
  • Y:滴入1单位水,而不是拿起1
  • (即空间):完全注满水(仅在移至时才输出S;该程序也以前导空格输出,这是有道理的,因为您开始注满水)

如您所见,可以完全不使用任何多余的池来越过这个(相当贫瘠的)地图。实际上,根据这些规则,在任何地图上可以取得任何距离,而无需任何预先放置的水。因此,此算法仅忽略任何预先放置的水,这意味着我不必浪费字节尝试处理它。抱歉,这也意味着您不会看到机器人死亡。它永远不会超出它知道可以生存的范围。

我们既需要XY(又需要一些额外的代码来确保我们X在大部分策略中都能使用,但偶尔需要Y在末尾)的原因是,规范要求输出地图的最终版本。实现此目的最简单的方法是完全不改变地图(除了我们通过最初为空的正方形的路径之外),特别是因为如果碰巧在路径上,以9水开头的正方形最终会10(破坏ASCII艺术)而且我们只用了X,因此我们需要找到一些避免在地图上掉落过多水的解决方案。这里的算法将“自然地”在路线上的每个广场上滴加1单位额外的水;因此,我们访问每个广场的倒数第二次时间,我们通过使用Y而不是X减少了1的水量,因此在最后一次访问时,我们将广场排水回原来的水量,而不是使它比我们开始时略湿。

我建议不要在较大的地图上运行它,因为它具有O(2 ^ n)的性能(尽管该机器人从不死于口渴,但使用这样的策略认为它会因饥饿而死是有道理的。)

可读版本:

# implicit with -n: read a line of input into $_
push @a, [split //]; #/ split $_ into characters, store at the end of @a
($s,$t) = (length$`,$.) if /S/; # if we see S, store its coordinates
($e,$f) = (length$`,$.) if /E/  # if we see E, store its coordinates
}{ # Due to -n, loop back to start if there are more lines.

# From here onwards, $" stores the partial solution this iteration;
#                    $\ stores the partial solution last iteration;
#                    $_ stores the path from ($s,$t) to S.
# At the start of the program, $" is a space, $\ and $_ are empty.

$_ .=  # Work out the next step on the path:
  $s < $e ? ($s++,R) # if too far left, move right, record that in $_;
: $s > $e ? ($s--,L) # if too far right, move left, record that in $_;
: $t < $f ? ($t++,D) # if too far up,    move down, record that in $_;
: ($t--,U);          # in other cases we must be too far down.
$\ = reverse $";     # Store last iteration; $" is constructed backwards.
$" .=                # Extend $" by appending
  y/LRUD/RLDU/r .    # the path from ($s, $t) back to S;
  Y .                # a literal 'Y';
  reverse .          # $/ backwards (i.e. the path from S to ($s, $t);
  ($"=~y/Y/X/r);     # a copy of $" with all 'Y' changed to 'X'.
$a[$t-1][$s] =~      # At the current path coordinate,
  y/./#/;            # replace any '.' with '#'.
$\ .=                # Start appending to $\;
  $s-$e||$t-$f?redo  # if we're not at E, abort that and jump back to {{,
: $_;                # otherwise append $_ (the path from S to E).
print map            # For each element of some array
  {join'',@$_}       # output its concatenated elements
  @a                 # specifying that array as @a.
# Implicitly: print $\ (which specifies the sort of newline print uses).

泛滥成灾的代码会比您的条件出口代码少吗?
Sparr

1
我不认为会这样(尽管有可能我只是没有看到某种方式;这当然是一个值得考虑的想法)。您仍然必须处理四个方向,现在还必须处理地图的边缘,这在此版本的算法中没有问题。

好点,重新优势。我认为可以在无限的地图上完成。
Sparr
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.