레이저 미러 포털 파티


27

2D 보드 에는 다음과 같은 객체 포함됩니다.

  • ^, >, v, 또는 <하십시오 레이저 위로 향하게 에미 오른쪽, 아래, 왼쪽 또는 각각. 둘 이상이있을 수 있습니다. 레이저는 빈 공간에서 직선으로 이동합니다 (빈 공간은 점으로 .표시됨). 레이저는 이미 터를 통과하지 않습니다.
  • *: 목표. 레이저 목표물을 통과합니다 . 둘 이상이있을 수 있습니다.

이 보드는 또한 다음과 같은 개체를 포함 :

  • @: 단단한 벽. 레이저는 여기를 통과하지 않습니다.
  • \: 왼쪽으로 기울어 진 반사판. 다음 표에 따라 레이저 방향을 변경합니다.

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

    반사경의 작동 방식에 대해 매우 직관적이어야합니다. 그것들을 실제 양면 거울이라고 생각하면 방향이 명확해야합니다.

  • /: 오른쪽으로 기대는 반사경. 다음 표에 따라 레이저 방향을 변경합니다.

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 1, 2, 3... 9, •의 포털 . 숫자는 포털의 채널을 나타냅니다. 동일한 채널의 포털이 정확히 2 개 있습니다 (예 : 3 개는 없음 1). 포털 은 레이저의 위치를 ​​동일한 채널의 다른 포털의 위치 로 변경합니다 . 예를 들어 :

    >     1     @     1     *
    

    레이저는 첫 번째에 맞았을 때 다른쪽에 1있는 두 번째로 순간 이동 되기 때문에 대상에 충돌합니다 1. 레이저는 이전과 같은 방향을 유지합니다.

    포털은 레이저를 다른 채널의 포털로 1순간 이동하지 않습니다 (예 : 레이저를 a로 순간 이동하지 않습니다) 9.

프로그램은 보드의 2D 표현을 입력으로받습니다. 보드는 항상 직사각형 모양입니다. True모든 대상에 레이저가 통과하거나 False그렇지 않으면 출력이 있어야합니다 .

다음은 몇 가지 테스트 사례입니다.

  1. 입력

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

    산출

    True
    
  2. 입력

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

    산출

    True
    
  3. 입력

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

    산출

    False
    
  4. 입력

    ../\.
    >./**
    

    산출

    False
    
  5. 입력

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

    산출

    True
    
  6. 입력

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

    출력 (가장 오른쪽에있는 대상에 유의)

    False
    

오른쪽 경사 반사기 (/)가 레이저 빔의 방향을 왼쪽 (←)에서 아래쪽 (↓)으로 변경 한 경우 더 의미가 없습니까?
squeamish ossifrage

@ squeamish ossifrage 죄송합니다. 귀하의 질문을 이해하지 못합니다. 당신이 생각하십니까 왼쪽 기대어 반사 테이블에 어떤 반사 규칙이 잘못인가?
압생트

나는 당신이 왼쪽과 오른쪽 섞여있어 생각
점잔 빼는 ossifrage

1
레이저가 그리드 경계에 도달하면 어떻게됩니까?
DavidG

2
@DavidG Nothing, 또는 그것이 돌아온 방식으로 되돌아옵니다. (이 경우에는 동일합니다). 예 6에서 볼 수 있듯이 그것은 '랩 어라운드'하지 않습니다
데니스 Jaheruddin을

답변:


8

파이썬, 310 302 287 278 277 260

기존 Python 게시물과 크게 다르지 않지만 주목할만한 트릭이 하나 있다고 생각합니다. 또한 "종료되지 않은"입력도 처리합니다 1>1. 편집 : 죄송합니다! 이미 터는 레이저를 차단합니다.

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 문자열 (입력 행) 목록을 가져 와서 부울 결과를 반환합니다.

다음은 코드가 다운되는 멋진 GIF입니다.

여기에 이미지 설명을 입력하십시오

편집 : Will의 굉장한 GIF 제공. 감사합니다 윌!


이 사양은 "레이저가 이미 터를 통과하지 못하도록 지정합니다 ." 그래서 1>1종료됩니다. 나는 많은 노력을 기울이지 않았고 그것이 구현에 일어나지 않는다고 가정했지만 끝내지 않는 것을 찾을 수 없었습니다. 누군가가 발표 할 수 있다면 물론 재고 할 것입니다.
VisualMelon

4
@VisualMelon : 규칙은 레이저가 태어나거나 죽는 지점을 제외하고는 시간 대칭 적입니다. 즉, 모든 것이 종료되어야 함을 의미합니다. 루프).
Micah

@Micah hehe, 적절한 설명을 해주신 것에 감사드립니다. 직관을 다룰 때 걱정하지 않아도되었으므로 다른 도구를 제 상자에 넣어 주셔서 감사합니다.
VisualMelon

예, 잘못 읽었습니다.
Ell September

Ell에게 모자! 아주 잘 했어요 .find(d)발견되지 않으면 -1 을 반환 하는 사실을 사용하여 몇 바이트를 더 줄일 수 있다고 생각합니다 . if-1<d:명령문 을 제거 하고 대신 j+=[-1,1,w,-w,-i][d]while 루프의 맨 위에서 수행 하면, 발견되지 않은 -1은 해당 배열 의 마지막 요소를에 추가하여 0 j을 만듭니다 . j@
Will

7

펄, 647

이것은 코드 골프에 대한 첫 번째 시도이며, 나는 C # 점수를 이길 수조차 없었지만 조금 당황 스럽지만 전체 작업을 일련의 정규식 대체. (또한 Perl을 정리하는 것이 재미있을 것이라고 생각했지만 결국 Ruby 또는 Python으로 구현하지 않는 것이 후회했습니다.)

나는 많은 테스트를 수행하지는 않았지만 모든 경우를 처리해야 한다고 생각 합니다.

그리드는 STDIN을 통해 입력됩니다. 입력에 적어도 하나의 줄 바꿈이 있어야합니다 (즉, 줄 바꿈이없는 단일 행은 작동하지 않음).

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

설명 : 코드는 레이저가 통과 할 때 그리드 문자열을 반복적으로 업데이트합니다. -수평 레이저 나타내는 |수직 레이저 +교차 레이저 레이저의 위쪽에서 반사 거울 레이저가 바닥에서 반사 거울 바닥 튀는 레이저로 미러 및 레이저 오프 튀는와 거울 상단. A는 동안, 양쪽 레이저 미러 A는 양면 거울은 레이저. . (이 내가 다소 적절한 모양 문자 선택하려고 대소 문자를 구분합니다 - 예를 들어를, 그리고K\k/Z\W/%/X\kK다소 명백한 선택이지만 불행히도 그 효과는 그다지 도움이되지 않습니다. 이 정보를 실제로 테이블에 넣어야하지만 지금은 지쳤습니다.)

동일한 방식으로 포털을 처리하는 경우 (즉, 가능한 입력 / 출력 레이저 위치에 따라 각 숫자에 추가 문자 세트를 할당하는 경우)에는 144 자 (원본 9 포함)가 필요합니다. 대신 레이저가 "입력"포털에 도달하면, "출력"포털 문자를 올바른 방향으로 레이저를 방출하는 문자 세트에 추가합니다. (이것은 입력 포털과 출력 포털을 구별해야 qwertyuio합니다.이 문자 를 사용했습니다.)

인쇄 문을 사용하여 다소 번거롭지 않아서 대체가 발생하는 것을 볼 수 있습니다 (각 대체는 레이저 진행의 "라운드"를 나타냄). 그리고 반복에 많은 반복이 걸리지 않도록 g메인에 플래그가 추가되었습니다 s///.

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

나는 파이썬에서 이런 종류의 접근법 (정규식 대신 bool 배열을 사용)을 실험했지만이 작은 근처에 도달 할 수 없었습니다. 나는 이것이 정말로 생각을 자극하는 접근법이라고 생각합니다! 내 시도는 catvid.net/michael/apl의 멋진 vid youtube.com/watch?v=a9xAKttWgP4petercollingridge.co.uk/blog/python-game-of-life-in-one-in-line

1
감사합니다! 나는 포털에 들어오고 나가는 레이저의 각 가능한 조합에 대해 다른 캐릭터를 사용하는 것이 얼마나 실현 가능한지를 알아낼 때 내 노력이 GoL과 얼마나 비슷한지를 분명히 깨달았습니다. 나는 더 많은 캐릭터를 면도 할 수 있다고 생각하지만 ... 이것은 분명히 최적의 접근법이 아닙니다!
Kyle Strand

또한, 누군가가 처음 몇 줄의 문자 클래스에서 트리플 이스케이프 처리 된``를 처리하는 더 좋은 방법을 알고 있다면, 그것은 사랑
Kyle Strand

6

파이썬 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

내 축소되지 않은 버전은 실제로 보드에 레이저 경로를 표시합니다.

>-+--\
..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 바이트

완전한 C # 프로그램, Will 's와 같은 좋은 결과는 없습니다. 개별적으로 방출되는 각각의 레이저 경로를 따라 방문하고 우리가 방문한 셀의 배열을 유지하여 끝에있는 모든 별을 방문했는지 확인할 수 있습니다. 편집 : 모든 것을 1D로 만들고 int 대신 char을 사용하여 현재 char을 저장하여 많은 바이트를 스트라이프했습니다.

w0lf는 내 코드 중간에 언더 활용도가 높은 for-loop가 있음을 상기 시켰으므로 마지막 노력을 기울이고 작동시키는 것이 더 좋을 것이라고 생각했습니다. 바지 멜빵. 나는 두 번째 for 루프가 무너지는 것을 좋아하지 않을 것입니다. 코드는 지금 끔찍하게 무질서하지만 몇 바이트를 절약했습니다. 이 과정에서 포털 처리를 다시 작성했습니다. 또한 집계 된 조건부 연산이 아니라 중첩 된 "이동"을 수행하는 더 짧은 방법을 찾았습니다.

골프 코드 :

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

덜 골프 코드 :

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

새로운 포털 처리 코드는 String.IndexOf 함수가 문자열 이상으로 1 문자를 찾기 시작하면 행복하게 -1 (즉, 문자를 찾을 수 없음)을 반환한다는 사실을 활용합니다 (더 이상 시작하도록 요청하면 예외가 발생 함). 이것은 나에게 뉴스 였지만이 경우 끔찍하게 편리했습니다.


+1 멋진 골프! 난 그냥 트릭 생각 : 당신이 걸릴 수 m+=(d>0?d-2:0)+(d<3?d-1:0)*W;와 그것을 밀어 for다음과 같이 : for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W). 이렇게하면 세미콜론을 잃기 때문에 하나의 문자를 저장하게됩니다.
Cristian Lupascu

@ w0lf는 마지막 노력을하고, 완전히 루프의 찔러 감사를 축소 관리)
VisualMelon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.