갈증으로 죽는 걸보고 싶어


12

당신은 두 도시 사이의 사막을 건너는 여행자입니다. 멈추지 않고 물을 충분히 운반 할 수 없습니다. 이것은 고전적인 퍼즐의 변형입니다.

규칙

사막은 다음과 같습니다 : 대부분 빈 공간의 WxH 그리드. 표시된 공간 S은 시작 E위치이고 종료하려는 위치이며 숫자 N으로 표시된 사각형에는 N 단위의 물이 들어갑니다. .홀드 제로 워터가 표시된 사각형 .

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

S는 5 단위의 물로 시작합니다.

최대 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사각형이 있고 모든 줄이로 끝나고 \nSTDIN 전체가이 정규식을 따릅니다./^[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

사소한 데모 입력으로 게시 된 가장 짧은 코드 승리합니다.


프로그램이 해결 가능한지도를 풀 수 있어야하는지 또는 하나의지도에서만 작동해야하는지 여부를 지정하려면이를 명확히해야합니다. 나는 전자를 확실히 장려 할 것이다. 하나의 맵의 경우 솔루션을 계산하는 것보다 하드 코딩하는 것이 더 쉽습니다.

명확성을 위해 편집되었습니다. 예, 물이 0보다 많으면 승리하며, 프로그램은 모든 입력 가능한 입력을 해결해야합니다.
spraff

5 * 물이없는 타일을 밟으면 A *와 같은 알고리즘 사용을 중단하고 각 타일에 5 단위의 경로를 연속적으로 삭제하고 시작으로 돌아가는 이유는 무엇입니까?
Blue

아무것도. 어서
spraff

'S에서 모든 물을 나르십시오'전략은 효과가 있지만 지루할 것입니다. S.,.,.,.,. e .... E 여기서, e는 실제로 점입니다. 쉼표는 보관소를 따라가는 곳이며 'e'는 E를 실행하기 위해 5 개의 물이 있어야하는 곳입니다. 1 개의 물을 첫 번째 쉼표로 옮기기위한 4 단계 (E + 0 E-1 W + 0 W + 4). 하나의 물을 두 번째 쉼표로 옮기는 16 단계. 52에서 셋째, 160에서 넷째, 484는 1 개의 물을 e로 떨어 뜨리고 S. 1926 단계로 되돌아 가면, 5 개의 물을 운반하고, 5는 더 많은 물을 1931 단계로 옮깁니다. 경로의 두 단계마다 솔루션 길이가 효과적으로 세 배가됩니다.
Sparr

답변:


12

펄, 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

예 (스크롤을하고 구조를 표시 할 필요가 없도록 출력에 줄 바꿈을 추가했습니다).

이자형.....
# .....
# .....
# .....
#####에스
 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

프로그램에 의해 사용되는 표기법에서 운동을 통해 표현되고 L, R, UD좌측에 대해 최대 바로 아래에 각각. 기본적으로, 당신은 매 이동마다 1 단위의 물을 집어 들지만, 캐릭터를 추가하여 수정할 수 있습니다 :

  • X: 1을 집지 않고 2 단위의 물을 떨어 뜨립니다.
  • Y: 1을 집어 올리지 않고 1 단위의 물을 떨어 뜨립니다.
  • (즉, 공간) : 물을 완전히 보충합니다 (이동 후 출력 만 가능합니다 S; 프로그램은 또한 물이 가득 차기 때문에 시작 공간으로 출력됩니다).

보시다시피, 여분의 수영장을 사용하지 않고 불모의지도를 건너 갈 수 있습니다. 사실,에,이 규칙에 따라 어떤 거리를 얻을 수있어 어떤 어떤 사전에 놓인 물의 도움없이,지도. 따라서이 알고리즘은 미리 배치 된 물을 무시하므로 처리하기 위해 바이트를 낭비 할 필요가 없습니다. 이것은 또한 당신이 봇 다이를 볼 수 없다는 것을 의미합니다. 죄송합니다. 생존을 보장하는 범위를 벗어나지 않습니다.

우리가 모두 필요한 이유 X와을 Y(그리고 우리가 보장하는 추가 코드의 비트 X전략의 가장하지만 가끔 전반에 걸쳐 Y끝에)는 사양 출력 할지도의 최종 버전을 필요로한다는 것이다. 이것을 구현하는 가장 쉬운 방법은 맵을 완전히 건드리지 않는 것입니다 (처음에는 비어있는 사각형을 통한 경로 제외). 특히 9물로 시작된 사각형 10은 경로에있을 경우 (ASCII 예술을 깨는) 것으로 끝납니다. 우리는 사용했다X따라서지도에 여분의 물을 떨어 뜨리지 않는 솔루션을 찾아야합니다. 여기서 알고리즘은 경로의 각 사각형에 물 1 개를 추가로 자연적으로 떨어 뜨립니다. 따라서 우리가 각 광장을 방문하는 두 번째 시간은 X가 아닌 Y를 사용하여 떨어지는 물의 양을 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.