Đảng Gương Laser


27

Một bảng 2D sẽ chứa các đối tượng sau:

  • ^, >, v, Hay <: Một tia laser phát hướng lên, phải, xuống, sang trái hoặc tương ứng. Có thể có nhiều hơn một. Laser sẽ đi theo một đường thẳng trong không gian trống (không gian trống được biểu thị bằng một dấu chấm .). Laser không đi qua bộ phát.
  • *: Mục tiêu. Laser đi qua mục tiêu. Có thể có nhiều hơn một.

Bảng cũng có thể chứa các đối tượng sau:

  • @: Một bức tường vững chắc. Các tia laser sẽ không đi qua đây.
  • \: Một phản xạ nghiêng trái . Thay đổi hướng của laser theo bảng sau:

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

    Nó sẽ khá trực quan như cách các phản xạ làm việc. Chỉ cần tưởng tượng chúng như một tấm gương hai mặt thực tế và các hướng phải rõ ràng.

  • /: Một phản xạ nghiêng phải . Thay đổi hướng của laser theo bảng sau:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 1, 2, 3... 9: Một cổng thông tin . Con số biểu thị kênh của cổng thông tin - sẽ có chính xác hai cổng của cùng một kênh (ví dụ: sẽ không có ba cổng 1). Cổng thông tin thay đổi vị trí của laser thành vị trí của cổng thông tin khác của cùng một kênh. Ví dụ:

    >     1     @     1     *
    

    Tia laser sẽ bắn trúng mục tiêu vì khi nó chạm vào cái đầu tiên 1, nó bị dịch chuyển sang cái thứ hai 1ở phía bên kia. Laser giữ nguyên hướng tương tự như trước đây.

    Một cổng thông tin sẽ không dịch chuyển tia laser đến một cổng của một kênh khác (tức là 1sẽ không dịch chuyển tia laser đến a 9.

Chương trình của bạn sẽ nhận được một đại diện 2D của bảng làm đầu vào. Bảng sẽ luôn có hình chữ nhật. Đầu ra phải là Truenếu tất cả các mục tiêu có laser đi qua chúng, hoặc Falsenếu không.

Dưới đây là một số trường hợp thử nghiệm:

  1. Đầu vào

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

    Đầu ra

    True
    
  2. Đầu vào

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

    Đầu ra

    True
    
  3. Đầu vào

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

    Đầu ra

    False
    
  4. Đầu vào

    ../\.
    >./**
    

    Đầu ra

    False
    
  5. Đầu vào

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

    Đầu ra

    True
    
  6. Đầu vào

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

    Đầu ra (lưu ý mục tiêu ở ngoài cùng bên phải)

    False
    

Sẽ không có ý nghĩa hơn nếu một gương phản xạ nghiêng phải (/) thay đổi hướng của chùm tia laser từ trái (←) xuống (↓)?
squossish ossifrage

@squeamish ossifrage Tôi xin lỗi, tôi không hiểu câu hỏi của bạn. Đó phản ánh quy tắc trên bàn phản xạ nghiêng trái bạn có nghĩ là không chính xác?
absinthe

Tôi nghĩ rằng bạn đã trộn lẫn trái và phải
squossish ossifrage

1
Điều gì xảy ra nếu laser đạt đến ranh giới lưới?
DavidG

2
@DavidG Không có gì, hoặc nó bị trả lại theo cách nó đã đến. (Đây là tương đương trong trường hợp này). Nó không "quấn quanh" như có thể thấy từ ví dụ 6.
Dennis Jaheruddin

Câu trả lời:


8

Con trăn 310 302 287 278 277 260

Không hoàn toàn khác biệt so với bài viết Python hiện có, nhưng tôi có một hoặc hai thủ thuật đáng chú ý, tôi nghĩ vậy. Nó cũng xử lý đầu vào "không kết thúc", chẳng hạn như 1>1. EDIT : Rất tiếc! phát xạ khố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 lấy một danh sách các chuỗi (các dòng đầu vào) và trả về kết quả boolean.

Đây là một gif đẹp của mã đang được chơi xuống:

nhập mô tả hình ảnh ở đây

EDIT : Gif lịch sự tuyệt vời của Will. Cảm ơn sẽ!


Thông số kỹ thuật xác định rằng "Laser không đi qua bộ phát." như vậy 1>1sẽ chấm dứt. Tôi đã không thể tìm thấy thứ gì đó không chấm dứt, mặc dù tôi đã không nỗ lực nhiều vào nó và gần như cho rằng nó không xảy ra cho việc thực hiện của tôi. Tôi tất nhiên sẽ xem xét lại nếu ai đó có thể trình bày một.
VisualMelon

4
@VisualMelon: Các quy tắc là đối xứng thời gian ngoại trừ tại các điểm mà tia laser được sinh ra hoặc chết đi, điều đó có nghĩa là mọi thứ phải chấm dứt (vì bạn luôn có thể theo dõi nó một cách duy nhất trở lại điểm mà nó được sinh ra và bản thân chúng không thể là một phần của một vòng lặp).
Mi-chê

@Micah hehe, cảm ơn vì một lời giải thích phù hợp, như tôi đã nói tôi đã đi bằng trực giác và không lo lắng về điều đó nhiều, cảm ơn vì đã đặt một công cụ khác vào hộp của tôi.
VisualMelon

Yup, tôi đọc nhầm.
Ell

Ngả mũ với Ell! Hoàn thành rất tốt. Tôi nghĩ rằng bạn có thể cạo thêm một vài byte bằng cách sử dụng thực tế .find(d)trả về -1 nếu không tìm thấy. Nếu bạn loại bỏ if-1<d:câu lệnh và thay vào đó thực hiện j+=[-1,1,w,-w,-i][d]ở đầu vòng lặp while, -1 không tìm thấy sẽ biến thành phần tử cuối cùng trong mảng jđó, sẽ tạo thành j0, mà chúng ta biết là @...?
Sẽ

7

Perl, 647

Đây là lần thử đầu tiên của tôi ở môn đánh gôn, và tôi hơi xấu hổ, tôi thậm chí không đánh bại điểm C #, nhưng tôi nghĩ sẽ rất thú vị (hoặc vui, hoặc chỉ là bạo dâm) để làm toàn bộ điều này như một loạt thay thế regex. (Tôi cũng nghĩ sẽ rất vui khi đánh lên Perl của mình, nhưng cuối cùng tôi đã rất hối hận vì đã không thực hiện nó trong Ruby hoặc Python.)

Tôi đã không thực hiện nhiều thử nghiệm, nhưng tôi nghĩ nó nên xử lý mọi trường hợp.

Lưới được nhập thông qua STDIN. Phải có ít nhất một dòng mới trong đầu vào (nghĩa là một hàng không có dòng mới sẽ không hoạt động).

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

Giải thích: mã lặp lại cập nhật chuỗi lưới khi các laser đi qua nó. -đại diện cho một tia laser nằm ngang, |một tia laser thẳng đứng, +tia laser chéo, Kmột \chiếc gương với tia laser bật ra khỏi đỉnh, kmột /chiếc gương với tia laser bật ra khỏi đáy, Zmột \chiếc gương có tia laser bật ra khỏi đáy và Wmột /chiếc gương bị tia laser bật ra đỉnh. %là một /tấm gương với laser ở cả hai bên, trong khi Xlà một \tấm gương với laser ở cả hai bên. (Đây là những trường hợp nhạy cảm. Tôi đã cố gắng chọn các chữ cái có vẻ phù hợp - ví dụ, kKlà một số lựa chọn rõ ràng - nhưng thật không may, hiệu quả thực sự không hữu ích. Tôi thực sự nên đặt thông tin này vào một bảng, nhưng tôi đã kiệt sức ngay bây giờ.)

Xử lý các cổng theo cùng một cách (nghĩa là gán cho mỗi chữ số một bộ ký tự phụ dựa trên các vị trí laser đầu vào / đầu ra có thể) sẽ cần 144 ký tự (bao gồm cả 9 gốc), do đó, khi laser chạm vào cổng "đầu vào", Tôi thêm ký tự cổng thông tin "đầu ra" vào tập hợp các ký tự phát ra tia laser theo hướng thích hợp. (Điều này không yêu cầu phân biệt giữa cổng đầu vào và đầu ra; Tôi đã sử dụng các chữ cái qwertyuiocho việc này.)

Một phần nào đó không được đánh gôn, với các câu lệnh in để bạn có thể thấy sự thay thế xảy ra (mỗi lần thay thế đại diện cho một "vòng" tiến trình laser) và với gcờ được thêm vào chính s///để nó không mất quá nhiều lần lặp:

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

Tôi đã thử nghiệm cách tiếp cận này (sử dụng mảng bool chứ không phải regex) trong Python nhưng không thể đến gần với cái nhỏ này. Tôi nghĩ rằng đây là một cách tiếp cận thực sự kích thích tư duy! Những nỗ lực của tôi đã bị ảnh hưởng bởi catpad.net/michael/apl với vid youtube.com/watch?v=a9xAKttWgP4petercollingridge.co.uk/blog/python-game-of-life-in-one-line
Sẽ

1
@ Sẽ cảm ơn! Tôi chắc chắn đã nhận ra những nỗ lực của mình tương tự như thế nào với GoL trong khoảng thời gian tôi tìm ra cách khả thi khi sử dụng một ký tự khác nhau cho mỗi tổ hợp laser có thể đi vào và ra khỏi cổng. Tôi nghĩ rằng tôi có thể loại bỏ một vài nhân vật nữa, nhưng ... đây rõ ràng không phải là cách tiếp cận tối ưu!
Kyle Strand

Ngoài ra, nếu có ai biết cách tốt hơn để xử lý các `` thoát 'ba trong các lớp nhân vật trong vài dòng đầu tiên, điều đó sẽ rất đáng yêu ...
Kyle Strand

6

Con trăn 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

Phiên bản chưa hoàn thành của tôi thực sự vẽ các đường dẫn laser trên bảng, khá đẹp:

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

Hoàn thành chương trình C #, không có đầu ra đẹp như Will's. Hoạt động bằng cách đi theo đường dẫn laser cho từng phát riêng lẻ và giữ một mảng các ô mà chúng tôi đã truy cập, để chúng tôi có thể kiểm tra xem cuối cùng chúng tôi đã truy cập tất cả các ngôi sao chưa. Chỉnh sửa: sọc một số lượng lớn byte bằng cách tạo mọi thứ 1D và bằng cách sử dụng char thay vì int để lưu trữ char hiện tại

w0lf nhắc nhở tôi rằng tôi đã sử dụng một vòng lặp for được sử dụng ngay giữa mã của mình, vì vậy tôi nghĩ rằng tôi nên thực hiện một nỗ lực cuối cùng và đưa nó vào hoạt động, và bây giờ tôi đang xuống đến số lượng xoăn tối thiểu tuyệt đối niềng răng. Tôi sẽ không giả vờ thích sự sụp đổ của vòng lặp thứ hai, mã bây giờ bị rối loạn khủng khiếp, nhưng nó đã lưu một vài byte. Trong quá trình tôi viết lại việc xử lý cổng thông tin. Tôi cũng tìm thấy một phương pháp ngắn hơn để thực hiện "di chuyển" với hoạt động có điều kiện lồng nhau thay vì tổng hợp.

Mã đánh gôn:

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

Mã golf ít hơn:

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

Mã xử lý cổng thông tin mới sử dụng thực tế là hàm String.IndexOf vui vẻ trả về -1 (tức là không tìm thấy char) nếu bạn yêu cầu nó bắt đầu tìm kiếm 1 ký tự ngoài chuỗi (ném ngoại lệ nếu bạn yêu cầu nó bắt đầu xa hơn nữa). Đây là tin tức với tôi, nhưng rất thuận tiện trong trường hợp này.


+1 chơi golf tuyệt vời! Tôi chỉ nghĩ về một mẹo: bạn có thể lấy m+=(d>0?d-2:0)+(d<3?d-1:0)*W;và đẩy nó vào for, như thế này : for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W). Bằng cách này, bạn sẽ lưu được một char, vì bạn sẽ mất dấu chấm phẩy.
Cristian Lupascu

@ w0lf đã thực hiện một nỗ lực cuối cùng và quản lý để thu gọn hoàn toàn các vòng lặp, cảm ơn vì sự
nũng nịu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.