Bữa tiệc tìm kiếm phim kinh dị


21

Cốt truyện : Jimmy bị mất tích; chúng ta phải tìm anh ấy Chúng ta nên chia tay.

Cốt truyện xoắn : Jimmy đã chết.

Nhưng, diễn viên của chúng tôi không biết điều đó, vì vậy dù sao họ cũng cần tìm kiếm toàn bộ khu vực. Có một cột N cột x M hàng (1 <= M, N <= 256) lưới ô, được đánh dấu là "S" cho điểm bắt đầu, "." cho không gian mở hoặc "#" cho một chướng ngại vật. Đây là bản đồ .

Có 0 <= p <= 26 bạn diễn , 0 <= q <= 26 tính năng bổ sung , và 1 ngôi sao . Mọi người ban đầu ở trong ô được đánh dấu S.

Những quy định

Mỗi người có bán kính quan sát được hiển thị bên dưới:

 ...
.....
..@..
.....
 ...

Ngôi sao được ký hiệu là "@", các trang phụ bằng chữ in hoa, bắt đầu bằng "A" và phần bổ sung bằng chữ thường, bắt đầu bằng "a". Ban đầu, bán kính quan sát xung quanh điểm bắt đầu đã được đánh dấu là đã tìm kiếm. Nếu điều này tạo thành toàn bộ không gian mở của bản đồ, trò chơi sẽ kết thúc. Mỗi lượt, theo thứ tự sau :

  1. Mỗi người đồng thời làm cho một vị vua di chuyển (đứng yên hoặc di chuyển đến một trong 8 ô lân cận).
  2. Tất cả các tế bào trong bán kính tầm nhìn xung quanh mỗi người được tính là tìm kiếm.
  3. Nếu một người phụ nữ không thể nhìn thấy ai khác, cô ấy chết. Nếu một phần phụ không thể nhìn thấy một trang phục, ngôi sao hoặc ít nhất 2 phần bổ sung khác, anh ta sẽ chết. Những điều này xảy ra đồng thời - nghĩa là, không thể có phản ứng dây chuyền về cái chết trong một lượt; các điều kiện trên được kiểm tra và tất cả những người sắp chết sẽ chết cùng một lúc.
  4. Nếu tất cả các không gian mở trên bản đồ đã được tìm kiếm, tìm kiếm kết thúc.

Ghi chú

Nhiều người có thể ở trên cùng một hình vuông tại bất kỳ điểm nào và những người này có thể nhìn thấy nhau.

Chướng ngại vật không bao giờ cản trở tầm nhìn, chỉ chuyển động; mọi người có thể nhìn thấy nhau trên khắp, er ... dung nham?

Các không gian mở trên bản đồ được đảm bảo được kết nối bằng các bước di chuyển của vua.

Chữ "S" ban đầu cũng được coi là không gian mở, chứ không phải là một trở ngại.

Bất kỳ di chuyển vua nào hạ cánh trên một không gian mở là hợp lệ. Ví dụ, động thái sau đây là hợp pháp:

....      ....
.@#. ---> ..#.
.#..      .#@.
....      ....

Đầu vào

Đầu vào sẽ ở định dạng

N M p q
[N cols x M rows grid with characters ".", "#", and "S"]

Đầu vào mẫu:

6 5 0 0
......
......
..S...
......
......

9 9 1 1
S.......#
.......##
......##.
..#####..
...##....
...##....
...#.....
....#..#.
.........

p và q lần lượt là số lượng trang phục và phụ.

Đầu ra

Đầu ra phải là, cho mỗi lượt, các bước di chuyển được thực hiện, với các hướng được chỉ định bởi

789
456
123

Thứ tự của các động thái không quan trọng, vì tất cả chúng đều được ban hành đồng thời. Không liệt kê một động thái cho một người là tốt, và tương đương với việc di chuyển anh ta theo hướng 5. Các bước di chuyển nên được liệt kê theo định dạng sau:

@9 A2 a2 B7.

"." biểu thị sự kết thúc của bước đi của bạn cho một lượt.

Sau khi bản đồ đã được tìm kiếm, dòng đầu ra cuối cùng phải là ba số nguyên, cách nhau bởi khoảng trắng: số lượt mà bạn phải hoàn thành để tìm kiếm bảng, số lượng trang phục sinh hoạt và số lượng bổ sung sinh hoạt. Đối với đầu vào ví dụ đầu tiên

6 5 0 0
......
......
..S...
......
......

Sau đây là đầu ra hợp lệ:

@4.
@6.
@6.
@6.
4 0 0

Lưu ý cuối cùng: ngôi sao không thể chết và không gian mở trên bản đồ được đảm bảo được kết nối, vì vậy việc tìm kiếm cuối cùng sẽ luôn thành công.

Chấm điểm

Điểm của bạn là tổng số lượt thực hiện trong một loạt các bài kiểm tra điểm chuẩn; bạn được chào đón để gửi trường hợp thử nghiệm của riêng bạn cùng với câu trả lời của bạn. Tổng số lượng trang phục sinh hoạt trên tập hợp điểm chuẩn sẽ được sử dụng làm bộ ngắt kết nối và trong trường hợp vẫn còn một số ràng buộc, tổng số lượng bổ sung sinh hoạt sẽ được sử dụng.

Bộ kiểm tra và bộ điều khiển

Hiện tại, 5 bản đồ đang trực tuyến tại https://github.com/Tudwell/HorrorMovieSearchParty/ . Bất cứ ai gửi câu trả lời cũng có thể gửi một trường hợp thử nghiệm mà tôi có quyền từ chối vì bất kỳ lý do gì (nếu tôi từ chối bản đồ của bạn vì một số lý do, bạn có thể gửi một trường hợp khác). Chúng sẽ được thêm vào bộ kiểm tra theo quyết định của tôi.

Một bộ điều khiển Python (được thử nghiệm trong 2.7.5) được cung cấp trên github dưới dạng bộ điều khiển . Một bộ điều khiển thứ hai ở đó, control_disp.py , giống hệt nhau ngoại trừ việc nó hiển thị đầu ra đồ họa trong quá trình tìm kiếm (yêu cầu thư viện Pygame).

Đầu ra bộ điều khiển đồ họa

Cách sử dụng :

python controller.py <map file> <your execution line>

I E:

python controller.py map1.txt python solver.py map1.txt

Bộ điều khiển có đầu ra (cho stdin chương trình của bạn ) của mẫu

Turn 1
@:2,3 A:2,3 B:2,3.
##...##
#ooo..#
ooooo..
ooooo..
ooooo..
#ooo...
##.....
###....
----------------------------------------

Đây là số lần lượt (lượt 1 là trước khi bạn di chuyển), danh sách kết thúc '.'- của tất cả các diễn viên và tọa độ x, y của họ (ký tự phía trên bên trái là (0,0)), đại diện cho toàn bộ bảng, và một dòng với 40 '-'s. Sau đó, nó chờ đầu vào (từ thiết bị xuất chuẩn của chương trình ) của biểu mẫu

@9 A2 B7.

Đây là định dạng đầu ra được chỉ định ở trên. Bộ điều khiển xuất ra 'o' cho không gian mở đã được tìm kiếm, '.' cho không gian mở chưa được tìm kiếm và '#' cho các chướng ngại vật. Nó chỉ bao gồm những người sống trong danh sách người và tọa độ của họ, và theo dõi tất cả các quy tắc của trò chơi. Bộ điều khiển sẽ thoát nếu cố gắng di chuyển bất hợp pháp. Nếu di chuyển cho một lượt cho trước kết thúc tìm kiếm, đầu ra không như trên; thay vào đó là hình thức

Finished in 4 turns
4 1 0

"4 1 0" ở đây biểu thị 4 lượt tổng, 1 trang phục sinh hoạt và 0 phụ sinh hoạt. Bạn không cần sử dụng bộ điều khiển; cảm thấy tự do để sử dụng nó hoặc sửa đổi nó cho mục nhập của riêng bạn. Nếu bạn quyết định sử dụng nó và gặp phải vấn đề, hãy cho tôi biết.

Cảm ơn @githubphagocyte đã giúp tôi viết bộ điều khiển.

Chỉnh sửa: Đối với mục nhập ngẫu nhiên, bạn có thể chọn bất kỳ lần chạy nào trên bản đồ cụ thể làm điểm số của mình cho bản đồ đó. Lưu ý rằng do các yêu cầu ghi điểm, bạn nên luôn luôn chọn ít lượt nhất, sau đó là ít trang phục chết nhất, sau đó là số lần bổ sung chết ít nhất cho mỗi bản đồ.


7
dòng thứ hai nên giữa các thẻ spoilers!
Averroes

Câu trả lời:


8

Ruby, An toàn đầu tiên + BFS + Tính ngẫu nhiên, Điểm số ≤ 1458

Tôi không chắc chắn làm thế nào bạn sẽ ghi được đệ trình ngẫu nhiên. Nếu tất cả các câu trả lời phải có tính xác định, hãy cho tôi biết và tôi sẽ chọn một hạt giống hoặc loại bỏ hoàn toàn tính ngẫu nhiên.

Một số tính năng và thiếu sót của giải pháp này:

  • Không ai chết cả. Khi bắt đầu, tôi nhóm tất cả các diễn viên sao cho mọi người đều an toàn. Các nhân vật trong mỗi nhóm này di chuyển cùng nhau. Điều đó tốt cho việc giữ cho mọi người sống nhưng không hiệu quả tối ưu.
  • Mỗi nhóm tìm kiếm vị trí chưa được khám phá gần nhất trên bản đồ thông qua tìm kiếm theo chiều rộng đầu tiên và thực hiện bước di chuyển đầu tiên của nhánh tìm kiếm đó. Nếu có sự ràng buộc giữa nhiều lần di chuyển tối ưu, một bước ngẫu nhiên sẽ được chọn. Điều này là để đảm bảo rằng không phải tất cả các nhóm luôn đi theo cùng một hướng.
  • Chương trình này không biết về quan điểm. Nó thực sự cố gắng di chuyển đến mọi tế bào chưa được khám phá. Việc tính đến điều này có thể làm tăng đáng kể hiệu suất, kể từ đó bạn cũng có thể định lượng chất lượng của mỗi lần di chuyển bằng bao nhiêu ô sẽ phát hiện ra.
  • Chương trình không theo dõi thông tin giữa các lượt (trừ các nhóm diễn viên). Điều đó làm cho nó khá chậm trên các trường hợp thử nghiệm lớn hơn. map5.txtmất từ ​​1 đến 13 phút để hoàn thành.

Một số kết quả

Map     Min turns    Max turns
map1        46           86
map2        49          104
map3       332          417
map4       485          693
map5       546          887

Bây giờ đây là mã:

start = Time.now

map_file = ARGV.shift
w=h=p=q=0
File::open(map_file, 'r') do |file|
    w,h,p,q = file.gets.split.map(&:to_i)
end

costars = p > 0 ? (1..p).map {|i| (i+64).chr} : []
extras = q > 0 ? (1..q).map {|i| (i+96).chr} : []
groups = []

costars.zip(extras).each do |costar, extra|
    break unless extra
    groups << (costar + extra)
    costars.delete(costar)
    extras.delete(extra)
end

costars.each_slice(2) {|c1, c2| groups << (c1 + (c2 || '@'))} unless costars.empty?
extras.each_slice(3) {|c1, c2, c3| groups << (c1 + (c2 || '') + (c3 || '@'))} unless extras.empty?
groups << '@' unless groups.join['@']

#$stderr.puts groups.inspect


directions = {
    1 => [-1, 1],
    2 => [ 0, 1],
    3 => [ 1, 1],
    4 => [-1, 0],
    5 => [ 0, 0],
    6 => [ 1, 0],
    7 => [-1,-1],
    8 => [ 0,-1],
    9 => [ 1,-1]
}

loop do
    break unless gets # slurp turn number
    coords = {}
    input = gets
    input.chop.chop.split.each{|s| actor, c = s.split(':'); coords[actor] = c.split(',').map(&:to_i)}
    #$stderr.puts input
    #$stderr.puts coords.inspect
    map = []
    h.times { map << gets.chomp }

    gets # slurp separator
    moves = groups.map do |group|
        x, y = coords[group[0]]
        distances = {[x,y] => 0}
        first_moves = {[x,y] => nil}
        nearest_goal = Float::INFINITY
        best_move = []
        active = [[x,y]]
        while !active.empty?
            coord = active.shift
            dist = distances[coord]
            first_move = first_moves[coord]
            next if dist >= nearest_goal
            [1,2,3,4,6,7,8,9].each do |move|
                dx, dy = directions[move]
                x, y = coord
                x += dx
                y += dy
                next if x < 0 || x >= w || y < 0 || y >= h || map[y][x] == '#'
                new_coord = [x,y]
                if !distances[new_coord]
                    distances[new_coord] = dist + 1
                    first_moves[new_coord] = first_move || move
                    active << new_coord if map[y][x] == 'o'
                end

                if dist < distances[new_coord]
                    distances[new_coord] = dist + 1
                    first_moves[new_coord] = first_move || move
                end

                if map[y][x] == '.'
                    if dist + 1 < nearest_goal
                        nearest_goal = dist + 1
                        best_move = [first_moves[new_coord]]
                    elsif dist + 1 == nearest_goal
                        best_move << first_moves[new_coord]
                    end
                end
            end
        end

        #if group['@']
        #    distances.each{|k,v|x,y=k;map[y][x]=(v%36).to_s(36)}
        #    $stderr.puts map
        #end

        dir = best_move.sample
        group.chars.map {|actor| actor + dir.to_s}
    end * ' '
    #$stderr.puts moves
    puts moves
    $stdout.flush
end

#$stderr.puts(Time.now - start)

Có một vài nhận xét ra đầu ra gỡ lỗi trong đó. Đặc biệt là if group['@']khối này khá thú vị vì nó in ra một hình ảnh trực quan của dữ liệu BFS.

Chỉnh sửa: Cải thiện tốc độ đáng kể, bằng cách dừng BFS nếu đã tìm thấy di chuyển tốt hơn (đó là điểm quan trọng của việc sử dụng BFS ở vị trí đầu tiên).


Có an toàn không khi mong đợi rằng mục nhập của bạn sẽ luôn có quyền truy cập vào tệp bản đồ?
Sparr

Vâng; tệp bản đồ luôn ở đó và nếu bạn sử dụng bộ điều khiển, bạn sẽ nhận được một bản sao cập nhật của nó mỗi lượt.
Eric Tressler
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.