Acenda um Roguelike


14

Dado um quadro, escreva o programa ou função mais curto para exibir ou retornar quais personagens estão à vista do jogador. Um personagem está à vista se é possível traçar uma linha entre ele e o jogador, sem cruzar nenhum personagem que bloqueie a visão.

Entrada:

  • @representa a posição do jogador. Haverá apenas um deles na entrada.
  • qualquer caractere que corresponda ao regex [#A-Z]bloqueia a visão.
  • qualquer personagem que corresponda [ a-z]permite visão.
  • não haverá caracteres inválidos
  • você tem uma entrada retangular garantida

As linhas são definidas da seguinte maneira:

  • definir vetor para ser uma magnitude e uma direção
  • uma direção é uma de N, NE, E, SE, S, SW, W, NW
  • uma magnitude é quantos caracteres nessa direção para contar
  • deixe o vetor inicial ser chamado d 1 ; o segundo vetor será chamado d 2
  • um de d 1 ou d 2 deve ter uma magnitude de 1; o outro pode ter qualquer magnitude
  • A direção de d 1 deve estar adjacente à direção de d 2 (por exemplo: N e NE)

Uma linha é definida para ser todos os caracteres ao longo do caminho marcado aplicando d 1 , depois d 2 , d 1 , d 2 ....

Linha de amostra (dada pelos .):
d 1 = (magnitude: 4, direção: E)
d 2 = (magnitude: 1, direção NE)

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

Resultado:

  • cada caractere visível na posição correta .substitui o espaço.
  • Espaço para cada caractere não visível.

Entrada de amostra:

@         
    K     
 J        

    L   




         o

Saída correspondente:

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

Entrada de amostra:

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

Saída correspondente:

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

Entrada de amostra:

  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        

Saída correspondente:

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

3
OK ... morcegos, todos os tipos de fungos, mofos e cobras e até fantasmas bloqueiam a linha de visão, mas imitações gigantes, orcs, mastodontes, todo tipo de outras criaturas ou até vórtices de fogo não?
John Dvorak

@JanDvorak Eu era preguiçoso e escolhi letras maiúsculas para bloquear. Mais ou menos como monstros ALTOS vs monstros curtos; que você seria capaz de ver. Então sim.
Justin

1
Eu não sei sobre mecânica quântica, mas o morcego e a múmia gnomo podem ser um negócio fácil. A imitação pode complicar ainda mais as coisas. Além disso, essas três formigas podem ser divertidas, e o grande grupo de monstros variados do nordeste já deve saber sobre você. Sim ... pode ser desagradável. Quanto ao número 3 - onde está o meu rolo de teleporação? Opa, isso foi destruir a armadura.
John Dvorak

3
Apenas uma observação curiosa, mas se eu entendo direito sua definição de "linha", parece que existem alguns quadrados que não serão visíveis mesmo sem obstáculos. Por exemplo, se o jogador estiver em (0, 0), o quadrado em (5, 12) não poderá ser alcançado por nenhuma linha. Poderia ter feito mais sentido, digamos, especificar alguma implementação canônica do algoritmo de linha de Bresenham para desenhar uma linha entre dois pontos, e definir um quadrado como obscuro se a linha entre ele e o jogador cruzar um obstáculo.
Ilmari Karonen 28/01

1
@IlmariKaronen Você está absolutamente correto. É assim que eu gosto. :-).
Justin

Respostas:


5

GolfScript, 171 caracteres

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

A entrada deve ser fornecida no STDIN.

A saída para os exemplos dados acima é um pouco diferente. Eu verifiquei as respostas manualmente e acho que estão corretas.

Exemplo 1:

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

Exemplo 2:

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

Exemplo 3:

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

Este não parece trabalho para entradas de linha única (que são retângulos válidos ...)
Justin

@Quincunx O código pressupõe que você finalize sua entrada com uma nova linha. Como alternativa, acrescente n+o código.
Howard

4

Ruby - 510 caracteres

Bastante um mamute; mas é a minha primeira tentativa de golfe.

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

A entrada é por arquivo especificado como argumento; Presumo que o arquivo de entrada seja composto por um bloco retangular de caracteres (portanto, espaços à direita incluídos) e que tenha uma nova linha à direita.

Esta versão faz uso extensivo catch-throwpara sair de loops profundos; Possivelmente, posso melhorar as coisas com loops com verificação de limites.

Código não ofuscado:

# 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

Editar

Ilmari Karonen observa na pergunta comenta que o algoritmo de visão fornecido não vê todos os quadrados, mesmo quando não há obstáculos. Aqui está uma demonstração disso, a (40,40) de distância do jogador.

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

Hmm. Isso falha no teste 3. Precisa de depuração.
Chowlett 27/01

você tem certeza? Eu poderia ter feito um erro ...
Justin

Tenho certeza - eu posso ver o V atrás do muro! Acho que não estou detectando a nova linha após a linha anterior.
precisa saber é o seguinte

Definitivamente não deve estar vendo isso ...
Justin

Ah, foi um problema com a minha opinião; Eu tinha um espaço extra depois XqQ. Dito isto, sua resposta dada para 3 não corresponde à caixa de teste - ela tem pelo menos uma linha extra na parte superior e apenas um espaço entre a Oe l.
Chowlett
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.