Laser Party Party Portal

27

Plansza 2D będzie zawierać następujące obiekty:

  • ^, >, v, Lub <: Laser emiter skierowaną do góry, w prawo, w dół, w lewo lub odpowiednio. Może być ich więcej niż jeden. Lasery będą podróżować w linii prostej w pustej przestrzeni (pusta przestrzeń jest reprezentowana kropką .). Lasery nie przechodzą przez emitery.
  • *: Cel. Lasery przechodzą przez cele. Może być ich więcej niż jeden.

Plansza może również zawierać następujące obiekty:

  • @: Solidna ściana. Laser nie przejdzie tutaj.
  • \: Reflektor pochylony w lewo . Zmienia kierunek laserów zgodnie z następującą tabelą:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Left
    Right                             Down
    Down                              Right
    Left                              Up
    

    Powinno być dość intuicyjne w działaniu reflektorów. Wyobraźcie sobie je jako rzeczywiste dwustronne lustro, a wskazówki powinny być jasne.

  • /: Prawy reflektor. Zmienia kierunek laserów zgodnie z następującą tabelą:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 1, 2, 3... 9: a portal . Liczba wskazuje kanał portalu - będą dokładnie dwa portale tego samego kanału (na przykład nie będzie trzech 1). Portal zmienia pozycję laserów na pozycję innego portalu tego samego kanału. Na przykład:

    >     1     @     1     *
    

    Laser uderzy w cel, ponieważ gdy trafi pierwszy 1, zostaje teleportowany do drugiego 1po drugiej stronie. Lasery zachowują ten sam kierunek, w którym były wcześniej.

    Portal nie teleportuje lasera do portalu innego kanału (tzn. 1Nie teleportuje lasera do 9.

Twój program otrzyma dwuwymiarową reprezentację tablicy jako dane wejściowe. Tablica zawsze będzie miała prostokątny kształt. Wynik powinien być taki, Trueże wszystkie cele mają lasery przechodzące przez nie, lub w Falseinny sposób.

Oto kilka przypadków testowych:

  1. Wkład

    >....\
    ..*...
    >./../
    ..*...
    

    Wydajność

    True
    
  2. Wkład

    >..........\
    1........../
    2..........1
    3..........2
    4..........3
    5..........4
    6..........5
    7..........6
    8..........7
    9..........8
    *..........9
    

    Wydajność

    True
    
  3. Wkład

    >.@............*
    >..@...........*
    >...@..........*
    >....@.........*
    >.....@........*
    >...*..@........
    >.......@......*
    

    Wydajność

    False
    
  4. Wkład

    ../\.
    >./**
    

    Wydajność

    False
    
  5. Wkład

    /.......*.......\/3.....
    @..............//\.\....
    *.............2\.1\/\...
    \..............///.....<
    .........*...//\\/.....\
    >.............\.1.///.4.
    4.......*/...\2\/3/\/..^
    

    Wydajność

    True
    
  6. Wkład

    vvvvvvvvvvvvvvvvv
    \\\\\\\\\\\\\\\\\
    /////////////////
    \\\\\\\\\\\\\\\\\
    /////////////////
    \\\\\\\\\\\\\\\\\
    /////////////////
    *****************
    

    Wyjście (zwróć uwagę na cel po prawej stronie)

    False
    
Absynt
źródło
Czy nie byłoby bardziej sensowne, gdyby prawy reflektor (/) zmienił kierunek wiązki laserowej z lewej (←) na dół (↓)?
piskliwy ossifrage
@squeamish ossifrage Przepraszam, nie rozumiem twojego pytania. Która reguła odbicie na lewo pochylony tabeli reflektora sądzisz jest błędna?
absynt
Myślę, że pomyliłeś się z prawą i lewą stroną
piskliwy ossifrage
1
Co się stanie, jeśli laser osiągnie granicę siatki?
DavidG
2
@DavidG Nic, albo odbija się tak, jak przyszedł. (W tym przypadku są one równoważne). Nie „zawija się”, jak widać z przykładu 6.
Dennis Jaheruddin

Odpowiedzi:

8

Pyton, 310 302 287 278 277 260

Nie różni się radykalnie od istniejącego postu w Pythonie, ale myślę, że ma jedną lub dwie godne uwagi sztuczki. Obsługuje również dane wejściowe „nieterminujące”, takie jak 1>1. EDYCJA : Ups! emitery blokują lasery.

def t(b):
 w=len(b[0])+1;B=list('@'*w+'@'.join(b));i=l=len(B);C="<>^v@"
 while i:
    j=l-i;i-=1;d=C.find(B[j]);c='.'
    while c not in C:
     if'+'>c:B[j]='.'
     if'0'<c<C:j=(B*2).index(c,j+1)%l
     elif'.'<c:d^=2+(c<C)
     j-=[1,-1,w,-w,j][d];c=B[j%l]
 return'*'not in B

t pobiera listę ciągów (wiersze wejściowe) i zwraca wynik logiczny.

Oto fajny gif kodowania gry w golfa:

wprowadź opis zdjęcia tutaj

EDYCJA : Niesamowity gif dzięki uprzejmości Willa. Dzięki Will!

Łokieć
źródło
Specyfikacja określa, że „Lasery nie przechodzą przez emitery”. tak 1>1się skończy. Nie udało mi się znaleźć czegoś, co się nie kończy, ale nie włożyłem w to wiele wysiłku i prawie zakładałem, że tak się nie stanie z moją implementacją. Oczywiście ponownie zastanowię się, czy ktoś może go przedstawić.
VisualMelon,
4
@VisualMelon: Reguły są symetryczne czasowo, z wyjątkiem miejsc, w których lasery rodzą się lub giną, co oznacza, że ​​wszystko musi się skończyć (ponieważ zawsze możesz jednoznacznie prześledzić go z powrotem do momentu, w którym się urodził, a emitery same nie mogą być częścią pętli).
Micheasza
@ Michee hehe, dzięki za właściwe wyjaśnienie, tak jak powiedziałem, że poszedłem z intuicją i nie martwiłem się tym zbytnio, dzięki za włożenie innego narzędzia do mojego pudełka.
VisualMelon,
Tak, źle to odczytałem.
Ell
Czapki z głów przed Ellem! Bardzo ładnie wykonane. Myślę, że możesz ogolić jeszcze kilka bajtów, korzystając z faktu, że .find(d)zwraca -1, jeśli nie zostanie znalezione. Jeśli usuniesz if-1<d:instrukcję i zamiast tego zrobisz j+=[-1,1,w,-w,-i][d]na górze pętli while, nie znaleziono -1 zmieni się w dodanie ostatniego elementu w tej tablicy j, co spowoduje j0, o którym wiemy, że jest @...?
Czy
7

Perl, 647

To jest moja pierwsza próba gry w golfa kodowego i jestem trochę zawstydzona, że ​​nawet nie pobiłam wyniku C #, ale pomyślałam, że byłoby to interesujące (lub zabawne lub po prostu masochistyczne), aby zrobić to wszystko jako seria podstawień wyrażeń regularnych. (Pomyślałem również, że fajnie byłoby odświeżyć mój Perl, ale pod koniec głęboko żałowałem, że nie wdrożyłem go w Ruby ani Python).

Nie przeprowadziłem wielu testów, ale myślę, że powinno poradzić sobie z każdą sprawą.

Siatka jest wprowadzana przez STDIN. Na wejściu musi znajdować się co najmniej jedna nowa linia (tzn. Pojedynczy wiersz bez nowej linii nie będzie działać).

%s=(d,'[|+#$vk%ZX]',u,'[|+#$^W%KX]',r,'[-G+#>k%KX]',l,'[-G+#<W%ZX]');%o=(d,'[-.*G/k\\\\Z',u,'[-.*G/W\\\\K',r,'[|.*$\\\\/kK',l,'[|.*$\\\\/ZW');for$d(d,u,r,l){$o{$d}.='123456789qwertyuio]'}%u=(d,'.|-+*$G#/Wk%\KZX',u,'.|-+*$G#/kW%\ZKX',r,'.-|+*G$#/Wk%\ZKX',l,'.-|+*G$#/kW%\KZX');@q=split//,"qwertyuio";local$/;$_=<STDIN>;for$i(1..9){$m{$i}=$q[$i-1];$m{$m{$i}}=$i;s/$i/$m{$i}/e}/.*?\n/;$l='.'x((length$&)-1);do{$c=0;for$d(d,u,r,l){%p=(d,"(?<=$s{d}$l)$o{d}",u,"$o{u}(?=$l$s{u})",r,"(?<=$s{r})$o{r}",l,"$o{l}(?=$s{l})");%h=split//,$u{$d};$c+=s!$p{$d}!$h{$&}||($v=$&,($o{$d}=~s/$v// && $s{$d}=~s/]/$m{$v}]/),$v)!es}}while($c);print/\*/?"False\n":"True\n"

Objaśnienie: kod iteracyjnie aktualizuje ciąg siatki, gdy lasery przez niego przechodzą. -przedstawia poziomy laser, |pionowy laser, +skrzyżowane laserów Kdo \lustra za pomocą lasera odbijając się od górnej, kjak /lustro za pomocą lasera odbija się od dna, Zna \zwierciadło laserem odbijając się od dołu i Wz /lustra z laserem odbijając szczyt. %jest /lustrem z laserami po obu stronach, podczas gdy Xjest \lustrem z laserami po obu stronach. (Rozróżniana jest wielkość liter. Próbowałem wybrać litery, które wyglądają nieco odpowiednio - na przykład kiKsą dość oczywistymi wyborami - ale niestety efekt naprawdę nie jest taki pomocny. Powinienem naprawdę umieścić te informacje w tabeli, ale jestem teraz wyczerpany).

Obsługa portali w ten sam sposób (tj. Przypisanie każdej cyfrze zestawu dodatkowych znaków na podstawie możliwych pozycji lasera wejściowego / wyjściowego) wymagałaby 144 znaków (w tym oryginalnej 9), więc zamiast tego, gdy laser uderzy w portal „wejściowy”, Dodam znak portalu „wyjściowy” do zestawu znaków, które emitują laser we właściwym kierunku. (Wymaga to rozróżnienia między portalami wejściowymi i wyjściowymi; użyłem qwertyuiodo tego liter .)

Nieco golfa, z drukowanymi instrukcjami, dzięki czemu można zobaczyć, że zachodzą podstawienia (każde zastąpienie reprezentuje jedną „rundę” postępu laserowego), a gflaga jest dodana do głównej, s///aby nie wymagała tylu iteracji:

# Throughout, d,u,r,l represents lasers going down, up, left, or right
# `sources` are the character classes representing laser "sources" (i.e. any
# character that can, on the next round, cause a laser to enter the space
# immediately adjacent to it in the proper direction)
%sources=(d,'[|+#$vk%ZX]',u,'[|+#$^W%KX]',r,'[-G+#>k%KX]',l,'[-G+#<W%ZX]');
# `open` characters will not block a laser
%open=(d,'[-.*G/k\\\\Z',u,'[-.*G/W\\\\K',r,'[|.*$\\\\/kK',l,'[|.*$\\\\/ZW');
# One of each portal is changed into the corresponding letter in `qwertyuio`.
# At the start, each portal is 'open' and none of them is a source.
for$d(d,u,r,l){$open{$d}.='123456789qwertyuio]'}
# A mapping of 'open' characters to the characters they become when a laser
# goes through them. (This is used like a hash of hashes; see the assignment
# of `%h` below.)
%update=(d,'.|-+*$G#/Wk%\KZX',
    u,'.|-+*$G#/kW%\ZKX',
    r,'.-|+*G$#/Wk%\ZKX',
    l,'.-|+*G$#/kW%\KZX');
@q=split//,"qwertyuio";
local$/;$_=<STDIN>;
for$i(1..9){
    $m{$i}=$q[$i-1];
    $m{$m{$i}}=$i;
    s/$i/$m{$i}/e}
print "After substituting portals:\n";
print;
print "\n";
# Find the number of characters in each line and create a string of `.`'s,
# which will be used to correlate characters above/below one another in the
# grid with each other.
/.*?\n/;
$l='.'x((length$&)-1);
do{
    $changes=0;
    for$d(d,u,r,l){
        # `patterns` is a mapping from each direction to the regex representing
        # an update that must occur (i.e. a place where a laser must progress).
        # Each pattern is either a lookahead or lookbehind plus the necessary
        # "open" character class.
        %patterns=(d,"(?<=$sources{d}$l)$open{d}",
            u,"$open{u}(?=$l$sources{u})",
            r,"(?<=$sources{r})$open{r}",
            l,"$open{l}(?=$sources{l})");
        %h=split//,$update{$d};
        # Match against the pattern for each direction. Note whether any
        # matches were found.
        $changes+=s!$patterns{$d}!
            # If the "open" character for a map is in the `update` map, return
            # the corresponding value. Otherwise, the "open" character is a
            # portal.
            $h{$&} || ($v=$&,
                        # For portals, remove the input portal from the
                        # proper "open" list and add the output portal to
                        # the proper "source" list.
                       ($open{$d}=~s/$v// && $sources{$d}=~s/]/$m{$v}]/),
                       $v)
                    # This whole substitution should allow `.` to match
                    # newlines (see the definition of `$l` above), and the
                    # replacement must be an expression rather than a string
                    # to facilitate the portal logic. The `g` allows multiple
                    # updates per "frame"; it is left out of the golfed code.
                    !egs
    }
    # Print the next "frame".
    print;
    print "\n";
# Continue updating until no "open" spaces are found.
}while($changes);
# Print whether `*` is still present in the input.
print/\*/?"False\n":"True\n"
Kyle Strand
źródło
Eksperymentowałem z tego rodzaju podejściem (używając tablic bool zamiast wyrażeń regularnych) w Pythonie, ale nie mogłem zbliżyć się do tego małego. Myślę, że to bardzo prowokujące do myślenia podejście! Na moje próby błędnie wpłynął catpad.net/michael/apl z dobrym vid youtube.com/watch?v=a9xAKttWgP4 i petercollingridge.co.uk/blog/python-game-of-life-in-one-line
Będzie
1
@Will Thanks! Zdecydowanie zdałem sobie sprawę z tego, jak podobne były moje wysiłki w stosunku do GoL w czasie, gdy doszedłem do wniosku, jak wykonalne byłoby użycie innej postaci dla każdej możliwej kombinacji laserów wchodzących i wychodzących z portalu. Myślę, że mógłbym być w stanie zgolić jeszcze kilka postaci, ale ... to zdecydowanie nie jest optymalne podejście!
Kyle Strand
Ponadto, jeśli ktoś zna lepszy sposób radzenia sobie z potrójnymi znakami ucieczki w klasach postaci w pierwszych kilku wierszach, byłoby to urocze ...
Kyle Strand
6

Python 338 351

def t(b):
 L=len;w=L(b[0])+3;b=list("@"*w+"@@".join(b)+"@"*w);w-=1;I=b.index
 for i in range(L(b)):
  c=b[i];d={"^":-w,"<":-1,">":1,"v":w}.get(c)
  if d:
   while c!='@':
    i+=d;c=b[i]
    if c=='*':b[i]='.'
    elif c in '/\\':d={-w:-1,w:1,1:w,-1:-w}[d]*(-1 if c=='/' else 1)
    elif c>'0':i+=I(c)-i or I(c,i+1)-i
 return "*" not in b

Moja niezminimalizowana wersja faktycznie kreśli ścieżki lasera na planszy, co jest ładne:

>-+--\
..X..|
>-/--/
..X...

>----------\
1----------/
2----------1
3----------2
4----------3
5----------4
6----------5
7----------6
8----------7
9----------8
X----------9

>-@............*
>--@...........*
>---@..........*
>----@.........*
>-----@........*
>---X--@........
>-------@......*

/-------X+------\/3.....
@........|.....//\+\....
X........|....2\+1\/\...
\--------+----+///+++--<
.........X...//\\/+++--\
>--------+---+\+1+///-4|
4-------X/...\2\/3/\/..^

vvvvvvvvvvvvvvvvv
\\\\\\\\\\\\\\\\\
/////////////////
\\\\\\\\\\\\\\\\\
/////////////////
\\\\\\\\\\\\\\\\\
/////////////////
XXXXXXXXXXXXXXXX*

def debug(board,x,y):
    emit_dir = {
        "^":    ( 0, -1),
        "<":    (-1,  0),
        ">":    ( 1,  0),
        "v":    ( 0,  1),
    }
    class PortalException(Exception): pass
    xdir, ydir = emit_dir[board[y][x]]
    while True:
        # print "step (%d, %d) (%d, %d)" % (x, y, xdir, ydir)
        x += xdir
        y += ydir
        if y < 0 or y >= len(board) or x < 0 or x >= len(board[y]):
            return
        ch = board[y][x]
        if ch == '/':
            xdir, ydir = -ydir, -xdir
        elif ch == '\\':
            xdir, ydir = ydir, xdir
        elif ch in '@^><v':
            return
        elif ch == '*':
            board[y] = board[y][:x] + 'X' + board[y][x+1:]
        elif ch in '.-|':
            ch = ('-' if xdir else '|') if ch == '.' else '+'
            board[y] = board[y][:x] + ch + board[y][x+1:]
        elif ch in '123456789':
            try:
                for r in range(len(board)):
                    for c in range(len(board[r])):
                        if board[r][c] == ch and (r != y or c != x):
                            x, y = c, r
                            raise PortalException()
                raise Exception("could not find portal %s (%d,%d)" % (ch, x, y))
            except PortalException:
                pass
Wola
źródło
5

C # - 515 414 400 bajtów

Kompletny program w języku C #, bez ładnych wyników takich jak Will. Działa poprzez podążanie ścieżką lasera dla każdego emitowanego osobno i utrzymywanie szeregu komórek, które odwiedziliśmy, abyśmy mogli sprawdzić, czy odwiedziliśmy wszystkie gwiazdy na końcu. Edycja: rozłożył dużą liczbę bajtów, robiąc wszystko 1D i używając znaku zamiast int do przechowywania bieżącego znaku

w0lf przypomniał mi, że miałem niedostatecznie wykorzystaną pętlę for w samym środku mojego kodu, więc pomyślałem, że powinienem zrobić ostatni wysiłek i uruchomić to, a teraz sprowadzam się do absolutnej minimalnej liczby kręconych szelki Nie będę udawał, że podoba mi się zwinięcie drugiej pętli for, kod jest teraz strasznie nieuporządkowany, ale zaoszczędził kilka bajtów. W trakcie tego procesu ponownie napisałem obsługę portalu. Znalazłem również krótszą metodę wykonywania „przenoszenia” za pomocą zagnieżdżonej, a nie zagregowanej operacji warunkowej.

Kod do gry w golfa:

using C=System.Console;class P{static void Main(){var S=C.In.ReadToEnd().Replace("\r","");int W=S.IndexOf('\n')+1,l=S.Length,i=l,d,m,n;var M=new int[l];for(char c;i-->0;)for(d="^<v>".IndexOf(c=S[m=i]);c>14&d>-1;d=(m+=d==2?W:d>0?d-2:-W)>=0&m<l&&"@^<v>".IndexOf(c=S[m])<0?d:-1)for(d=c==47?3-d:c==92?d^1:d,M[n=m]=1;c%49<9&&(m=S.IndexOf(c,m+1))==n|m<0;);for(;l-->0;)W*=S[l]==42?M[l]:1;C.WriteLine(W>0);}}

Kod mniej golfowy:

using C=System.Console;

class P
{
    static void Main()
    {
        var S=C.In.ReadToEnd().Replace("\r",""); // read the grid, remove pesky carriage returns
        int W=S.IndexOf('\n')+1,l=S.Length,i=l,d,m,n; // find "width"
        var M=new int[l]; // defaults to 0s

        for(char c;i-->0;) // for each cell

            for(d="^<v>".IndexOf(c=S[m=i]); // find initial direction, if any
                c>14&d>-1; // loop only if we have direction
                d=(m+=d==2?W:d>0?d-2:-W) // move (after iteration)
                >=0&m<l&&"@^<v>".IndexOf(c=S[m])<0?d:-1) // terminate if we hit something or go off edge

                for(d=c==47?3-d:c==92?d^1:d, // mirrors
                    M[n=m]=1; // we have seen this spot
                    c%49<9&&(m=S.IndexOf(c,m+1))==n|m<0;); // portals

        for(;l-->0;) // for each cell
            W*=S[l]==42?M[l]:1; // if *, then mul by whether seen

        C.WriteLine(W>0);
    }
}

Nowy kod obsługi portalu wykorzystuje fakt, że funkcja String.IndexOf szczęśliwie zwraca -1 (tzn. Nie znaleziono znaku), jeśli poprosisz, aby zaczął szukać 1 znaku poza ciągiem (zgłasza wyjątek, jeśli poprosisz, aby zaczął dalej). To była dla mnie nowość, ale w tym przypadku była okropnie wygodna.

VisualMelon
źródło
+1 Niesamowite gra w golfa! Pomyślałem o trick: można wziąć m+=(d>0?d-2:0)+(d<3?d-1:0)*W;i wpakować go w fornastępujący sposób: for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W). W ten sposób uratujesz jeden znak, ponieważ stracisz średnik.
Cristian Lupascu,
@ w0lf podjął ostatni wysiłek i udało się całkowicie zwinąć pętle for, dzięki za szturchanie;)
VisualMelon