恐怖电影搜寻派对


21

剧情:吉米失踪了;我们必须找到他。我们应该分手。

剧情转折:吉米已经死了。

但是,我们的演员不知道这一点,因此他们仍然需要搜索整个区域。有N列x M行(1 <= M,N <= 256)的单元格网格,其中任一网格标记为“ S”作为起点“”。代表开放空间,“#”代表障碍物。这是地图

有0 <= p <= 26个Costars,0 <= q <= 26个Extras和1个star。最初,每个人都在标记为S的单元格中。

规则

每个人的视线半径如下所示:

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

星星用“ @”表示,古斯塔用大写字母表示,以“ A”开头,多余部分用小写字母表示,以“ a”开头。最初,起点周围的视线半径已标记为已搜索。如果这构成了地图的整个开放空间,则游戏结束。每转,按以下顺序

  1. 每个人同时使国王移动(要么静止不动,要么移动到8个相邻牢房之一)。
  2. 每个人周围视线半径内的所有像元都算作搜索。
  3. 如果肋骨看不见别人,她就会死。如果一个额外人员看不到肋骨,星星或至少2个其他额外人员,他会死。这些事件同时发生 -也就是说,单回合就没有死亡的连锁反应;检查以上条件,每个要死的人都会立即死亡。
  4. 如果已经搜索了地图上的所有开放空间,则搜索结束。

笔记

任何时候都可以有多个人在同一广场上,这些人可以看到彼此。

障碍永远不会阻碍视线,只会阻碍运动。人们可以在熔岩上看到彼此,呃...熔岩?

确保地图上的开放空间由国王移动连接。

最初的“ S”也被认为是开放空间,而不是障碍物。

降落在开放空间上的任何国王举动均有效。例如,以下举动是合法的:

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

输入项

输入将采用以下格式

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

输入样例:

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

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

p和q分别是Costar和Extras的数量。

输出量

输出应该是每一转的动作,其方向为

789
456
123

动作的顺序无关紧要,因为它们都是同时制定的。不列出某人的举动是好的,并且等同于朝方向5移动。举动应以以下格式列出:

@9 A2 a2 B7.

“。” 表示您转弯的动作结束。

搜索完地图后,输出的最后一行应该是三个整数,并用空格分隔:完成搜索木板所需的转数,居住的肋骨数量和居住的附加设施数量。对于第一个示例输入

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

以下是有效的输出:

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

最后要注意的是:恒星不会死,并且可以保证地图上的开放空间已经连通,因此搜索始终将最终成功。

计分

您的分数是一组基准测试所经过的总回合数;欢迎您提交自己的测试用例以及答案。超过基准集的生活肋骨总数将被用作平局,如果仍然存在平局,则将使用额外生活费的总数。

测试仪和控制器

目前,https://github.com/Tudwell/HorrorMovieSearchParty/上有5幅地图在线。提交答案的任何人都可能还会提交测试用例,我保留出于任何原因拒绝测试的权利(如果由于某种原因我拒绝了您的地图,则您可以提交另一个)。我将自行决定将这些添加到测试集中。

在github上提供了一个Python (在2.7.5中测试)控制器作为 controller.py。那里的第二个控制器controller_disp.py相同,除了它在搜索过程中显示图形输出(需要Pygame库)。

图形控制器输出

用法

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

即:

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

控制器具有以下形式的输出(到您程序的stdin):

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

这是转弯编号(转弯之前是转弯1),是所有演员及其x,y坐标的“。”终止列表(左上角的字符为(0,0)),表示整个演员板,并与40'-线。然后,它等待表单的输入(来自程序的stdout

@9 A2 B7.

这是上面指定的输出格式。控制器为搜索到的开放空间输出“ o”。表示尚未搜索的开放空间,“#”表示障碍物。它仅在人物列表及其座标中包含有生命的人物,并跟踪游戏的所有规则。如果尝试非法移动,控制器将退出。如果给定回合的移动完成了搜索,则输出结果将与上面不同;而是它的形式

Finished in 4 turns
4 1 0

“ 4 1 0”在这里表示4个总转弯,1个生活肋类和0个生活附加类。您不需要使用控制器。您可以随意使用它或对其进行修改,以用于自己的输入。如果您决定使用它并遇到问题,请告诉我。

感谢@githubphagocyte帮助我编写控制器。

编辑: 对于随机条目,您可以选择特定地图上的任意跑步作为该地图的得分。请注意,由于计分要求,对于每张地图,您都应始终选择最少的转弯,最少的死肋条,最少的额外附加值。


7
第二行应该在剧透标签之间!
Averroes 2014年

Answers:


8

Ruby,安全第一+ BFS +随机性,得分≤1458

我不确定您将如何为随机提交打分。如果所有答案都必须是确定性的,请让我知道,我将选择一个种子或完全摆脱随机性。

此解决方案的一些功能和缺点:

  • 没有人去世。首先,我将所有演员分组,以便每个人都安全。这些组中的每个字符都一致移动。这对于使每个人都活着却不是最佳效率很有好处。
  • 每个组都通过广度优先搜索在地图上搜索最近的未勘探点,并采取该搜索分支的第一步。如果多个最佳移动之间存在平局,则随机选择一个。这是为了确保并非所有组都始终朝着相同的方向前进。
  • 该程序不了解视野。实际上,它试图移动到每个未探索的单元。考虑到这一点,可能会大大提高性能,因为从那时起,您还可以通过发现每个移动的数量来量化每个移动的质量。
  • 该程序不会跟踪各个回合之间的信息(演员组除外)。这使得在较大的测试用例上相当慢。map5.txt需要1到13分钟才能完成。

一些结果

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

现在这里是代码:

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)

那里有一些注释掉的调试输出。特别是该if group['@']块非常有趣,因为它可以打印出BFS数据的可视化图像。

编辑:如果已经找到更好的动作,则停止BFS,可以显着提高速度(这首先是使用BFS的关键)。


是否可以安全地期望您的条目将始终有权访问地图文件?
Sparr 2014年

是; 地图文件始终存在,并且如果您使用控制器,则每转一圈都会获得其更新副本。
埃里克·特雷斯勒
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.