Partai Portal Cermin Laser

27

Papan 2D akan berisi objek-objek berikut:

  • ^, >, v, Atau <: Sebuah laser emitor menghadap ke atas, kanan, bawah, atau kiri masing-masing. Mungkin ada lebih dari satu. Laser akan bergerak dalam garis lurus di ruang kosong (ruang kosong diwakili dengan titik .). Laser tidak melewati penghasil emisi.
  • *: Sebuah target. Laser melewati target. Mungkin ada lebih dari satu.

Papan juga dapat berisi benda-benda berikut:

  • @: Dinding yang kokoh. Laser tidak akan lewat sini.
  • \: Reflektor yang condong ke kiri . Mengubah arah laser berdasarkan tabel berikut:

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

    Seharusnya cukup intuitif bagaimana cara kerja reflektor. Bayangkan saja mereka sebagai cermin dua sisi yang sebenarnya dan arahnya harus jelas.

  • /: Reflektor yang condong ke kanan . Mengubah arah laser berdasarkan tabel berikut:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 1, 2, 3... 9: A Portal . Angka tersebut menunjukkan saluran portal - akan ada tepat dua portal dari saluran yang sama (misalnya, tidak akan ada tiga portal 1). Portal mengubah posisi laser ke posisi portal lain dari saluran yang sama. Contohnya:

    >     1     @     1     *
    

    Laser akan mengenai target karena ketika mengenai yang pertama 1, ia akan dipindahkan ke yang kedua 1di sisi yang lain. Laser mempertahankan arah yang sama seperti sebelumnya.

    Sebuah portal tidak akan memindahkan laser ke portal dari saluran yang berbeda (yaitu 1tidak akan memindahkan laser ke 9.

Program Anda akan menerima representasi 2D papan sebagai masukan. Papan akan selalu berbentuk persegi panjang. Outputnya harus Truejika semua target memiliki laser yang melewatinya, atau Falsesebaliknya.

Berikut ini beberapa kasus uji:

  1. Memasukkan

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

    Keluaran

    True
    
  2. Memasukkan

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

    Keluaran

    True
    
  3. Memasukkan

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

    Keluaran

    False
    
  4. Memasukkan

    ../\.
    >./**
    

    Keluaran

    False
    
  5. Memasukkan

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

    Keluaran

    True
    
  6. Memasukkan

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

    Keluaran (catat target di paling kanan)

    False
    
Absinth
sumber
Bukankah lebih masuk akal jika reflektor yang condong ke kanan (/) mengubah arah sinar laser dari kiri (←) ke bawah (↓)?
squeamish ossifrage
@squeamish ossifrage Maaf, saya tidak mengerti pertanyaan Anda. Refleksi yang aturan di meja reflektor kiri bersandar menurut Anda tidak benar?
absinthe
Saya pikir Anda kiri dan kanan campur aduk
osifrage mual
1
Apa yang terjadi jika laser mencapai batas grid?
DavidG
2
@ David G Tidak ada, atau memantul kembali seperti itu. (Ini setara dalam kasus ini). Itu tidak 'membungkus' seperti yang dapat dilihat dari contoh 6.
Dennis Jaheruddin

Jawaban:

8

Python, 310 302 287 278 277 260

Tidak secara radikal berbeda dari posting Python yang ada, tetapi memiliki satu atau dua trik yang perlu diperhatikan, saya pikir. Ini juga menangani input "non-terminating", seperti 1>1. EDIT : Ups! emitor memblokir 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 mengambil daftar string (jalur input) dan mengembalikan hasil boolean.

Berikut adalah gif yang bagus dari kode yang sedang di-golf:

masukkan deskripsi gambar di sini

EDIT : Awsome atas izin Will. Will, terima kasih!

Elo
sumber
Spesifikasi menentukan bahwa "Laser tidak melewati penghasil emisi." jadi 1>1akan berakhir. Saya belum dapat menemukan sesuatu yang tidak berakhir, meskipun saya belum berusaha keras dan menganggap itu tidak terjadi untuk implementasi saya. Tentu saja saya akan mempertimbangkan kembali jika seseorang dapat menyajikannya.
VisualMelon
4
@VisualMelon: Peraturannya simetris waktu kecuali di tempat di mana laser dilahirkan atau mati, yang berarti semuanya harus berakhir (karena Anda selalu dapat melacaknya secara unik kembali ke titik kelahirannya, dan penghasil emisi tidak dapat dengan sendirinya menjadi bagian dari satu loop).
Micah
@Micah hehe, terima kasih untuk penjelasan yang tepat, seperti saya katakan saya pergi dengan intuisi dan tidak terlalu mengkhawatirkannya, terima kasih telah meletakkan alat lain di kotak saya.
VisualMelon
Yup, saya salah baca.
Ell
Angkat topi untuk Ell! Dilakukan dengan sangat baik. Saya pikir Anda dapat mencukur beberapa byte lagi dengan menggunakan fakta yang .find(d)mengembalikan -1 jika tidak ditemukan. Jika Anda menghapus if-1<d:pernyataan dan alih-alih melakukannya j+=[-1,1,w,-w,-i][d]di bagian atas loop sementara, -1 yang tidak ditemukan akan berubah menjadi menambahkan elemen terakhir dalam array ke j, yang akan menghasilkan j0, yang kita tahu adalah @...?
Will
7

Perl, 647

Ini adalah upaya pertama saya di kode-golf, dan saya agak malu saya bahkan tidak mengalahkan skor C #, tapi saya pikir itu akan menarik (atau menyenangkan, atau hanya masokis) untuk melakukan semuanya sebagai serangkaian penggantian regex. (Saya juga berpikir akan menyenangkan untuk memoles Perl saya, tetapi pada akhirnya saya sangat menyesal tidak menerapkannya dalam Ruby atau Python.)

Saya belum melakukan banyak pengujian, tetapi saya pikir itu harus menangani setiap kasus.

Grid adalah input melalui STDIN. Harus ada setidaknya satu baris baru di input (yaitu satu baris tanpa baris baru tidak akan berfungsi).

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

Penjelasan: kode secara iteratif memperbarui string grid ketika laser melewatinya. -merupakan laser horisontal, |laser vertikal, +laser menyeberang, Ksebuah \cermin dengan laser memantul dari atas, ksebuah /cermin dengan laser memantul dari bawah, Zsebuah \cermin dengan laser memantul dari bagian bawah, dan Wsebuah /cermin dengan laser memantul atas. %adalah /cermin dengan laser di kedua sisi, sementara Xadalah \cermin dengan laser di kedua sisi. (Ini peka huruf besar-kecil. Saya mencoba mengambil huruf yang terlihat agak sesuai - misalnya, kdanKadalah pilihan yang agak jelas - tetapi sayangnya efeknya sebenarnya tidak terlalu membantu. Saya benar-benar harus memasukkan info ini ke dalam tabel, tapi saya kelelahan sekarang.)

Menangani portal dengan cara yang sama (yaitu menetapkan setiap digit satu set karakter tambahan berdasarkan kemungkinan posisi input / output laser) akan membutuhkan 144 karakter (termasuk yang asli 9), jadi sebagai gantinya, ketika laser menyentuh portal "input", Saya menambahkan "output" karakter portal ke set karakter yang memancarkan laser ke arah yang tepat. (Ini memang membutuhkan membedakan antara portal input dan output; saya menggunakan huruf qwertyuiountuk ini.)

Agak un-golf, dengan pernyataan cetak sehingga Anda dapat melihat substitusi terjadi (setiap substitusi mewakili satu "putaran" perkembangan laser), dan dengan gbendera ditambahkan ke utama s///sehingga tidak mengambil begitu banyak iterasi:

# 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
sumber
Saya bereksperimen dengan pendekatan semacam ini (menggunakan array bool daripada regex) dengan Python tetapi tidak bisa mendekati yang kecil ini. Saya pikir ini pendekatan yang benar-benar membangkitkan semangat! Upaya saya salah dipengaruhi oleh catpad.net/michael/apl dengan vid bagus youtube.com/watch?v=a9xAKttWgP4 dan petercollingridge.co.uk/blog/python-game-of-life-in-one-one-line
Will
1
@ Akan terima kasih! Saya benar-benar menyadari betapa miripnya usaha saya dengan GoL di sekitar waktu saya bekerja betapa layaknya menggunakan karakter yang berbeda untuk setiap kemungkinan kombinasi laser yang masuk dan keluar dari portal. Saya pikir saya mungkin bisa mengurangi beberapa karakter lagi, tapi ... ini jelas bukan pendekatan yang optimal!
Kyle Strand
Juga, jika ada yang tahu cara yang lebih baik untuk menangani `triple-escaped` dalam kelas karakter di beberapa baris pertama, itu akan menyenangkan ...
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

Versi saya yang tidak dijinakkan sebenarnya memplot jalur laser di papan, yang cukup:

>-+--\
..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
Akan
sumber
5

C # - 515 414 400 byte

Selesaikan program C #, tidak ada output yang bagus seperti Will. Bekerja dengan mengikuti jalur laser untuk masing-masing yang dipancarkan secara terpisah, dan menyimpan susunan sel mana yang telah kami kunjungi, sehingga kami dapat memeriksa bahwa kami telah mengunjungi semua bintang pada akhirnya. Sunting: melucuti sejumlah besar byte dengan membuat semuanya 1D dan dengan menggunakan char bukannya int untuk menyimpan karakter saat ini

w0lf mengingatkan saya bahwa saya memiliki loop di bawah dimanfaatkan tepat di tengah-tengah kode saya, jadi saya pikir saya lebih baik membuat satu upaya terakhir dan membuatnya bekerja, dan sekarang saya ke jumlah minimum mutlak keriting kawat gigi. Saya tidak akan berpura-pura menyukai runtuhnya yang kedua untuk loop, kodenya mengerikan sekarang, tetapi menyimpan beberapa byte. Dalam prosesnya saya menulis ulang penanganan portal. Saya juga menemukan metode yang lebih pendek untuk melakukan "langkah" dengan bersarang daripada operasi bersyarat agregat.

Kode golf:

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

Lebih sedikit kode 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);
    }
}

Kode penanganan portal baru menggunakan fakta bahwa fungsi String.IndexOf dengan senang hati mengembalikan -1 (yaitu char tidak ditemukan) jika Anda memintanya mulai mencari 1 karakter di luar string (melempar pengecualian jika Anda memintanya untuk memulai lebih jauh di luar). Ini adalah berita bagi saya, tetapi sangat nyaman dalam hal ini.

VisualMelon
sumber
+1 bermain golf Luar Biasa! Aku hanya berpikir dari trik: Anda bisa mengambil m+=(d>0?d-2:0)+(d<3?d-1:0)*W;dan mendorong dalam for, seperti ini: for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W). Dengan cara ini, Anda akan menghemat satu char, karena Anda akan kehilangan titik koma.
Cristian Lupascu
@ w0lf melakukan upaya terakhir dan berhasil menutup loop untuk sepenuhnya, terima kasih atas dorongan;)
VisualMelon