Tôi muốn xem bạn chết khát


12

Bạn là một du khách băng qua sa mạc giữa hai thị trấn. Bạn không thể mang đủ nước để đi qua mà không dừng lại. Đây là một biến thể của một câu đố cổ điển.

Những quy định

Một sa mạc trông như thế này: một lưới WxH chủ yếu là không gian trống. Không gian được đánh dấu Slà nơi bạn bắt đầu, Elà nơi bạn muốn kết thúc và một hình vuông được đánh dấu bằng số N chứa N đơn vị nước. Hình vuông được đánh dấu bằng một .nước giữ không.

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

Bạn bắt đầu tại S với 5 đơn vị nước.

Bạn có thể mang theo tối đa 5 đơn vị nước.

Mỗi lượt bạn

  1. di chuyển một hình vuông lên, xuống, trái hoặc phải,
  2. tiêu thụ 1 đơn vị nước mà bạn đang mang,
  3. nhặt hoặc thả một số đơn vị nước.

Một ngã rẽ được ký hiệu như vậy : (direction)(+|-)(units of water), +cho biết bạn đang lấy nước, -rằng bạn đang thả nó.

Ví dụ lần lượt:

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.

Nếu bạn thực hiện các động tác này bắt đầu từ S trong ví dụ trên, sa mạc sẽ trông như thế này sau đó.

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

Bạn có thể lấy không nhiều nước hơn trên quảng trường của bạn. Khi bạn lấy nước, hãy trừ số đơn vị đó vào số đếm của gạch.

Bạn chỉ có thể lấy nước để chứa tối đa 5 đơn vị.

Không có ô nào có thể chứa hơn 9 đơn vị, ngoại trừ S chứa các đơn vị vô cực.

Bạn chỉ có thể thả nhiều nước như bạn đang giữ.

Nước trên mặt đất vẫn không thay đổi cho đến khi bạn lấy lại.

Nếu bạn quay trở lại S, bạn có thể lấy bất kỳ lượng nước nào mà không làm cạn kiệt nó.

Nếu bạn đạt E thì bạn thắng . Bạn vẫn thắng nếu bạn tiêu thụ đơn vị nước cuối cùng của mình trên E.

Nếu sau lượt của bạn, bạn không có nước và bạn không ở trên E, bạn sẽ chết .

Đầu vào và đầu ra

Chương trình của bạn sẽ nhận được một bản đồ bắt đầu có kích thước tùy ý trên STDINdưới dạng nghệ thuật ASCII theo định dạng ở trên. Bạn có thể giả sử nó là hình chữ nhật tức là tất cả các dòng có cùng độ dài, có chính xác một Svà một Ehình vuông, tất cả các dòng được kết thúc \nvà toàn bộ STDIN sẽ tuân theo biểu thức này:/^[SE1-9\.\n]+$/

Chương trình của bạn sẽ ghi đầu ra sau vào STDOUT:

  1. danh sách các động thái,
  2. trạng thái cuối cùng của bản đồ.

Bạn có thể xuất danh sách di chuyển ở bất kỳ định dạng thuận tiện.

Trạng thái cuối cùng của bản đồ sẽ được in cùng định dạng với đầu vào ngoại trừ việc nó sẽ hiển thị thêm tuyến đường bạn đi qua sa mạc bằng cách đánh dấu tất cả các ô được truy cập bằng #, nếu ô đó không chứa nước và không phải là S hoặc E (nghĩa là nó là .)

VÍ DỤ đầu vào:

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

VÍ DỤ sản lượng chiến thắng:

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

Vô dụng

Khi bạn đăng mã của mình, hãy đăng một đầu vào bản đồ mẫu mà mã của bạn tìm thấy giải pháp thỏa mãn các điều kiện không tầm thường sau:

  • S và E cách nhau ít nhất 10 lần.
  • Bất kỳ hình vuông nào ban đầu chứa N đơn vị nước phải được bao quanh bởi đường viền N chiều rộng trong đó tất cả các hình vuông là .(không có nước, không phải S hoặc E)

THÍ DỤ

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

Nếu bạn tăng lượng nước trên bất kỳ gạch nào, những thứ trên trở nên tầm thường.

Yêu cầu

Có lẽ chương trình của bạn sẽ gặp phải một số lần thử thất bại trước khi tìm thấy giải pháp, nếu có.

  1. Chương trình của bạn cuối cùng phải giải quyết bất kỳ đầu vào có thể giải quyết.
  2. Tôi muốn xem bạn chết - chương trình của bạn sẽ đưa ra các bước di chuyển và bản đồ cuối cùng của tuyến đường đến cái chết cho mỗi nỗ lực thất bại để tìm ra giải pháp.
  3. Nếu bạn gặp phải một giải pháp chiến thắng, hãy in toàn bộ đầu ra cho điều đó và chấm dứt.
  4. Chạy cho đến khi tìm thấy giải pháp, nhưng không thử cùng một giải pháp hai lần - tất cả các trường hợp tử vong phải theo các tuyến khác nhau.
  5. Sử dụng này một đầu vào thử nghiệm:

(nó yêu cầu ít nhất một lần di chuyển để thả bộ đệm nước ở một số điểm giữa).

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

Mã ngắn nhất được đăng với đầu vào trình diễn không tầm thường mà nó giải quyết được chiến thắng.


Điều này cần được làm rõ để xác định xem chương trình có cần giải quyết bất kỳ bản đồ có thể giải được hay không, hoặc liệu nó chỉ phải hoạt động cho một bản đồ. Tôi chắc chắn sẽ khuyến khích người trước; trong trường hợp có một bản đồ, sẽ dễ dàng mã hóa giải pháp hơn là tính toán nó.

Chỉnh sửa cho rõ ràng. Có bạn thắng nếu bạn có nhiều hơn 0 nước và có chương trình của bạn phải giải quyết tất cả các đầu vào có thể giải được.
spraff

Điều gì ngăn bạn sử dụng thuật toán như A * và thả một đường dẫn 5 đơn vị trên mỗi ô bạn liên tiếp đi và quay lại điểm bắt đầu nếu bạn bước lên một ô không có 5 nước?
Màu xanh

Không có gì. Đi về phía trước.
spraff

Chiến lược 'mang tất cả nước từ chiến lược S' sẽ hoạt động, mặc dù nó sẽ rất tẻ nhạt. Hãy xem xét S.,.,.,.,. E .... E trong đó, và e là các dấu chấm thực sự. Dấu phẩy là nơi bạn giữ các ngăn của mình trên đường đi và 'e' là nơi bạn cần có 5 nước để chạy trong E. 4 bước để di chuyển 1 nước đến dấu phẩy đầu tiên (E + 0 E-1 W + 0 W + 4). 16 bước để di chuyển 1 nước đến dấu phẩy thứ hai. 52 đến thứ ba, 160 đến thứ tư, 484 để thả 1 nước xuống e và quay trở lại S. 1926 bước và bạn đang mang theo 5 nước, 5 bước nữa để chạy đến E, 1931 bước. Mỗi hai bước của con đường có hiệu quả gấp ba lần chiều dài giải pháp của bạn.
Sparr

Câu trả lời:


12

Perl, 299 + 1 = 300 254 + 1 = 255 byte

Điều này gần như chắc chắn sẽ bị đánh bại bởi một trong những ngôn ngữ chơi gôn khi mọi người nhìn thấy thuật toán của tôi :-)

Chạy với -n(1 byte hình phạt).

Phiên bản trước không hoàn toàn tuân thủ thông số kỹ thuật vì nó để lại thêm nước trên bản đồ và không hiển thị nó trong phiên bản cuối cùng của bản đồ; Trong khi thay đổi thuật toán để giải quyết tình huống đó, tôi đã xoay sở để chơi nó nhỏ hơn một chút trong quy trình.

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

Ví dụ (Tôi đã thêm ngắt dòng vào đầu ra để tránh phải cuộn và hiển thị cấu trúc):

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 LLLLLUUUYDDDDRRRR
 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 LLLLLUUYDDRRRR
 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

Trong các ký hiệu được sử dụng bởi các chương trình, phong trào được thể hiện qua L, R, U, và Dcho trái, lên, phải, xuống tương ứng. Theo mặc định, bạn lấy 1 đơn vị nước sau mỗi lần di chuyển, nhưng điều này có thể được sửa đổi bằng cách nối thêm một ký tự:

  • X: thả 2 đơn vị nước, thay vì chọn 1 đơn vị
  • Y: thả 1 đơn vị nước, thay vì chọn 1 đơn vị
  • (không gian ví dụ): hoàn toàn nạp tiền vào nước (chỉ có đầu ra sau khi chuyển sang S; chương trình cũng là đầu ra với một không gian hàng đầu, có ý nghĩa vì bạn bắt đầu đầy đủ về nước)

Như bạn có thể thấy, có thể vượt qua bản đồ (khá cằn cỗi) này mà không cần sử dụng thêm nhóm nào. Trên thực tế, có thể có bất kỳ khoảng cách nào theo các quy tắc này, trên bất kỳ bản đồ nào , mà không cần sự trợ giúp của bất kỳ nước đặt trước nào. Như vậy, thuật toán này chỉ bỏ qua bất kỳ nước đặt sẵn nào, có nghĩa là tôi không phải lãng phí byte khi cố gắng xử lý nó. Điều này cũng có nghĩa là bạn sẽ không thấy bot chết, xin lỗi. Nó không bao giờ di chuyển vượt quá phạm vi mà nó biết nó được đảm bảo để tồn tại.

Lý do chúng tôi cần cả hai XY(và một chút mã bổ sung để đảm bảo chúng tôi có Xtrong hầu hết chiến lược nhưng đôi khi Yở cuối) là thông số kỹ thuật yêu cầu phiên bản cuối cùng của bản đồ được xuất ra. Cách dễ nhất để thực hiện điều này là để bản đồ hoàn toàn không bị ảnh hưởng (ngoài đường đi của chúng tôi qua các ô vuông trống ban đầu), đặc biệt là một hình vuông bắt đầu bằng 9nước sẽ kết thúc bằng 10(phá vỡ nghệ thuật ASCII) nếu nó xảy ra trên đường và chúng tôi chỉ sử dụngXvà do đó chúng ta cần tìm một số giải pháp tránh làm rơi thêm nước trên bản đồ. Thuật toán ở đây sẽ "tự nhiên" thả thêm 1 đơn vị nước trên mỗi ô vuông trên tuyến đường; do đó, thời gian áp chót chúng tôi ghé thăm mỗi ô vuông, chúng tôi giảm lượng nước giảm đi 1 thông qua việc sử dụng Y thay vì X, vì vậy trong chuyến thăm cuối cùng của chúng tôi, chúng tôi rút cạn nước trở lại lượng nước ban đầu, thay vì để nó hơi ướt hơn so với khi chúng tôi bắt đầu.

Tôi khuyên bạn không nên chạy cái này trên bản đồ lớn, vì nó có hiệu suất O (2 ^ n) (mặc dù bot không bao giờ chết vì khát, thật có thể nghĩ rằng nó sẽ chết vì đói khi sử dụng chiến lược như thế này.)

Phiên bản dễ đọc:

# 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).

Lũ có thể lấp đầy thế giới theo hình xoắn ốc ít mã hơn khối điều kiện của bạn để tìm hướng thoát?
Sparr

1
Tôi không nghĩ nó sẽ như vậy (mặc dù có thể có một số cách mà tôi không nhìn thấy; chắc chắn đó là một ý tưởng đáng để xem xét). Bạn vẫn phải đối phó với bốn hướng, và bây giờ bạn cũng phải đối phó với cạnh của bản đồ, một điều không phải là vấn đề trong phiên bản thuật toán này.

Điểm tốt, cạnh lại. Tôi nghĩ rằng nó có thể được thực hiện trên một bản đồ vô tận.
Sparr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.