Nyalakan Roguelike

14

Diberi papan, tulis program atau fungsi terpendek untuk menampilkan atau mengembalikan karakter yang terlihat oleh pemain. Sebuah karakter akan terlihat jika mungkin untuk menarik garis antara itu dan pemain, tanpa melintasi karakter apa pun yang menghalangi penglihatan.

Memasukkan:

  • @mewakili posisi pemain. Hanya ada satu dari ini di input.
  • setiap karakter yang cocok dengan [#A-Z]visi blok regex .
  • karakter apa pun yang cocok [ a-z]memungkinkan penglihatan.
  • tidak akan ada karakter yang tidak valid
  • Anda dijamin input persegi panjang

Garis didefinisikan sebagai berikut:

  • mendefinisikan vektor menjadi besar dan arah
  • arah adalah salah satu dari N, NE, E, SE, S, SW, W, NW
  • besarnya adalah berapa banyak karakter di sepanjang arah itu untuk dihitung
  • biarkan vektor awal disebut d 1 ; vektor kedua disebut d 2
  • salah satu dari d 1 atau d 2 harus memiliki besaran 1; yang lain mungkin memiliki besaran apa pun
  • Arah d 1 harus berbatasan dengan arah d 2 (mis: N dan NE)

Garis didefinisikan sebagai semua karakter di sepanjang jalan yang ditandai dengan menerapkan d 1 , lalu d 2 , d 1 , d 2 ....

Garis sampel (diberikan oleh .s):
d 1 = (besarnya: 4, arah: E)
d 2 = (besarnya: 1, arah NE)

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

Keluaran:

  • setiap karakter yang terlihat di posisi yang tepat, .menggantikan ruang.
  • Ruang untuk setiap karakter yang tidak terlihat.

Input sampel:

@         
    K     
 J        

    L   




         o

Output yang sesuai:

@.........
....K.....
.J.....   
..........
.. .L.....
..  . ....
... .. ...
...  .. ..
...   .  .
....  ..  

Input sampel:

 B###M#  by 
 #Q   # Zmpq
 # # aaa    
@  m #      
# ##P#      
# ####      
# ####      
#M ###      
######      

Output yang sesuai:

.B  #M      
.# ..   Z pq
.#.#.aaa..  
@..m.#      
#.##P#      
 .#         
 .#         
 M.         
  #         

Input sampel:

  w                 

     O  l   gg  rT  
   QQL      Ag  #b  
   qqqqq         XqQ
 x     V# f@aa      
   Y        aaa     
   uU  E  l TaKK    
  e  dd  FF d opi   
   e       d        

Output yang sesuai:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   
Justin
sumber
3
OK ... kelelawar, semua jenis jamur, jamur dan ular dan bahkan hantu menghalangi pandangan, tetapi tiruan raksasa, orc bukit, mastodon, semua jenis makhluk lain atau bahkan vortisitas api tidak?
John Dvorak
@ JanDvorak Saya malas dan memilih huruf kapital untuk diblokir. Semacam monster TALL vs monster pendek; yang akan Anda bisa melihat. Jadi iya.
Justin
1
Saya tidak tahu tentang mekanika kuantum, tetapi kelelawar dan mumi gnome mungkin mudah. Namun, mimik itu mungkin memperumit masalah. Juga, ketiga semut itu mungkin menyenangkan, dan sekelompok besar monster macam-macam di timur laut mungkin sudah tahu tentang Anda. Ya ... itu mungkin jahat. Adapun # 3 - di mana gulir teleporasi saya? Ups, itu menghancurkan baju besi.
John Dvorak
3
Hanya pengamatan yang aneh, tetapi jika saya memahami definisi "garis" Anda dengan benar, sepertinya ada beberapa kotak yang tidak akan terlihat bahkan tanpa hambatan. Misalnya, jika pemain berada di (0, 0), maka kuadrat di (5, 12) tidak dapat dijangkau oleh garis apa pun. Mungkin lebih masuk akal untuk, katakanlah, menentukan beberapa implementasi kanonik dari algoritma garis Bresenham untuk menggambar garis antara dua titik, dan mendefinisikan kotak sebagai dikaburkan jika garis antara itu dan pemain memotong rintangan.
Ilmari Karonen
1
@IlmariKaronen Anda benar sekali. Itulah yang saya suka. :-).
Justin

Jawaban:

5

GolfScript, 171 karakter

.n?):L)[n*.]*1/:I'@'?{\+[{1$+}*]..{I=26,{65+}%"#
"+\?)}??)<}+{[L~.).)1L)L.(-1L~]>2<`{[.[~\]]{1/~2$*+L*.-1%}%\;~}+L,%~}8,%%{|}*`{1$?)I@=.n=@|\.' '={;'.'}*' 'if}+I,,%''*n%n*

Masukan harus diberikan di STDIN.

Output untuk contoh yang diberikan di atas sedikit berbeda. Saya memverifikasi jawaban dengan tangan dan berpikir itu benar.

Contoh 1:

@.........
....K.....
.J.....   
..........
.. .L.....
..  . ....
... .. ...
...  .. ..
...   .  .
....  ..  

Contoh 2:

.B  #M      
.# ..   Z pq
.#.#.aaa..  
@..m.#      
#.##P#      
 .#         
 .#         
 M.         
  #         

Contoh 3:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   
Howard
sumber
Ini tampaknya tidak berfungsi untuk input baris tunggal (yang merupakan persegi panjang yang valid ...)
Justin
@ Quincunx Kode ini mengasumsikan bahwa Anda menyelesaikan input Anda dengan baris baru. Atau dapat juga ditambahkan n+ke kode.
Howard
4

Ruby - 510 karakter

Cukup besar; tapi ini adalah percobaan golf saya yang pertama.

m=$<.read;w,s,o,p=m.index(?\n)+1,m.size,m.dup.gsub(/[^@\n]/,' '),m.index(?@);d=[-w,1-w,1,w+1,w,w-1,-1,-1-w];0.upto(7){|i|x=d[i];[i-1,i+1].each{|j|y=d[j%8];[1,nil].each{|l|t=0;catch(:a){loop{c,f,r=p,1,nil;catch(:b){loop{(l||r)&&(1.upto(t){|u|c+=x;n=!(0...s).include?(c)||m[c]==?\n;n&&throw(f ?:a: :b);o[c]=m[c]==" "??.: m[c];a=m[c]=~/[#A-Z]/;a&&throw(f ?:a: :b)};f=nil);r=1;c+=y;n=!(0...s).include?(c)||m[c]==?\n;n&&throw(f ?:a: :b);o[c]=m[c]==" "??.: m[c];a=m[c]=~/[#A-Z]/;a&&throw(f ?:a: :b)}};t+=1}}}}};$><<o

Input dengan file ditentukan sebagai argumen; Saya menganggap file input terdiri dari blok karakter persegi panjang (jadi, termasuk spasi tambahan), dan memiliki baris baru tambahan.

Versi ini menggunakan ekstensif catch-throwuntuk keluar dari loop mendalam; Saya mungkin dapat memperbaiki masalah dengan batas-memeriksa loop sebagai gantinya.

Kode tidak terotorisasi:

# Read the map in
map = $<.read

# Determine its width and size
width = map.index("\n")+1
size = map.size

# Create a blank copy of the map to fill in with visible stuff
output = map.dup.gsub /[^@\n]/,' '

# Locate the player
player = map.index('@')

dirs = [
  -width,   # N
  1-width,  # NE
  1,        # E
  width+1,  # SE
  width,    # S
  width-1,  # SW
  -1,       # W
  -1-width  # NW
]

0.upto(7) do |i1|
  d1 = dirs[i1]
  [i1-1, i1+1].each do |i2|
    d2 = dirs[i2%8]

    # Stepping by 0,1,2... in d1, work along the line.
    # Write the cell value into the duplicate map, then break if it's
    # a "solid" character.
    #
    # Extensive use of catch-throw lets us exit deep loops.

    # For convenience of notation, instead of having either d1 or d2
    # be magnitude 1, and always doing d1,d2,d1... - I have d2 always
    # being magnitude 1, and doing either d1,d2,d1 or d2,d1,d2...

    # Loop twice - first with d1,d2,d1... second with d2,d1,d2...
    [true,false].each do |long_first|
      step = 0

      catch(:all_done) do
        # This loop increments step each iteration, being the magnitude of d1
        loop do
          cell = player
          first = true  # True until we've done the first d1
          later = false # True once we've done the first d2

          catch(:done) do
            # This loop repeatedly applies d1 and d2
            loop do
              if long_first || later  # Don't apply d1 first if starting with d2
                1.upto(step) do |dd1|
                  cell += d1 # Move one cell in d1
                  invalid = !(0...size).include?(cell) || map[cell]=="\n" # Out of range
                  throw :all_done if first && invalid # No point trying a longer step if the
                                                      # first application of d1 is out of range
                  throw :done if invalid # No point continuing with this step length

                  output[cell]=map[cell] == " " ? '.' : map[cell] # Transfer visble character
                  wall = map[cell]=~/[#A-Z]/  # Hit a wall?
                  throw :all_done if first && wall # Drop out as before
                  throw :done if wall
                end
                first = false
              end
              later=true

              # Now repeat above for the single d2 step
              cell += d2
              invalid = !(0...size).include?(cell) || map[cell]=="\n"
              throw :all_done if first && invalid
              throw :done if invalid
              output[cell]=map[cell] == " " ? '.' : map[cell]
              wall = map[cell]=~/[#A-Z]/
              throw :all_done if first && wall
              throw :done if wall
            end
          end
          step += 1
        end
      end
    end
  end
end

puts output

Edit

Ilmari Karonen mencatat dalam komentar pertanyaan bahwa algoritma penglihatan yang diberikan tidak melihat semua kotak, bahkan ketika tidak ada kendala. Berikut ini adalah demonstrasi dari itu, ke (40,40) jauh dari pemain.

@.......................................
........................................
........................................
........................................
........................................
............ ...........................
..............  ........................
............ ...   ..... ...............
.............. ...    .....  ...........
...............  ...     .....   .......
.................  ...      .....    ...
..................   ...       .....
..... . ............   ...        .....
.....................    ...         ...
...... . ..............    ...
...... .. ..............     ...
....... . ................     ...
....... .. ............. ..      ...
.......  .  .................      ...
........ .. ............... ..       ...
........  .  ............... ...       .
........  ..  ................ ..
.........  .  ................. ...
.........  ..  .................  ..
....... .   .   . ................ ...
..........  ..  ...................  ..
..........   .   ...................  ..
........ .   ..   . ..................
........ ..   .   .. ..................
...........   ..   .....................
......... .    .    . ..................
......... ..   ..   .. .................
......... ..    .    .. ................
.......... .    ..    . ................
.......... ..    .    .. ...............
.......... ..    ..    .. ..............
..........  .     .     .  .............
........... ..    ..    .. .............
........... ..     .     .. ............
...........  .     ..     .  ...........
Chowlett
sumber
Hmm. Tes ini gagal 3. Membutuhkan debugging.
Chowlett
apakah kamu yakin Saya bisa membuat kesalahan ...
Justin
Cukup yakin - Saya bisa melihat V di balik dinding! Saya pikir saya tidak mendeteksi baris baru setelah baris sebelumnya.
Chowlett
Pasti tidak akan melihat itu ...
Justin
Ah, itu masalah dengan masukan saya; Saya memiliki ruang ekstra setelahnya XqQ. Yang mengatakan, jawaban yang Anda berikan untuk 3 tidak cocok dengan testcase sama sekali - itu setidaknya memiliki garis tambahan di atas, dan hanya satu ruang antara Odan l.
Chowlett