หนังสยองขวัญปาร์ตี้ค้นหา


21

เรื่องย่อ : Jimmy หายไป; เราต้องไปหาเขา เราควรแยกกัน

เรื่องย่อ : Jimmy ตายไปแล้ว

แต่นักแสดงของเราไม่รู้เช่นนั้นดังนั้นพวกเขาจึงต้องค้นหาพื้นที่ทั้งหมดต่อไป มีตาราง N คอลัมน์ x M แถว (1 <= M, N <= 256) ตารางของเซลล์ซึ่งระบุว่าเป็น "S" สำหรับจุดเริ่มต้น " สำหรับพื้นที่เปิดโล่งหรือ "#" สำหรับสิ่งกีดขวาง นี่คือแผนที่

มีอยู่ 0 <= p <= 26 มีcostars , 0 <= Q <= 26 แถมและ 1 ดาว ทุกคนเริ่มต้นในเซลล์ที่มีเครื่องหมาย S

กฎระเบียบ

แต่ละคนมีรัศมีสายตาที่แสดงด้านล่าง:

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

ดาวฤกษ์นั้นเขียนด้วย "@" ซึ่งเป็นตัวพิมพ์ใหญ่โดยใช้ตัวพิมพ์ใหญ่เริ่มต้นด้วย "A" และส่วนที่เพิ่มเติมด้วยตัวอักษรพิมพ์เล็กเริ่มต้นด้วย "a" เริ่มแรกรัศมีการมองเห็นโดยรอบจุดเริ่มต้นจะถูกทำเครื่องหมายเป็นค้นหาแล้ว หากนี่เป็นการเปิดพื้นที่ทั้งหมดของแผนที่เกมจะสิ้นสุดลง กลับกันในลำดับต่อไปนี้ :

  1. แต่ละคนพร้อมกันทำให้กษัตริย์เคลื่อนไหว (ไม่ว่าจะยืนนิ่งหรือเคลื่อนที่ไปยังหนึ่งใน 8 เซลล์ใกล้เคียง)
  2. เซลล์ทั้งหมดในรัศมีสายตารอบ ๆ แต่ละคนจะถูกนับเป็นการค้นหา
  3. ถ้า costar ไม่เห็นใครเลยเธอก็ตาย หากมีคนพิเศษไม่สามารถมองเห็นคอสตาร์ดาวหรือสิ่งอื่นอย่างน้อย 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 คือจำนวนของ costars และ extras ตามลำดับ

เอาท์พุต

เอาท์พุทควรจะเป็นสำหรับการเปิดแต่ละครั้งการเคลื่อนไหวที่ทำด้วยทิศทางที่ระบุ

789
456
123

คำสั่งของการเคลื่อนไหวไม่สำคัญเพราะพวกเขาทั้งหมดพร้อมกัน ไม่แสดงรายการการย้ายสำหรับบุคคลนั้นเป็นเรื่องปกติและเทียบเท่ากับการย้ายเขาไปในทิศทางที่ 5 การย้ายควรจะอยู่ในรูปแบบต่อไปนี้:

@9 A2 a2 B7.

"" หมายถึงการสิ้นสุดของการเคลื่อนไหวของคุณสำหรับการเปิด

หลังจากค้นหาแผนที่แล้วบรรทัดสุดท้ายของผลลัพธ์ควรเป็นจำนวนเต็มสามจำนวนคั่นด้วยช่องว่าง: จำนวนรอบที่คุณใช้เพื่อค้นหาบอร์ดให้เสร็จสิ้นจำนวนค่าใช้จ่ายในการดำรงชีวิตและจำนวนของสิ่งอำนวยความสะดวกพิเศษ สำหรับอินพุตตัวอย่างแรก

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

ต่อไปนี้คือผลลัพธ์ที่ถูกต้อง:

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

หมายเหตุสุดท้าย: ดาวไม่สามารถตายได้และรับประกันว่าจะมีการเปิดพื้นที่บนแผนที่เพื่อเชื่อมต่อดังนั้นการค้นหาจะประสบความสำเร็จในที่สุด

เกณฑ์การให้คะแนน

คะแนนของคุณคือจำนวนเทิร์นทั้งหมดที่ใช้ในชุดการทดสอบเกณฑ์มาตรฐาน คุณสามารถส่งกรณีทดสอบของคุณเองพร้อมกับคำตอบของคุณ ผลรวมของจำนวนค่าครองชีพเหนือชุดมาตรฐานจะถูกใช้เป็นตัวแบ่งไทเบรกเกอร์และในกรณีที่ยังมีเน็คไทอยู่จะใช้ผลรวมของจำนวนค่าครองชีพพิเศษ

ชุดทดสอบและคอนโทรลเลอร์

ปัจจุบัน 5 แผนที่ที่ออนไลน์อยู่ในhttps://github.com/Tudwell/HorrorMovieSearchParty/ ใครก็ตามที่ส่งคำตอบอาจส่งกรณีทดสอบซึ่งฉันขอสงวนสิทธิ์ในการปฏิเสธด้วยเหตุผลใด ๆ (ถ้าฉันปฏิเสธแผนที่ของคุณด้วยเหตุผลบางอย่างคุณอาจส่งอีก) สิ่งเหล่านี้จะถูกเพิ่มเข้าไปในชุดทดสอบตามดุลยพินิจของฉัน

งูหลาม(ทดสอบใน 2.7.5)ตัวควบคุมอยู่ใน GitHub เป็น controller.py ตัวควบคุมตัวที่สองนั่นคือcontroller_disp.pyเหมือนกันยกเว้นจะแสดงเอาท์พุทกราฟิกในระหว่างการค้นหา (ต้องใช้ Pygame library)

เอาต์พุตคอนโทรลเลอร์แบบกราฟิก

การใช้งาน :

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 ที่ช่วยฉันเขียนคอนโทรลเลอร์

แก้ไข: สำหรับรายการแบบสุ่มคุณสามารถเลือกวิ่งบนแผนที่ใด ๆ เป็นคะแนนของคุณสำหรับแผนที่นั้น โปรดทราบว่าเนื่องจากข้อกำหนดการให้คะแนนคุณควรเลือกเทิร์นที่น้อยที่สุดจากนั้นเลือก costars ที่ตายแล้วน้อยที่สุดจากนั้นเลือก extras deadest ที่น้อยที่สุดสำหรับแต่ละแผนที่


7
บรรทัดที่สองควรอยู่ระหว่างแท็กสปอยเลอร์!
Averroes

คำตอบ:


8

ทับทิมความปลอดภัยอันดับแรก + 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)

มีเอาต์พุต debug บางส่วนที่คอมเม้นต์อยู่ในนั้น โดยเฉพาะอย่างยิ่งif group['@']บล็อกนั้นค่อนข้างน่าสนใจเพราะมันแสดงภาพข้อมูล BFS

แก้ไข:การปรับปรุงความเร็วที่สำคัญโดยหยุด BFS หากพบการเคลื่อนไหวที่ดีขึ้นแล้ว (ซึ่งเป็นจุดที่ใช้ BFS ในตอนแรก)


จะปลอดภัยหรือไม่หากคุณคาดว่าข้อมูลของคุณจะสามารถเข้าถึงไฟล์แผนที่ได้ตลอดเวลา?
Sparr

ใช่; ไฟล์แผนที่อยู่ที่นั่นเสมอและหากคุณใช้คอนโทรลเลอร์คุณจะได้รับสำเนาที่ปรับปรุงแล้วของมันในแต่ละเทิร์น
Eric Tressler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.