Zünde einen Roguelike an

14

Schreiben Sie auf einer Tafel das kürzeste Programm oder die kürzeste Funktion, um anzuzeigen oder zurückzugeben, welche Zeichen für den Spieler sichtbar sind. Ein Charakter ist in Sicht, wenn es möglich ist, eine Linie zwischen ihm und dem Spieler zu ziehen, ohne dass Charaktere gekreuzt werden, die die Sicht beeinträchtigen.

Eingang:

  • @repräsentiert die Position des Spielers. In der Eingabe wird nur eine davon vorhanden sein.
  • Jedes Zeichen, das dem regulären Ausdruck entspricht, [#A-Z]blockiert die Sicht.
  • Jedes Zeichen, das passt, [ a-z]ermöglicht das Sehen.
  • Es gibt keine ungültigen Zeichen
  • Ihnen wird eine rechteckige Eingabe garantiert

Linien sind wie folgt definiert:

  • Definieren Sie den Vektor als Größe und Richtung
  • Eine Richtung ist eine von N, NE, E, SE, S, SW, W, NW
  • Eine Größe gibt an, wie viele Zeichen entlang dieser Richtung gezählt werden sollen
  • sei der Anfangsvektor d 1 ; der zweite Vektor heißt d 2
  • eines von d 1 oder d 2 muss eine Größe von haben 1; der andere kann eine beliebige Größe haben
  • Die Richtung von d 1 muss der Richtung von d 2 benachbart sein (z. B .: N und NE)

Eine Linie ist definiert als alle Zeichen entlang des Pfades, die durch Anwenden von d 1 , dann d 2 , d 1 , d 2 markiert sind ... .

Abtastzeile (gegeben durch das .s):
d 1 = (Betrag: 4, Richtung: E)
d 2 = (Betrag: 1, Richtung NE)

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

Ausgabe:

  • Jedes sichtbare Zeichen an der richtigen Position .ersetzt das Leerzeichen.
  • Platz für jedes nicht sichtbare Zeichen.

Beispieleingabe:

@         
    K     
 J        

    L   




         o

Entsprechende Ausgabe:

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

Beispiel Input:

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

Entsprechende Ausgabe:

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

Beispieleingabe:

  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        

Entsprechende Ausgabe:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   
Justin
quelle
3
OK ... Fledermäuse, alle Arten von Pilzen, Schimmelpilzen, Schlangen und sogar Gespenster blockieren die Sichtlinie, aber gigantische Mimiken, Bergorcs, Mastodons, alle möglichen anderen Kreaturen oder sogar Feuerwirbel nicht?
John Dvorak
@JanDvorak Ich war faul und habe Großbuchstaben zum Sperren gewählt. So ähnlich wie TALL-Monster gegen kleine Monster; welches würdest du sehen können. Also ja.
Justin
1
Ich kenne mich mit Quantenmechanik nicht aus, aber die Fledermaus und die Gnomenmumie könnten ein einfaches Geschäft sein. Die Nachahmung könnte die Sache jedoch noch komplizierter machen. Außerdem könnten diese drei Ameisen Spaß machen, und die große Gruppe von verschiedenen Monstern im Nordosten könnte bereits über Sie Bescheid wissen. Ja ... es könnte böse sein. Was # 3 betrifft - wo ist meine Teleporationsrolle? Ups, das war Rüstung zerstören.
John Dvorak
3
Nur eine merkwürdige Beobachtung, aber wenn ich Ihre Definition von "Linie" richtig verstehe, sieht es so aus, als gäbe es einige Quadrate, die auch ohne Hindernisse nicht sichtbar sind . Befindet sich der Spieler beispielsweise bei (0, 0), kann das Feld bei (5, 12) von keiner Linie erreicht werden. Es wäre vielleicht sinnvoller gewesen, beispielsweise eine kanonische Implementierung von Bresenhams Linienalgorithmus zum Zeichnen einer Linie zwischen zwei beliebigen Punkten anzugeben und ein Quadrat als verdeckt zu definieren, wenn die Linie zwischen ihm und dem Spieler ein Hindernis schneidet.
Ilmari Karonen
1
@IlmariKaronen Du bist absolut richtig. So mag ich es einfach. :-).
Justin

Antworten:

5

GolfScript, 171 Zeichen

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

Der Eingang muss auf STDIN bereitgestellt werden.

Die Ausgabe für die oben angegebenen Beispiele unterscheidet sich geringfügig. Ich habe die Antworten von Hand überprüft und denke, dass sie korrekt sind.

Beispiel 1:

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

Beispiel 2:

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

Beispiel 3:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   
Howard
quelle
Dies scheint nicht für einzeilige Eingänge (die gültige Rechtecke sind ...) zu funktionieren
Justin
@Quincunx Der Code setzt voraus, dass Sie Ihre Eingabe mit einem Zeilenumbruch abschließen. Alternativ können Sie n+den Code voranstellen .
Howard
4

Ruby - 510 Zeichen

Ziemlich ein Mammut; Aber es ist mein erster Versuch, Golf zu spielen.

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

Die Eingabe erfolgt über eine Datei, die als Argument angegeben wird. Ich gehe davon aus, dass die Eingabedatei aus einem rechteckigen Zeichenblock besteht (einschließlich nachfolgender Leerzeichen) und eine nachfolgende Newline enthält.

Diese Version macht ausgiebig Gebrauch catch-throw, um tiefe Schleifen zu verlassen; Möglicherweise kann ich die Sache stattdessen mit "bounds-checked" -Schleifen verbessern.

Freier Code:

# 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

Bearbeiten

Ilmari Karonen merkt in der Frage an, dass der gegebene Sichtalgorithmus nicht alle Quadrate sieht, auch wenn es kein Hindernis gibt. Hier ist eine Demonstration davon, um (40,40) vom Spieler entfernt.

@.......................................
........................................
........................................
........................................
........................................
............ ...........................
..............  ........................
............ ...   ..... ...............
.............. ...    .....  ...........
...............  ...     .....   .......
.................  ...      .....    ...
..................   ...       .....
..... . ............   ...        .....
.....................    ...         ...
...... . ..............    ...
...... .. ..............     ...
....... . ................     ...
....... .. ............. ..      ...
.......  .  .................      ...
........ .. ............... ..       ...
........  .  ............... ...       .
........  ..  ................ ..
.........  .  ................. ...
.........  ..  .................  ..
....... .   .   . ................ ...
..........  ..  ...................  ..
..........   .   ...................  ..
........ .   ..   . ..................
........ ..   .   .. ..................
...........   ..   .....................
......... .    .    . ..................
......... ..   ..   .. .................
......... ..    .    .. ................
.......... .    ..    . ................
.......... ..    .    .. ...............
.......... ..    ..    .. ..............
..........  .     .     .  .............
........... ..    ..    .. .............
........... ..     .     .. ............
...........  .     ..     .  ...........
Chowlett
quelle
Hmm. Dies schlägt Test 3 fehl. Erfordert ein Debugging.
Chowlett
bist du sicher? Ich hätte einen Fehler machen können ...
Justin
Ziemlich sicher - ich kann das V hinter der Wand sehen! Ich glaube, ich erkenne die neue Zeile nicht nach der vorherigen Zeile.
Chowlett
Das sollte man auf keinen Fall sehen ...
Justin
Ah, es war ein Problem mit meiner Eingabe; Ich hatte einen zusätzlichen Raum danach XqQ. Die angegebene Antwort für 3 stimmt jedoch überhaupt nicht mit dem Testfall überein. Sie enthält mindestens eine zusätzliche Zeile oben und nur ein Leerzeichen zwischen Ound l.
Chowlett