Zapal Roguelike

14

Biorąc pod uwagę tablicę, napisz najkrótszy program lub funkcję, aby wyświetlić lub zwrócić, które postacie są w zasięgu wzroku gracza. Postać jest widoczna, jeśli możliwe jest narysowanie linii między nią a graczem, bez przekraczania postaci blokujących widzenie.

Wejście:

  • @reprezentuje pozycję gracza. Na wejściu będzie tylko jeden z nich.
  • dowolna postać pasująca do wyrażenia [#A-Z]blokującego wyrażenia regularne .
  • dowolna dopasowana postać [ a-z]pozwala na widzenie.
  • nie będzie żadnych nieprawidłowych znaków
  • masz zagwarantowane prostokątne wejście

Linie są zdefiniowane w następujący sposób:

  • zdefiniuj wektor jako wielkość i kierunek
  • kierunek to jeden z N, NE, E, SE, S, SW, W, NW
  • wielkość to liczba znaków w tym kierunku do zliczenia
  • niech wektor początkowy nazywa się d 1 ; drugi wektor nazywa się d 2
  • jeden z d 1 lub d 2 musi mieć wielkość 1; drugi może mieć dowolną wielkość
  • kierunek d 1 musi przylegać do kierunku d 2 (np .: N i NE)

Linia jest zdefiniowana jako wszystkie znaki na ścieżce oznaczone przez zastosowanie d 1 , a następnie d 2 , d 1 , d 2 ....

Linia próbki (podana przez .s):
d 1 = (wielkość: 4, kierunek: E)
d 2 = (wielkość: 1, kierunek NE)

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

Wynik:

  • każda widoczna postać na właściwej pozycji .zastępuje spację.
  • Miejsce na każdą niewidoczną postać.

Przykładowe dane wejściowe:

@         
    K     
 J        

    L   




         o

Odpowiednia wydajność:

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

Przykładowe dane wejściowe:

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

Odpowiadające wyniki:

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

Przykładowe dane wejściowe:

  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        

Odpowiednia wydajność:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   
Justin
źródło
3
OK ... nietoperze, wszelkiego rodzaju grzyby, pleśnie i węże, a nawet upiory blokują pole widzenia, ale gigantyczne mimiki, orki na wzgórzach, mastodony, wszelkiego rodzaju inne stworzenia, a nawet wiry ognia nie?
John Dvorak
@JanDvorak Byłem leniwy i wybrałem wielkie litery do blokowania. Coś w rodzaju TALL potworów kontra potworów krótkich; co byś mógł zobaczyć. Więc tak.
Justin
1
Nie wiem o mechanice kwantowej, ale mumia nietoperza i gnoma może być łatwym zadaniem. Mimika może jednak jeszcze bardziej skomplikować sprawę. Te trzy mrówki mogą być zabawne, a duża grupa różnorodnych potworów na północnym wschodzie może już o tobie wiedzieć. Tak ... to może być paskudne. Co do nr 3 - gdzie jest mój zwój teleporacji? Ups, to było zniszczenie zbroi.
John Dvorak
3
Ciekawa obserwacja, ale jeśli dobrze rozumiem twoją definicję „linii”, wygląda na to, że istnieją kwadraty, które nie będą widoczne nawet bez przeszkód. Na przykład, jeśli gracz ma wartość (0, 0), to do kwadratu przy (5, 12) nie można dotrzeć żadną linią. Mogłoby być bardziej sensowne, powiedzmy, określenie kanonicznej implementacji algorytmu linii Bresenhama do rysowania linii między dowolnymi dwoma punktami i zdefiniowanie kwadratu jako zaciemnionego, jeśli linia między nim a graczem przecina przeszkodę.
Ilmari Karonen
1
@IlmariKaronen Masz absolutną rację. Właśnie tak to lubię. :-).
Justin

Odpowiedzi:

5

GolfScript, 171 znaków

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

Dane wejściowe należy podać na STDIN.

Wynik dla powyższych przykładów jest nieco inny. Zweryfikowałem odpowiedzi ręcznie i uważam, że są poprawne.

Przykład 1:

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

Przykład 2:

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

Przykład 3:

   ..........  .....
    ......... ..... 
     O..l...gg..rT  
...QQL......Ag..#b..
...qqqqq.........XqQ
        #.f@aa......
   Y........aaa.....
...uU..E..l.TaKK....
      d..FF.d.op    
     .... .d. ...   
Howard
źródło
Wydaje się, że to nie działa w przypadku danych wejściowych z pojedynczą linią (które są poprawnymi prostokątami ...)
Justin
@Quincunx Kod zakłada, że ​​zakończysz wprowadzanie nowego wiersza. Alternatywnie dodaj n+do kodu.
Howard
4

Rubin - 510 znaków

Całkiem mamut; ale to moja pierwsza próba gry w golfa.

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

Dane wejściowe są przez plik określony jako argument; Zakładam, że plik wejściowy składa się z prostokąta bloku znaków (więc wraz z końcowymi spacjami) i ma końcowy znak nowej linii.

Ta wersja szeroko wykorzystuje catch-throwwyjście z głębokich pętli; Zamiast tego mogę ewentualnie poprawić sprawy za pomocą pętli sprawdzonych pod kątem granic.

Kod nieobjawiony:

# 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

Edytować

Ilmari Karonen zauważa w komentarzu, że dany algorytm widzenia nie widzi wszystkich kwadratów, nawet gdy nie ma przeszkody. Oto demonstracja tego, w odległości do (40,40) od gracza.

@.......................................
........................................
........................................
........................................
........................................
............ ...........................
..............  ........................
............ ...   ..... ...............
.............. ...    .....  ...........
...............  ...     .....   .......
.................  ...      .....    ...
..................   ...       .....
..... . ............   ...        .....
.....................    ...         ...
...... . ..............    ...
...... .. ..............     ...
....... . ................     ...
....... .. ............. ..      ...
.......  .  .................      ...
........ .. ............... ..       ...
........  .  ............... ...       .
........  ..  ................ ..
.........  .  ................. ...
.........  ..  .................  ..
....... .   .   . ................ ...
..........  ..  ...................  ..
..........   .   ...................  ..
........ .   ..   . ..................
........ ..   .   .. ..................
...........   ..   .....................
......... .    .    . ..................
......... ..   ..   .. .................
......... ..    .    .. ................
.......... .    ..    . ................
.......... ..    .    .. ...............
.......... ..    ..    .. ..............
..........  .     .     .  .............
........... ..    ..    .. .............
........... ..     .     .. ............
...........  .     ..     .  ...........
Chowlett
źródło
Hmm To nie powiedzie się test 3. Wymaga debugowania.
Chowlett
Jesteś pewny? Mogłem się pomylić ...
Justin
Całkiem pewne - widzę V za ścianą! Myślę, że nie wykrywam nowej linii po poprzedniej linii.
Chowlett
Zdecydowanie nie powinienem tego widzieć ...
Justin
Ach, to był problem z moim wkładem; Po tym miałem dodatkowe miejsce XqQ. To powiedziawszy, twoja odpowiedź dla 3 w ogóle nie odpowiada testowi - ma przynajmniej dodatkową linię u góry i tylko jedną spację między Oa l.
Chowlett