Зажги Roguelike


14

С учетом доски напишите самую короткую программу или функцию для отображения или возврата символов, которые видны игроку. Персонаж находится в поле зрения, если можно провести черту между ним и игроком, не пересекая персонажей, которые мешают зрению.

Входные данные:

  • @представляет позицию игрока. На входе будет только один из них.
  • любой персонаж, который соответствует регулярному выражению, [#A-Z]блокирует зрение.
  • любой персонаж, который соответствует, [ a-z]позволяет зрение.
  • не будет недопустимых символов
  • вам гарантирован прямоугольный ввод

Линии определены следующим образом:

  • определить вектор, чтобы быть величиной и направлением
  • направление одно из N, NE, E, SE, S, SW, W, NW
  • величина - это количество символов в этом направлении для подсчета
  • пусть начальный вектор называется d 1 ; второй вектор будет называться d 2
  • один из d 1 или d 2 должен иметь величину 1; другой может иметь любую величину
  • Направление d 1 должно быть смежным с направлением d 2 (например, N и NE)

Линия определена, чтобы быть всеми символами вдоль пути, отмеченного применением d 1 , затем d 2 , d 1 , d 2 ....

Линия выборки (задается с помощью .s):
d 1 = (величина: 4, направление: E)
d 2 = (величина: 1, направление NE)

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

Выход:

  • каждый видимый символ в правильной позиции, .заменяет пробел.
  • Место для каждого невидимого символа.

Пример ввода:

@         
    K     
 J        

    L   




         o

Соответствующий вывод:

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

Пример ввода:

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

Соответствующий вывод:

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

Пример ввода:

  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        

Соответствующий вывод:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   

3
Хорошо ... летучие мыши, все виды грибов, плесени, змей и даже призраков блокируют линию обзора, но гигантские мимики, горные орки, мастодонты, всевозможные другие существа или даже огненные вихри не делают?
Джон Дворак

@JanDvorak Я был ленив и выбрал заглавные буквы для блокировки. Вроде как TALL монстров против коротких монстров; что бы вы могли увидеть. Так да.
Джастин

1
Я не знаю о квантовой механике, но летучая мышь и мумия гнома могут быть легкой сделкой. Однако, мимика может усложнить ситуацию. Кроме того, эти три муравья могут быть забавными, и большая группа разнообразных монстров на северо-востоке уже может знать о вас. Да ... это может быть неприятно. Что касается № 3 - где мой свиток телепорации? Ой, это было уничтожить доспехи.
Джон Дворак

3
Просто любопытное наблюдение, но если я правильно понимаю ваше определение «линии», похоже, что есть некоторые квадраты, которые не будут видны даже без каких-либо препятствий. Например, если игрок находится в (0, 0), то квадрат в (5, 12) не может быть достигнут ни одной линией. Возможно, имело бы больше смысла, скажем, указать некоторую каноническую реализацию алгоритма линии Брезенхэма для рисования линии между любыми двумя точками и определить квадрат как неясный, если линия между ним и игроком пересекает препятствие.
Ильмари Каронен

1
@IlmariKaronen Вы абсолютно правы. Вот как мне это нравится. :-).
Джастин

Ответы:


5

GolfScript, 171 символов

.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*

Ввод должен быть предоставлен на STDIN.

Выходные данные для приведенных выше примеров немного отличаются. Я проверил ответы от руки и думаю, что они правильные.

Пример 1:

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

Пример 2:

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

Пример 3:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   

Кажется, это не работает для однострочных входов (которые являются действительными прямоугольниками ...)
Джастин

@Quincunx Код предполагает, что вы завершаете ввод с новой строкой. В качестве альтернативы, добавьте n+код.
Говард

4

Рубин - 510 символов

Совсем мамонт; но это моя первая попытка в гольфе.

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

Ввод осуществляется с помощью файла, указанного в качестве аргумента; Я предполагаю, что входной файл состоит из прямоугольного блока символов (то есть, включая конечные пробелы) и содержит завершающий символ новой строки.

Эта версия широко используется catch-throwдля выхода из глубоких петель; Вместо этого я могу улучшить положение с помощью проверенных границ.

Необъяснимый код:

# 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

редактировать

Илмари Каронен отмечает в комментариях к вопросу, что данный алгоритм видения не видит все квадраты, даже когда нет препятствий. Вот демонстрация этого, до (40,40) от игрока.

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

Хм. Это не проходит тест 3. Требуется отладка.
Чоулетт

вы уверены? Я мог ошибиться ...
Джастин

Уверен - я вижу V за стеной! Я думаю, что я не обнаруживаю новую строку после предыдущей строки.
Чоулетт

Определенно не должно видеть это ...
Джастин

Ах, это была проблема с моим вкладом; У меня было дополнительное место после XqQ. Тем не менее, ваш ответ на 3 не соответствует тестовому сценарию - в нем по крайней мере есть дополнительная строка вверху и только один пробел между Oи l.
Чоулетт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.