Festa del portale dello specchio laser


27

Bordo Un 2D sarà contenere i seguenti oggetti:

  • ^, >, v, O <: Un emettitore laser rivolto verso l'alto, destra, giù, sinistra o rispettivamente. Potrebbe essercene più di uno. I laser viaggeranno in linea retta nello spazio vuoto (lo spazio vuoto è rappresentato da un punto .). I laser non passano attraverso gli emettitori.
  • *: Un bersaglio. I laser passano attraverso gli obiettivi. Potrebbe essercene più di uno.

La scheda può contenere anche i seguenti oggetti:

  • @: Un muro solido. Il laser non passerà qui.
  • \: Un riflettore rivolto a sinistra . Cambia la direzione dei laser secondo la seguente tabella:

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

    Dovrebbe essere piuttosto intuitivo su come funzionano i riflettori. Immaginali come un vero specchio a due facce e le direzioni dovrebbero essere chiare.

  • /: Un riflettore orientato a destra . Cambia la direzione dei laser secondo la seguente tabella:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 1, 2, 3... 9: Un portale . Il numero indica il canale del portale: ci saranno esattamente due portali dello stesso canale (ad esempio, non ci saranno tre 1). Il portale cambia la posizione dei laser nella posizione dell'altro portale dello stesso canale. Per esempio:

    >     1     @     1     *
    

    Il laser colpirà il bersaglio perché quando colpisce il primo 1, viene teletrasportato al secondo 1dall'altra parte. I laser mantengono la stessa direzione in cui si trovavano prima.

    Un portale non teletrasporterà il laser su un portale di un altro canale (ovvero a 1non teletrasporterà il laser su a 9.

Il tuo programma riceverà una rappresentazione 2D della scheda come input. La tavola avrà sempre una forma rettangolare. L'output dovrebbe essere Truese tutti i target hanno laser che li attraversano, o Falsealtrimenti.

Ecco alcuni casi di test:

  1. Ingresso

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

    Produzione

    True
    
  2. Ingresso

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

    Produzione

    True
    
  3. Ingresso

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

    Produzione

    False
    
  4. Ingresso

    ../\.
    >./**
    

    Produzione

    False
    
  5. Ingresso

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

    Produzione

    True
    
  6. Ingresso

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

    Output (notare l'obiettivo all'estrema destra)

    False
    

Non avrebbe più senso se un riflettore inclinato a destra (/) cambi la direzione di un raggio laser da sinistra (←) a giù (↓)?
ossifrage schizzinoso,

@squeamish ossifrage Mi dispiace, non capisco la tua domanda. Quale regola riflessione sul appoggiato sinistra tavolo riflettore pensi che non è corretto?
assenzio

Penso che tu sia stato mescolato a destra e sinistra
ossifrage schizzinoso,

1
Cosa succede se il laser raggiunge il limite della griglia?
DavidG

2
@DavidG Niente, o rimbalza come è arrivato. (Questi sono equivalenti in questo caso). Non si "avvolge" come si può vedere dall'esempio 6.
Dennis Jaheruddin

Risposte:


8

Pitone, 310 302 287 278 277 260

Non radicalmente diverso dall'attuale post di Python, ma penso che abbia uno o due trucchi degni di nota. Gestisce anche input "non terminanti", come ad esempio 1>1. EDIT : Oops! gli emettitori bloccano i 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 prende un elenco di stringhe (le righe di input) e restituisce un risultato booleano.

Ecco una bella gif del codice in corso di golf:

inserisci qui la descrizione dell'immagine

EDIT : Awsome gif per gentile concessione di Will. Grazie Will!


La specifica specifica che "I laser non passano attraverso gli emettitori". così 1>1terminerà. Non sono stato in grado di trovare qualcosa che non si interrompe, anche se non ho fatto molti sforzi in questo e praticamente ho pensato che non accadesse per la mia implementazione. Naturalmente riconsidererò se qualcuno può presentarne uno.
VisualMelon,

4
@VisualMelon: le regole sono simmetriche nel tempo, tranne nei punti in cui i laser sono nati o muoiono, il che significa che tutto deve terminare (dal momento che è sempre possibile risalire in modo univoco al punto in cui è nato, e gli emettitori non possono essere essi stessi parte di un ciclo).
Michea,

@Micah hehe, grazie per una spiegazione adeguata, come ho detto che sono andato con intuizione e non me ne sono preoccupato molto, grazie per aver messo un altro strumento nella mia scatola.
VisualMelon,

Sì, l'ho letto male.
Ell

Tanto di cappello a Ell! Molto ben fatto. Penso che puoi radere qualche byte in più usando il fatto che .find(d)restituisce -1 se non trovato. Se rimuovi l' if-1<d:istruzione e invece lo fai j+=[-1,1,w,-w,-i][d]all'inizio del ciclo while, un -1 non trovato si trasformerà in aggiunta dell'ultimo elemento in quell'array j, che farà j0, che sappiamo che è @...?
Sarà il

7

Perl, 647

Questo è il mio primo tentativo in assoluto di code-golf, e sono un po 'imbarazzato di non aver nemmeno battuto il punteggio C #, ma ho pensato che sarebbe stato interessante (o divertente o semplicemente masochista) fare l'intera cosa come un serie di sostituzioni regex. (Ho anche pensato che sarebbe stato divertente ripassare il mio Perl, ma alla fine mi sono pentito profondamente di non averlo implementato in Ruby o Python.)

Non ho fatto molti test, ma penso che dovrebbe gestire tutti i casi.

La griglia viene immessa tramite STDIN. Ci deve essere almeno una nuova riga nell'input (cioè una singola riga senza una nuova riga non funzionerà).

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

Spiegazione: il codice aggiorna iterativamente la stringa della griglia mentre i laser la attraversano. -rappresenta un laser orizzontale, |un laser verticale, +laser incrociati, Kuno \specchio con un laser che rimbalza sulla parte superiore, kuno /specchio con un laser che rimbalza sul fondo, Zuno \specchio con un laser che rimbalza sul fondo e Wuno /specchio con un laser che rimbalza la cima. %è uno /specchio con laser su entrambi i lati, mentre Xè uno \specchio con laser su entrambi i lati. (Questi sono case sensitive. Ho provato a scegliere lettere che sembrano un po 'appropriate - per esempio, keKsono scelte piuttosto ovvie, ma purtroppo l'effetto non è poi così utile. Dovrei davvero mettere queste informazioni in un tavolo, ma sono sfinito in questo momento.)

Gestire i portali nello stesso modo (cioè assegnare ad ogni cifra un set di caratteri extra in base alle possibili posizioni laser di input / output) richiederebbe 144 caratteri (incluso l'originale 9), quindi, invece, quando un laser colpisce un portale "input", Aggiungo il carattere del portale "output" all'insieme di caratteri che emettono un laser nella direzione corretta. (Ciò richiede una differenziazione tra i portali di input e output; qwertyuioper questo ho usato le lettere .)

Un po 'non golfato, con dichiarazioni stampate in modo da poter vedere le sostituzioni in corso (ogni sostituzione rappresenta un "giro" di progressione laser) e con la gbandiera aggiunta alla principale in s///modo che non subisca così tante iterazioni:

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

Ho sperimentato questo tipo di approccio (usando array bool piuttosto che regex) in Python ma non sono riuscito ad avvicinarmi a questo piccolo. Penso che questo sia un approccio davvero stimolante! I miei tentativi sono stati influenzati in modo errato da catpad.net/michael/apl con il bel video youtube.com/watch?v=a9xAKttWgP4 e petercollingridge.co.uk/blog/python-game-of-life-in-one-line
Sarà il

1
@Will Thanks! Sicuramente mi sono reso conto di quanto fossero simili i miei sforzi a GoL nel tempo in cui ho capito quanto fosse fattibile usare un carattere diverso per ogni possibile combinazione di laser che entrava e usciva da un portale. Penso che potrei essere in grado di radere qualche altro personaggio, ma ... questo chiaramente non è l'approccio ottimale!
Kyle Strand,

Inoltre, se qualcuno conosce un modo migliore per gestire le `` 'triple escape' nelle classi di personaggi nelle prime righe, sarebbe adorabile ...
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

La mia versione non minimizzata in realtà traccia i percorsi laser sulla scheda, il che è carino:

>-+--\
..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

5

C # - 515 414 400 byte

Programma C # completo, nessun output piacevole come quello di Will. Funziona seguendo il percorso laser per ogni emissione individuale e mantenendo una matrice di quali celle abbiamo visitato, in modo da poter verificare che alla fine abbiamo visitato tutte le stelle. Modifica: esegue lo striping di un gran numero di byte rendendo tutto 1D e utilizzando un carattere anziché un int per memorizzare il carattere corrente

w0lf mi ha ricordato che avevo un for-loop poco utilizzato proprio nel mezzo del mio codice, quindi ho pensato che sarebbe meglio fare un ultimo sforzo e metterlo al lavoro, e ora sono arrivato al numero minimo assoluto di ricci bretelle. Non pretendo che mi piaccia il crollo del secondo per loop, il codice ora è terribilmente disordinato, ma ha risparmiato qualche byte. Nel processo ho riscritto la gestione del portale. Ho anche trovato un metodo più breve per eseguire lo "spostamento" con un'operazione condizionale nidificata anziché aggregata.

Codice golfizzato:

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

Meno codice golf:

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

Il nuovo codice di gestione del portale utilizza il fatto che la funzione String.IndexOf restituisce felicemente -1 (ovvero char non trovato) se gli chiedi di iniziare a cercare 1 carattere oltre la stringa (genera un'eccezione se chiedi di iniziare oltre). Questa era una novità per me, ma era terribilmente conveniente in questo caso.


+1 Golf fantastico! Ho solo pensato a un trucco: si può prendere l' m+=(d>0?d-2:0)+(d<3?d-1:0)*W;e spingerlo in for, in questo modo: for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W). In questo modo, salverai un carattere, perché perderai un punto e virgola.
Cristian Lupascu,

@ w0lf ha fatto un ultimo sforzo ed è riuscito a far crollare completamente i loop for, grazie per la
spinta
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.