Laserspiegelportal-Party

27

Ein 2D - Board werden die folgenden Objekte enthalten:

  • ^, >, v, Oder <: Ein Laserstrahler nach oben, rechts, unten bzw. links. Es kann mehr als einen geben. Laser bewegen sich im leeren Raum in einer geraden Linie (leerer Raum wird mit einem Punkt dargestellt .). Laser passieren keine Emitter.
  • *: Ein Ziel. Laser passieren Ziele. Es kann mehr als einen geben.

Die Tafel kann auch die folgenden Objekte enthalten:

  • @: Eine feste Wand. Der Laser wird hier nicht passieren.
  • \: Ein nach links geneigter Reflektor. Ändert die Richtung von Lasern gemäß der folgenden Tabelle:

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

    Es sollte ziemlich intuitiv sein, wie die Reflektoren funktionieren. Stellen Sie sie sich als einen echten zweiseitigen Spiegel vor und die Richtungen sollten klar sein.

  • /: Ein nach rechts geneigter Reflektor. Ändert die Richtung von Lasern gemäß der folgenden Tabelle:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 1, 2, 3... 9: Ein Portal . Die Nummer gibt den Kanal des Portals an - es gibt genau zwei Portale desselben Kanals (zum Beispiel gibt es keine drei 1). Das Portal ändert die Position des Lasers in die Position des anderen Portals desselben Kanals. Zum Beispiel:

    >     1     @     1     *
    

    Der Laser trifft das Ziel, denn wenn er das erste trifft 1, wird er zum zweiten 1auf der anderen Seite teleportiert . Laser behalten die gleiche Richtung bei, in der sie vorher waren.

    Ein Portal teleportiert den Laser nicht zu einem Portal eines anderen Kanals (dh a 1teleportiert den Laser nicht zu a 9.

Ihr Programm erhält eine 2D-Darstellung der Karte als Eingabe. Die Tafel wird immer rechteckig sein. Die Ausgabe sollte erfolgen, Truewenn alle Ziele von Lasern durchlaufen werden, oder auf Falseandere Weise.

Hier sind einige Testfälle:

  1. Eingang

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

    Ausgabe

    True
    
  2. Eingang

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

    Ausgabe

    True
    
  3. Eingang

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

    Ausgabe

    False
    
  4. Eingang

    ../\.
    >./**
    

    Ausgabe

    False
    
  5. Eingang

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

    Ausgabe

    True
    
  6. Eingang

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

    Ausgabe (beachten Sie das Ziel ganz rechts)

    False
    
Absinth
quelle
Wäre es nicht sinnvoller, wenn ein nach rechts geneigter Reflektor (/) die Richtung eines Laserstrahls von links (←) nach unten (↓) ändert?
Squeamish Ossifrage
@squeamish ossifrage Es tut mir leid, ich verstehe deine Frage nicht. Welche Reflexion Regel auf der linken Seite gelehnt Reflektor Tisch denken Sie , ist falsch?
Absinth
Ich denke, Sie haben links und rechts verwechselt
zimperliche Ossifrage
1
Was passiert, wenn der Laser die Gittergrenze erreicht?
DavidG
2
@DavidG Nichts, oder es springt so zurück, wie es gekommen ist. (Diese sind in diesem Fall gleichwertig). Wie aus Beispiel 6 hervorgeht, wird es nicht
umgangen

Antworten:

8

Python, 310 302 287 278 277 260

Nicht radikal anders als der existierende Python-Post, hat aber ein oder zwei bemerkenswerte Tricks, denke ich. Es verarbeitet auch "nicht terminierende" Eingaben, wie z 1>1. EDIT : Ups! Emitter blockieren Laser.

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 Nimmt eine Liste von Strings (die Eingabezeilen) und gibt ein boolesches Ergebnis zurück.

Hier ist ein nettes GIF des Codes, der abgespielt wird:

Bildbeschreibung hier eingeben

EDIT : Awsome GIF mit freundlicher Genehmigung von Will. Vielen Dank, Will!

Ell
quelle
Die Spezifikation gibt an, dass "Laser nicht durch Emitter laufen". so 1>1wird beendet. Ich war nicht in der Lage, etwas zu finden, das nicht terminiert, obwohl ich nicht viel Mühe darauf verwendet habe und so gut wie angenommen habe, dass es bei meiner Implementierung nicht passiert. Ich werde natürlich überlegen, ob jemand einen vorlegen kann.
VisualMelon
4
@VisualMelon: Die Regeln sind zeitlich symmetrisch, außer an Orten, an denen Laser geboren werden oder sterben. Dies bedeutet, dass alles enden muss (da Sie es immer eindeutig bis zu dem Punkt zurückverfolgen können, an dem es geboren wurde, und Emitter selbst nicht Teil sein können einer Schleife).
Micah,
@Micah hehe, danke für die richtige Erklärung, wie ich schon sagte, ich bin intuitiv und mache mir keine großen Sorgen, danke, dass ich ein anderes Werkzeug in meine Schachtel gesteckt habe.
VisualMelon
Ja, ich habe es falsch gelesen.
Ell
Hut ab vor Ell! Sehr schön gemacht. Ich denke, Sie können ein paar Bytes mehr sparen, indem Sie die Tatsache verwenden, dass .find(d)-1 zurückgegeben wird, wenn es nicht gefunden wird. Wenn Sie die if-1<d:Anweisung entfernen und stattdessen j+=[-1,1,w,-w,-i][d]am oberen Rand der while-Schleife ausführen, wird aus einem nicht gefundenen -1 das letzte Element in diesem Array hinzugefügt j, zu dem j0 wird, von dem wir wissen, dass es @... ist.
Wird
7

Perl, 647

Dies ist mein erster Versuch, Code-Golf zu spielen, und es ist mir ein bisschen peinlich, dass ich nicht einmal den C # Score geschlagen habe, aber ich dachte, es wäre interessant (oder lustig oder einfach nur masochistisch), das Ganze als zu tun Serie von Regex-Substitutionen. (Ich dachte auch, es würde Spaß machen, mein Perl aufzufrischen, aber am Ende bereute ich zutiefst, es nicht in Ruby oder Python implementiert zu haben.)

Ich habe nicht viel getestet, aber ich denke, es sollte jeden Fall behandeln.

Das Gitter wird über STDIN eingegeben. Die Eingabe muss mindestens eine neue Zeile enthalten (dh eine einzelne Zeile ohne neue Zeile funktioniert nicht).

%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"

Erläuterung: Der Code aktualisiert die Rasterzeichenfolge iterativ, wenn die Laser sie durchlaufen. -stellt einen horizontalen Laser, |einen vertikalen Laser, +gekreuzte Laser, Keinen \Spiegel mit einem Laser, der von der Oberseite abprallt, keinen /Spiegel mit einem Laser, der von der Unterseite abprallt, Zeinen \Spiegel mit einem Laser, der von der Unterseite abprallt, und Weinen /Spiegel mit einem Laser, der von der Unterseite abprallt, dar die Spitze. %ist ein /Spiegel mit Lasern auf beiden Seiten, während Xein \Spiegel mit Lasern auf beiden Seiten ist. (Hierbei wird zwischen Groß - und Kleinschreibung unterschieden. Ich habe versucht, Buchstaben auszuwählen, die angemessen aussehen, z. B. kundKsind etwas offensichtliche Entscheidungen - aber leider ist der Effekt wirklich nicht so hilfreich. Ich sollte diese Informationen wirklich in eine Tabelle aufnehmen, aber ich bin im Moment erschöpft.)

Die gleiche Behandlung von Portalen (dh die Zuweisung eines zusätzlichen Zeichensatzes für jede Ziffer basierend auf den möglichen Eingabe- / Ausgabe-Laserpositionen) würde 144 Zeichen erfordern (einschließlich der ursprünglichen 9). Wenn also ein Laser auf ein "Eingabe" -Portal trifft, Ich füge das "Ausgabe" -Portalzeichen zu der Gruppe von Zeichen hinzu, die einen Laser in die richtige Richtung aussenden. (Dies erfordert eine Unterscheidung zwischen Eingabe- und Ausgabeportalen. Ich habe die Buchstaben qwertyuiodafür verwendet.)

Etwas unerfreulich, mit Print-Anweisungen, damit Sie sehen können, wie die Substitutionen ablaufen (jede Substitution stellt eine "Runde" der Laser-Progression dar), und mit dem gFlag, das zum Main hinzugefügt wurde, s///damit es nicht so viele Iterationen dauert:

# 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
quelle
Ich habe in Python mit dieser Art von Ansatz experimentiert (mit Bool-Arrays statt Regex), konnte aber nicht annähernd so klein werden. Ich halte das für einen wirklich nachdenklichen Ansatz! Meine Versuche wurden fälschlicherweise von catpad.net/michael/apl mit netten Videos beeinflusst. Youtube.com/watch?v=a9xAKttWgP4 und petercollingridge.co.uk/blog/python-game-of-life-in-one-line
Will
1
@Will Dankeschön! Ich erkannte definitiv, wie ähnlich meine Bemühungen zu GoL waren, als ich herausfand, wie machbar es wäre, für jede mögliche Kombination von Lasern, die in ein Portal hinein- und aus ihm herausgehen, einen anderen Charakter zu verwenden. Ich glaube, ich kann vielleicht noch ein paar Charaktere abschneiden, aber ... das ist eindeutig nicht der optimale Ansatz!
Kyle Strand
Auch wenn jemand einen besseren Weg kennt, um mit den dreifach geflohenen `` 'in den Zeichenklassen in den ersten paar Zeilen
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

Meine ungekürzte Version zeichnet tatsächlich die Laserpfade auf der Platine, was hübsch ist:

>-+--\
..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
Wille
quelle
5

C # - 515 414 400 Bytes

Komplettes C # -Programm, keine nette Ausgabe wie bei Will. Verfolgen Sie den Laserpfad für jede Emission einzeln und behalten Sie eine Reihe der Zellen bei, die wir besucht haben, damit wir überprüfen können, ob wir alle Sterne am Ende besucht haben. Bearbeiten: Striping einer großen Anzahl von Bytes, indem alles zu 1D gemacht wird und ein Zeichen anstelle eines Int zum Speichern des aktuellen Zeichens verwendet wird

w0lf erinnerte mich daran, dass ich mitten in meinem Code eine unterausgenutzte for-Schleife hatte, also dachte ich mir, ich sollte mich ein letztes Mal anstrengen und sie zum Laufen bringen, und jetzt bin ich auf das absolute Minimum an lockigen Hosenträger. Ich werde nicht so tun, als würde es mir gefallen, wenn die zweite for-Schleife zusammenbricht. Der Code ist jetzt schrecklich ungeordnet, hat aber ein paar Bytes gespart. Dabei habe ich das Portalhandling umgeschrieben. Ich habe auch eine kürzere Methode gefunden, um den "Move" mit verschachtelten statt aggregierten bedingten Operationen durchzuführen.

Golf Code:

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);}}

Weniger Golf Code:

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);
    }
}

Der neue Code für die Portalbehandlung nutzt die Tatsache, dass die Funktion String.IndexOf glücklich -1 (dh Zeichen nicht gefunden) zurückgibt, wenn Sie gefragt werden, ob 1 Zeichen hinter der Zeichenfolge gesucht werden soll. Das war eine Neuigkeit für mich, war aber in diesem Fall furchtbar praktisch.

VisualMelon
quelle
+1 Geniales Golfen! Ich dachte nur von einem Trick: Sie das nehmen konnte m+=(d>0?d-2:0)+(d<3?d-1:0)*W;und schieben es in die for, wie folgt aus : for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W). Auf diese Weise sparen Sie ein Zeichen, da Sie ein Semikolon verlieren.
Cristian Lupascu
@ w0lf machte einen letzten Versuch und schaffte es, die for-Schleifen vollständig zu
reduzieren