Illuminez un Roguelike

14

Étant donné un tableau, écrivez le programme ou la fonction la plus courte pour afficher ou renvoyer les personnages en vue du joueur. Un personnage est en vue s'il est possible de tracer une ligne entre lui et le joueur, sans croiser aucun personnage qui bloque la vision.

Contribution:

  • @représente la position du joueur. Il n'y en aura qu'un dans l'entrée.
  • tout personnage qui correspond à la [#A-Z]vision des blocs d' expression régulière .
  • tout personnage qui correspond [ a-z]permet la vision.
  • il n'y aura pas de caractères invalides
  • vous avez la garantie d'une entrée rectangulaire

Les lignes sont définies comme suit:

  • définir le vecteur comme une grandeur et une direction
  • une direction est l'une des N, NE, E, SE, S, SW, W, NW
  • une grandeur est le nombre de caractères dans cette direction pour compter
  • que le vecteur initial soit appelé d 1 ; le deuxième vecteur soit appelé d 2
  • l'un de d 1 ou d 2 doit avoir une magnitude de 1; l'autre peut avoir n'importe quelle ampleur
  • La direction de d 1 doit être adjacente à la direction de d 2 (par exemple: N et NE)

Une ligne est définie pour être tous les caractères le long du chemin marqué en appliquant d 1 , puis d 2 , d 1 , d 2 ....

Ligne d'échantillonnage (donnée par le .s):
d 1 = (magnitude: 4, direction: E)
d 2 = (magnitude: 1, direction NE)

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

Production:

  • chaque caractère visible dans la bonne position, .remplace l'espace.
  • Espace pour chaque personnage non visible.

Exemple d'entrée:

@         
    K     
 J        

    L   




         o

Sortie correspondante:

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

Exemple d'entrée:

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

Sortie correspondante:

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

Exemple d'entrée:

  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        

Sortie correspondante:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   
Justin
la source
3
OK ... les chauves-souris, toutes sortes de champignons, les moisissures et les serpents et même les spectres bloquent la ligne de vue, mais les imitations géantes, les orcs des collines, les mastodontes, toutes sortes d'autres créatures ou même les tourbillons de feu ne le font pas?
John Dvorak
@JanDvorak J'étais paresseux et j'ai choisi les majuscules pour le blocage. Un peu comme des monstres TALL vs des monstres courts; qui seriez-vous en mesure de voir par-dessus. Donc oui.
Justin
1
Je ne connais pas la mécanique quantique, mais la chauve-souris et la momie gnome pourraient être une affaire facile. Le mimique pourrait cependant compliquer les choses. De plus, ces trois fourmis peuvent être amusantes et le grand groupe de monstres assortis du nord-est peut déjà vous connaître. Ouais ... ça pourrait être méchant. Quant à # 3 - où est mon rouleau de téléporation? Oups, c'était détruire l'armure.
John Dvorak
3
Juste une observation curieuse, mais si je comprends bien votre définition de "ligne", il semble qu'il y ait des carrés qui ne seront pas visibles même sans aucun obstacle. Par exemple, si le joueur est à (0, 0), alors le carré à (5, 12) ne peut être atteint par aucune ligne. Il aurait peut-être été plus logique, par exemple, de spécifier une implémentation canonique de l'algorithme de ligne de Bresenham pour tracer une ligne entre deux points quelconques et de définir un carré comme obscurci si la ligne entre lui et le joueur intersecte un obstacle.
Ilmari Karonen du
1
@IlmariKaronen Vous avez absolument raison. C'est comme ça que je l'aime. :-).
Justin

Réponses:

5

GolfScript, 171 caractères

.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'entrée doit être fournie sur STDIN.

La sortie des exemples donnés ci-dessus est légèrement différente. J'ai vérifié les réponses à la main et je pense qu'elles sont correctes.

Exemple 1:

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

Exemple 2:

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

Exemple 3:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   
Howard
la source
Cela ne semble pas fonctionner pour les entrées sur une seule ligne (qui sont des rectangles valides ...)
Justin
@Quincunx Le code suppose que vous finalisez votre entrée avec une nouvelle ligne. Vous pouvez également ajouter n+le code au début .
Howard
4

Rubis - 510 caractères

Tout à fait un mammouth; mais c'est ma première tentative de 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'entrée se fait par fichier spécifié comme argument; Je suppose que le fichier d'entrée se compose d'un bloc rectangulaire de caractères (donc, espaces de fin inclus) et d'un retour à la ligne de fin.

Cette version fait un usage intensif de catch-throwpour quitter les boucles profondes; Je peux éventuellement améliorer les choses avec des boucles vérifiées à la place.

Code non obscurci:

# 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

Éditer

Ilmari Karonen note dans les commentaires de la question que l'algorithme de vision donné ne voit pas tous les carrés, même lorsqu'il n'y a pas d'obstacle. Voici une démonstration de cela, à (40,40) loin du lecteur.

@.......................................
........................................
........................................
........................................
........................................
............ ...........................
..............  ........................
............ ...   ..... ...............
.............. ...    .....  ...........
...............  ...     .....   .......
.................  ...      .....    ...
..................   ...       .....
..... . ............   ...        .....
.....................    ...         ...
...... . ..............    ...
...... .. ..............     ...
....... . ................     ...
....... .. ............. ..      ...
.......  .  .................      ...
........ .. ............... ..       ...
........  .  ............... ...       .
........  ..  ................ ..
.........  .  ................. ...
.........  ..  .................  ..
....... .   .   . ................ ...
..........  ..  ...................  ..
..........   .   ...................  ..
........ .   ..   . ..................
........ ..   .   .. ..................
...........   ..   .....................
......... .    .    . ..................
......... ..   ..   .. .................
......... ..    .    .. ................
.......... .    ..    . ................
.......... ..    .    .. ...............
.......... ..    ..    .. ..............
..........  .     .     .  .............
........... ..    ..    .. .............
........... ..     .     .. ............
...........  .     ..     .  ...........
Chowlett
la source
Hmm. Cela échoue au test 3. Nécessite un débogage.
Chowlett
êtes-vous sûr? J'aurais pu faire une erreur ...
Justin
Je suis sûr que je peux voir le V derrière le mur! Je pense que je ne détecte pas la nouvelle ligne après la ligne précédente.
Chowlett
Ne devrait certainement pas voir ça ...
Justin
Ah, c'était un problème avec mon entrée; J'ai eu un espace supplémentaire après XqQ. Cela dit, votre réponse donnée pour 3 ne correspond pas du tout au cas de test - elle a au moins une ligne supplémentaire en haut et un seul espace entre le Oet l.
Chowlett