Illumina una Roguelike


14

Dato un tabellone, scrivi il programma o la funzione più breve per visualizzare o restituire quali personaggi sono in vista del giocatore. Un personaggio è in vista se è possibile tracciare una linea tra lui e il giocatore, senza attraversare alcun personaggio che blocchi la visione.

Ingresso:

  • @rappresenta la posizione del giocatore. Ci sarà solo uno di questi nell'input.
  • qualsiasi personaggio che corrisponde alla [#A-Z]visione regex blocca.
  • qualsiasi personaggio che corrisponda [ a-z]consente la visione.
  • non ci saranno caratteri non validi
  • ti viene garantito un input rettangolare

Le linee sono definite come segue:

  • definire il vettore come grandezza e direzione
  • una direzione è una tra N, NE, E, SE, S, SW, W, NW
  • un magnitudo è il numero di caratteri lungo quella direzione da contare
  • lascia che il vettore iniziale sia chiamato d 1 ; il secondo vettore si chiama d 2
  • uno di d 1 o d 2 deve avere una grandezza di 1; l'altro può avere qualsiasi grandezza
  • La direzione di d 1 deve essere adiacente alla direzione di d 2 (ad es. N e NE)

Una linea è definita per essere tutti i caratteri lungo il percorso contrassegnato applicando d 1 , quindi d 2 , d 1 , d 2 ....

Linea di campionamento (indicata dalla .s):
d 1 = (magnitudine: 4, direzione: E)
d 2 = (magnitudine: 1, direzione NE)

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

Produzione:

  • ogni personaggio visibile nella giusta posizione, .sostituisce lo spazio.
  • Spazio per ogni personaggio non visibile.

Input di esempio:

@         
    K     
 J        

    L   




         o

Uscita corrispondente:

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

Input di esempio:

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

Uscita corrispondente:

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

Input di esempio:

  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        

Uscita corrispondente:

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

3
OK ... pipistrelli, tutti i tipi di funghi, muffe e serpenti e persino spettri bloccano la linea di vista, ma i mimi giganti, gli orchi delle colline, i mastodonti, tutti i tipi di altre creature o persino i vortici di fuoco no?
John Dvorak,

@JanDvorak Ero pigro e ho scelto le lettere maiuscole per bloccare. Un po 'come mostri TALL contro mostri corti; quale saresti in grado di vedere oltre. Quindi sì.
Justin,

1
Non conosco la meccanica quantistica, ma il pipistrello e la mummia dello gnomo potrebbero essere un affare facile. Il mimico potrebbe complicare ulteriormente le cose, però. Inoltre, quelle tre formiche potrebbero essere divertenti e il folto gruppo di mostri assortiti nel nord-est potrebbe già conoscerti. Sì ... potrebbe essere brutto. Per quanto riguarda il n. 3: dov'è il mio rotolo di teletrasporto? Oops, quello era distruggere l'armatura.
John Dvorak,

3
Solo un'osservazione curiosa, ma se capisco bene la tua definizione di "linea", sembra che ci siano alcuni quadrati che non saranno visibili anche senza ostacoli. Ad esempio, se il giocatore è a (0, 0), allora il quadrato a (5, 12) non può essere raggiunto da nessuna linea. Potrebbe essere più sensato, per esempio, specificare alcune implementazioni canoniche dell'algoritmo di linea di Bresenham per tracciare una linea tra due punti qualsiasi e definire un quadrato come oscurato se la linea tra esso e il giocatore interseca un ostacolo.
Ilmari Karonen,

1
@IlmariKaronen Hai assolutamente ragione. È così che mi piace. :-).
Justin,

Risposte:


5

GolfScript, 171 caratteri

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

L'ingresso deve essere fornito su STDIN.

L'output per gli esempi sopra riportati è leggermente diverso. Ho verificato le risposte a mano e penso che siano corrette.

Esempio 1:

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

Esempio 2:

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

Esempio 3:

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

Questo non sembra funzionare con input a linea singola (che sono rettangoli validi ...)
Justin

@Quincunx Il codice presuppone che tu abbia finalizzato l'input con una nuova riga. In alternativa, anteporre n+al codice.
Howard,

4

Rubino - 510 caratteri

Abbastanza un mammut; ma è il mio primo tentativo in assoluto di giocare a golf.

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

L'input è un file specificato come argomento; Presumo che il file di input sia composto da un blocco rettangolare di caratteri (quindi spazi inclusi) e che abbia una riga finale.

Questa versione fa ampio uso di catch-throwper uscire da loop profondi; Posso eventualmente migliorare le cose con i loop controllati da limiti invece.

Codice non filtrato:

# 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

modificare

Ilmari Karonen osserva nella domanda commenti che l'algoritmo di visione dato non vede tutti i quadrati, anche quando non ci sono ostacoli. Ecco una dimostrazione di ciò, a (40,40) di distanza dal giocatore.

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

Hmm. Questo fallisce il test 3. Richiede il debug.
Chowlett,

sei sicuro? Avrei potuto fare un errore ...
Justin,

Abbastanza sicuro: posso vedere la V dietro il muro! Penso di non rilevare la nuova riga dopo la riga precedente.
Chowlett,

Sicuramente non dovrei vederlo ...
Justin il

Ah, è stato un problema con il mio contributo; Ho avuto uno spazio extra dopo XqQ. Detto questo, la tua risposta data per 3 non corrisponde affatto al testcase - almeno ha una linea in più in alto e solo uno spazio tra il Oe l.
Chowlett,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.