코드 골프 : 레이저


152

도전

문자별로 가장 짧은 코드는 보드의 2D 표현을 입력하고 입력에 따라 'true'또는 'false' 를 출력 합니다.

보드는 4 가지 유형의 타일로 구성됩니다.

 # - A solid wall
 x - The target the laser has to hit
 / or \ - Mirrors pointing to a direction (depends on laser direction)
 v, ^, > or < - The laser pointing to a direction (down, up, right and left respectively)

오직이 하나의 레이저하나 개의 목표 . 벽은 레이저와 대상이 내부에 배치되는 모든 크기의 단색 사각형을 형성해야합니다. '방'내부의 벽이 가능합니다.

레이저 광선은 원점에서 가리키는 방향으로 이동하여 이동합니다. 레이저 광선이 벽에 닿으면 정지합니다. 레이저 광선이 거울에 닿으면 거울이 가리키는 방향으로 90도 반사됩니다. 거울은 양면이므로 양면이 '반사'하며 광선이 두 가지 방식으로 반사 될 수 있습니다. 레이저 광선이 레이저 ( ^v><) 자체에 닿으면 벽으로 취급됩니다 (레이저 빔이 비머를 파괴하므로 절대로 대상에 닿지 않습니다).

테스트 사례

입력:
    ##########
    # / \ #
    # #
    # \ x #
    #> / #
    ########## 
산출:
    진실

입력:
    ##########
    # vx #
    # / #
    # / #
    # \ #
    ##########
산출:    
    그릇된

입력:
    #############
    # # #
    #> # #
    # # #
    # # x #
    # # #
    #############
산출:
    그릇된

입력:
    ##########
    # / \ / \ / \ #
    # \\ // \\\ #
    # // \ / \ / \\ #
    # \ / \ / \ / x ^ #
    ##########
산출:
    진실

코드 카운트에는 입 / 출력 (전체 프로그램)이 포함됩니다.


84
IMMA CHARGIN 'MAH LAZER!
Ólafur Waage

37
이다 멋진 .
GManNickG

33
DO NOT CROSS 빔
GManNickG

49
@GameFreak : 정말 오래되었습니다.
Artelius

24
그 '^'는 실제로 머리에 괴물 '레이저가있는 상어입니까?
Nathan Feger

답변:


78

펄, 166160

251 248 246 222 214 208 203 201 193 190 180 176 173 170 166 -> 160 개 문자.

이 컨테스트가 끝났을 때 솔루션에 166 개의 스트로크가 있었지만 A. Rex는 6 명의 캐릭터를 더 면도 할 수있는 몇 가지 방법을 찾았습니다.

s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;%d='>.^1<2v3'=~/./g;($r)=grep$d|=$d{$t{$_}},%t;
{$_=$t{$r+=(1,-99,-1,99)[$d^=3*/\\/+m</>]};/[\/\\ ]/&&redo}die/x/?true:false,$/

첫 번째 줄은 입력을 %t보드 i 의 열 i , 열 j$t{99*i+j} 에서 문자를 보유하는 보드의 테이블에 로드합니다 . 그때,

%d=split//,'>.^1<2v3' ; ($r)=grep{$d|=$d{$t{$_}}}%t

그것의 요소를 검색 %t문자에 대한 것과 일치 > ^ <하거나 v, 동시에 세트 $d레이저 빔의 초기 방향을 나타내고 0에서 3 사이의 값이.

메인 루프에서 각 반복이 시작될 $d때 빔이 현재 미러에 있는지 업데이트 합니다. 3에 의한 XOR'ing은 \미러에 대한 올바른 동작을 제공하고 1에 의한 XOR'ing 은 미러에 대한 올바른 동작을 제공합니다 /.

$d^=3*/\\/+m</>

다음으로 현재 위치에 따라 현재 위치 $r가 업데이트됩니다.

$r+=(1,-99,-1,99)[$d] ; $_ = $t{$r}

$_매치 연산자를 편리하게 사용할 수 있도록 현재 위치에 문자를 할당합니다 .

/[\/\\ ]/ && redo

우리가 빈 공간이나 거울에 있다면 계속하십시오. 그렇지 않으면 true목표에 도달 하면 종료 됩니다 ( $_ =~ /x/) false.

제한 : 99 개 이상의 열이있는 문제에서는 작동하지 않을 수 있습니다. 이 제한은 3 자 이상의 비용으로 제거 할 수 있습니다.


좋아요, 323 자입니다. = D
strager

5
99자를 1E5로 변경하여 3자를 희생시키면서 매우 견고하게 만들 수 있습니다.
mob

2
가장 좋은 솔루션은 게시물 상단에 더 눈에.니다.
strager

13
그러나 정규식을 사용하여 보드를 회전 시키는가? 아 sick어요 그것은 자동 20 스트로크 보너스와 같습니다.
mob

1
@mobrule : 저장 여섯 스트로크 :으로서 제 1 라인 재정렬 s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;변경, %d=split//,.." to %의 D = ... = ~ /./ g , and change 그렙 {...} %에 t`grep..,%t
A. 렉스

75

펄, 177 자

첫 번째 줄 바꿈을 제거 할 수 있습니다. 다른 두 사람은 필수입니다.

$/=%d=split//,' >/^\v';$_=<>;$s='#';{
y/v<^/>v</?do{my$o;$o.=" 
"while s/.$/$o.=$&,""/meg;y'/\\'\/'for$o,$s;$_=$o}:/>x/?die"true
":/>#/?die"false
":s/>(.)/$s$d{$1}/?$s=$1:1;redo}

설명:

$/ = %d = (' ' => '>', '/' => '^', '\\' => 'v');

오른쪽으로 움직이는 빔이 {빈 공간, 앵글 미러, 다운 앵글 미러}로 들어가면 {오른쪽으로 움직이는 빔, 위로 움직이는 빔, 아래로 움직이는 빔}이됩니다. $/길을 따라 초기화 하십시오-다행히도 "6"은 유효한 입력 문자가 아닙니다.

$_ = <>;

로 보드를 읽으십시오 $_.

$s="#";

$s빔이 맨 위에 앉아있는 것의 상징입니다. 레이저 이미 터는 벽처럼 취급해야하므로 처음부터 벽으로 설정하십시오.

if (tr/v<^/>v</) {
  my $o;
  $o .= "\n" while s/.$/$o .= $&, ""/meg;
  tr,/\\,\\/, for $o, $s;
  $_ = $o;
}

레이저 빔이 오른쪽을 제외한 다른 방향을 가리키는 경우 해당 기호를 회전 한 다음 전체 보드를 제자리에서 회전하십시오 (거울의 기호도 회전). 왼쪽으로 90도 회전하여 행과 열을 바꾸면서 행을 반대로함으로써 s///e부작용 이 약간 미미 합니다. 골프 코드에서 tr은 y'''백 슬래시 하나의 백 슬래시를 건너 뛸 수 있는 형식으로 작성되었습니다 .

die "true\n" if />x/; die "false\n" if />#/;

목표물이나 벽에 부딪 치면 올바른 메시지로 종료하십시오.

$s = $1 if s/>(.)/$s$d{$1}/;

레이저 앞에 빈 공간이 있으면 앞으로 이동하십시오. 레이저 앞에 거울이 있으면 앞으로 이동하여 빔을 회전하십시오. 두 경우 모두 "저장된 심볼"을 이전 빔 위치에 다시 넣고 방금 덮어 쓴 것을 저장된 심볼에 넣습니다.

redo;

종료 할 때까지 반복하십시오. {...;redo}2 자 미만 for(;;){...}및 3 자 미만 while(1){...}입니다.


4
보드를 회전 ... 미친. 정규식 ... 미쳤어. O_o
strager

39
당신은 ... 당신은 괴물!
LiraNuna

4
LiraNuna : 나는 그것을 칭찬으로 선택합니다.
hobbs

21
골프는 끝났습니다. 정규식으로 2D 보드 회전을 어떻게 이길 수 있습니까?!
Konrad Rudolph

13
wtf? 펄 프로그래머는 마법사입니다.
Johannes Schaub-litb

39

C89 (209 자)

#define M(a,b)*p==*#a?m=b,*p=1,q=p:
*q,G[999],*p=G;w;main(m){for(;(*++p=getchar())>0;)M(<,-1)M
(>,1)M(^,-w)M(v,w)!w&*p<11?w=p-G:0;for(;q+=m,m=*q&4?(*q&1?
-1:1)*(m/w?m/w:m*w):*q&9?!puts(*q&1?"false":"true"):m;);}

설명

C를 이해하지 못한다면이 괴물은 따라하기 어려울 것입니다.

#define M(a,b)*p==*#a?m=b,*p=1,q=p:

이 작은 매크로는 현재 문자 ( *p)가 a문자 형식 ( *#a) 과 일치하는지 확인합니다 . 같으면 이동 벡터를 b( m=b)로 설정 하고이 문자를 벽 ( *p=1) 으로 표시 한 다음 시작점을 현재 위치 ( q=p)로 설정하십시오. 이 매크로에는 "else"부분이 포함됩니다.

*q,G[999],*p=G;
w;

일부 변수를 선언하십시오. * q는 빛의 현재 위치입니다. * G는 1D 배열로서의 게임 보드입니다. * p는 현재 읽을 위치 G입니다. * w는 보드의 너비입니다.

main(m){

그렇습니다 main. m움직임 벡터를 저장하는 변수입니다. ( main최적화 의 매개 변수 입니다.)

    for(;(*++p=getchar())>0;)

G사용하여 채워지는 모든 문자를 반복합니다 p. G[0]최적화로 건너 뛰십시오 ( p의 세 번째 부분에서 문자 쓰기를 다시 낭비하지 않아도 됨 for).

        M(<,-1)
        M(>,1)
        M(^,-w)
        M(v,w)

가능하면 위에 언급 된 매크로를 사용하여 레이저를 정의하십시오. -11대응에 바로 각각 왼쪽과 -ww상하.

        !w&*p<11
            ?w=p-G
            :0;

현재 문자가 줄 끝 마커 (ASCII 10) 인 경우 너비가 설정되지 않은 경우 너비를 설정하십시오. 건너 뛴 부분 G[0]w=p-G대신 쓸 수 있습니다 w=p-G+1. 또한 이것은 ?:체인에서 체인을 마무리합니다 M.

    for(;
        q+=m,

움직임 벡터로 빛을 이동시킵니다.

        m=
        *q&4
            ?(*q&1?-1:1)*(
                m/w?m/w:m*w
            )

움직임 벡터를 반영합니다.

            :*q&9
                ?!puts(*q&1?"false":"true")
                :m
        ;

이것이 벽이거나 x이면 적절한 메시지와 함께 m=0종료하십시오 (루프 종료). 그렇지 않으면 아무것도하지 마십시오 (noop; m=m)

    );
}

8
어! 아파트 단지에서 화재 경보가 울 렸을 때 C 솔루션을 개발 중이었습니다. 이제 나는 이겼다. 그래도 좋은 해결책.
rlbond

스왑 및 스왑 / 부정 단계에 임시 변수를 사용하는 Methinks는 두 문자를 절약합니다.
Artelius

@Artelius, 예, 나는 그것을 깨달았습니다. 감사.
strager

1
TCC는 사실과 함께 밖으로 지정되지 않은 선언 및 오류 좋아하지 않는다 g.c:3: declaration expected:(
마크 Rushakoff에게

2
puts의 선언을 제거 하는 데 도움이되었지만 170 미만으로 가져 오기에는 충분하지 않습니다. 209는 꽤 훌륭합니다. 도와 주셔서 감사합니다. 정말 감사. = (아무것도 그 펄 마녀를 폐위합니다!)
strager

36

나는 사람들이 LOOOOONG 시간 동안 이것을 기다리고있을 것입니다. (도전이 끝났고 아무도 더 이상 신경 쓰지 않는다는 것을 의미합니까?)

보라 ... 나는 여기에 해결책을 제시한다.

Befunge-93!

무려 973 개의 문자를 사용합니다 (또는 공백을 무시할 정도로 자선 가능한 경우 688 입니다. 서식 지정에만 사용되며 실제 코드에서는 아무 것도 수행하지 않습니다).

주의 사항 : 나는 얼마 전에 Perl에 자신의 Befunge-93 통역사를 썼습니다. 불행히도 이것이 실제로 테스트 할 시간이 있었던 전부입니다. 나는 일반적으로 정확성에 대해 확신하지만 EOF와 관련하여 이상한 제한이있을 수 있습니다 : Perl의 <>연산자는 파일 끝에서 undef를 반환 하기 때문에 숫자 컨텍스트에서 0으로 처리됩니다. EOF가 다른 값 (-1) 인 C 기반 구현의 경우이 코드가 작동하지 않을 수 있습니다.

003pv   >~v>  #v_"a"43g-!#v_23g03p33v>v
>39#<*v   ::   >:52*-!v   >"rorrE",vg2*
######1   >^vp31+1g31$_03g13gp vv,,<15,
    a#3     >0v       vp30+1g30<>,,#3^@
######p $     0vg34"a"<   >       >vp
^<v>  > ^   p3<>-#v_:05g-!|>:15g-!| $
 >     v^     <   <   <   >^v-g52:< $ 
  v _  >52*"eslaf",,vv|-g53:_      v   
  : ^-"#">#:< #@,,,,<<>:43p0 v0 p34< 
  >">"-!vgv<  ^0p33g31p32-1g3<       
 ^     <#g1|-g34_v#-g34_v#-g34"><v^"<<<<
    v!<^<33>13g1v>03g1-v>03g1+03p$v  $$
>^  _#-v 1>g1-1v>+13pv >03p       v  pp
^_:"^"^#|^g30 <3#   $<           $<>^33
 ^!-"<":<>"v"v^># p#$<>            $^44
^      >#^#_ :" "-#v_ ^   >         ^gg
v  g34$<   ^!<v"/":< >$3p$^>05g43p$ ^55
 >,@   |!-"\"  :_$43g:">"-!|>      ^$32
 *v"x":<      >-^    ^4g52<>:"^" -#v_^
 5>-!#v_"ror"vv$p34g51:<>#|  !-"<":<#|
 ^2,,, ,,"er"<>v      #^^#<>05g43p$$^>^
      >52*"eurt",,,,,@>15g4 3p$$$$  ^#
>:"v"\:"<"\: "^"   -!#^_-!#^_-!      ^
               >                       ^

설명

Befunge 구문 및 작업에 익숙하지 않은 경우 여기를 확인 하십시오 .

Befunge는 스택 기반 언어이지만 Befunge 코드에 문자를 쓸 수있는 명령이 있습니다. 나는 그것을 두 곳에서 활용합니다. 먼저 전체 입력 내용을 Befunge 보드에 복사하지만 실제 작성된 코드 아래에 몇 줄이 있습니다. (물론 이것은 코드가 실행될 때 실제로 보이지 않습니다.)

다른 곳은 왼쪽 상단 근처에 있습니다.

######
    a#
######

이 경우 위에서 강조한 영역은 두 개의 좌표를 저장하는 곳입니다. 가운데 행의 첫 번째 열은 현재 "커서 위치"에 대한 x 좌표를 저장하는 위치입니다. 두 번째 열은 y 좌표를 저장하는 곳입니다. 다음 2 개의 열은 레이저 빔 소스가 발견 될 때 레이저 빔 소스의 x 및 y 좌표를 저장하기위한 것이며; 그리고 마지막 열 ( 'a'문자가있는)은 현재 빔 방향을 포함하도록 덮어 쓰여집니다. 이는 빔의 경로가 추적됨에 따라 분명히 변합니다.

프로그램은 (0,27)을 초기 커서 위치로 지정하여 시작합니다. 그런 다음 입력은 한 번에 한 문자 씩 읽고 커서 위치에 놓입니다. 개행은 실제 캐리지 리턴과 같이 y 좌표 만 증가시키고 x 좌표는 0으로 되돌아갑니다. 결국 인터프리터는 undef를 읽으며 입력의 끝을 알리고 레이저 반복 단계로 넘어 가기 위해 0 문자 값이 사용됩니다. 레이저 문자 [<> ^ v]를 읽으면 메모리 저장소 ( 'a'문자 위)에도 복사되고 좌표는 왼쪽 열에 복사됩니다.

이 모든 것의 최종 결과는 전체 파일이 기본적으로 Befunge 코드에 복사되어 실제 코드보다 약간 작은 방법으로 복사된다는 것입니다.

이후 빔 위치가 커서 위치로 다시 복사되고 다음 반복이 수행됩니다.

  • 현재 빔 방향을 확인하고 커서 좌표를 적절하게 늘리거나 줄입니다. (나는 첫 번째 움직임에서 레이저 빔의 코너 케이스를 다루지 않아도되도록 이것을 먼저 수행합니다.)
  • 해당 위치의 문자를 읽습니다.
  • 문자가 "#"이면 줄 바꿈과 "false"를 스택에 넣고 인쇄하고 끝냅니다.
  • 모든 빔 문자와 비교하십시오 [<> ^ v]; 일치하는 경우 "false \ n"도 인쇄하고 종료하십시오.
  • 문자가 공백이면 스택을 비우고 계속하십시오.
  • 캐릭터가 슬래시 인 경우 빔 방향을 스택으로 가져와 각 방향 캐릭터와 차례로 비교합니다. 하나를 찾으면 새로운 방향이 코드의 동일한 지점에 저장되고 루프가 반복됩니다.
  • 문자가 백 슬래시 인 경우 기본적으로 위와 동일한 작업을 수행하십시오 (백 슬래시에 대한 적절한 맵핑 제외).
  • 캐릭터가 'x'인 경우 대상을 공격했습니다. "true \ n"을 인쇄하고 종료하십시오.
  • 해당 문자가 없으면 "error \ n"을 인쇄하고 종료하십시오.

수요가 충분하면 코드 에서이 모든 것이 달성되는 위치를 정확하게 지적하려고 노력할 것입니다.


14
+1-메모장에서 열린 EXE로 잘못 해석 될 수 있기 때문에 만 가능합니다.
Kyle Rosendo

1
음 ... 거룩한 ****. 나는 Befunge를 엉망으로 만들었습니다. 이것은 정말 인상적입니다.
Almo

땅콩 버터와 카이엔과 같이 난독 화 된 언어로 코드 골프!
wberry

29

F #, 36 줄, 매우 읽기 쉬운

좋아, 대답을 얻으려면 :

let ReadInput() =
    let mutable line = System.Console.ReadLine()
    let X = line.Length 
    let mutable lines = []
    while line <> null do
        lines <- Seq.to_list line :: lines
        line <- System.Console.ReadLine()
    lines <- List.rev lines
    X, lines.Length, lines

let X,Y,a = ReadInput()
let mutable p = 0,0,'v'
for y in 0..Y-1 do
    for x in 0..X-1 do 
        printf "%c" a.[y].[x]
        match a.[y].[x] with 
        |'v'|'^'|'<'|'>' -> p <- x,y,a.[y].[x]
        |_ -> ()
    printfn ""

let NEXT = dict [ '>', (1,0,'^','v')
                  'v', (0,1,'<','>')
                  '<', (-1,0,'v','^')
                  '^', (0,-1,'>','<') ]
let next(x,y,d) =
    let dx, dy, s, b = NEXT.[d]
    x+dx,y+dy,(match a.[y+dy].[x+dx] with
               | '/' -> s
               | '\\'-> b
               | '#'|'v'|'^'|'>'|'<' -> printfn "false"; exit 0
               | 'x' -> printfn "true"; exit 0
               | ' ' -> d)

while true do
    p <- next p    

샘플:

##########
#   / \  #
#        #
#   \   x#
# >   /  #
##########
true

##########
#   v x  #
# /      #
#       /#
#   \    #
##########
false

#############
#     #     #
# >   #     #
#     #     #
#     #   x #
#     #     #
#############
false

##########
#/\/\/\  #
#\\//\\\ #
#//\/\/\\#
#\/\/\/x^#
##########
true

##########
#   / \  #
#        #
#/    \ x#
#\>   /  #
##########
false

##########
#  /    \#
# / \    #
#/    \ x#
#\^/\ /  #
##########
false

54
이 책을 실제로 읽을 수 있습니다! 기적적!
Jeff Atwood

17
Java / C # 코드 골프는 문자가 아닌 줄로 계산됩니다. 이것이 핸디캡입니다.
Nathan Feger

3
@strager는 코드를 유지하기 위해 고용되어 원래 개발자가 떠난 지 3 년 동안 우울하지 않습니다.
Nathan Feger

Visual Studio 2010에서 F #을 사용하면 실패합니다. Seq.to_list가 존재하지 않으며 (확인, toList로 변경) 25 행, 불완전한 패턴 일치입니다.
Russell

2
예, 지금 _list를 toList로 변경하십시오. 불완전한 일치 경고는 정상입니다. 코드 골프이므로 다음과 같은 코드를 사용하지 않았습니다. | _-> failwith "불가능"
Brian

29

Golfscript-83 자 (내와 스트 레이저의 매쉬업)

줄 바꿈은 포장을 위해 여기 있습니다.

:|'v^><'.{|?}%{)}?:$@=?{.[10|?).~)1-1]=$+
:$|=' \/x'?\[.\2^.1^'true''false']=.4/!}do

골프 스크립트-107 자

개행은 명확성을 위해 거기에 있습니다

10\:@?):&4:$;{0'>^<v'$(:$=@?:*>}do;
{[1 0&--1&]$=*+:*;[{$}{3$^}{1$^}{"true "}{"false"}]@*=' \/x'?=~5\:$>}do$

작동 방식

첫 번째 줄은 초기 위치와 방향을 계산합니다.
두 번째 라인은 레이저가 거울에 닿을 때마다 회전하는 단계입니다.


18

루비 353 자 :

314 277 자!

좋아, 루비에는 256자가 있고 이제 끝났다. 멋진 라운드 번호. :)

247 자 멈출 수 없어

223 개 203 루비 201 문자

d=x=y=-1;b=readlines.each{|l|d<0&&(d="^>v<".index l[x]if x=l.index(/[>^v<]/)
y+=1)};loop{c=b[y+=[-1,0,1,0][d]][x+=[0,1,0,-1][d]]
c==47?d=[1,0,3,2][d]:c==92?d=3-d:c==35?(p !1;exit):c<?x?0:(p !!1;exit)}

공백으로 :

d = x = y = -1
b = readlines.each { |l|
  d < 0 && (d = "^>v<".index l[x] if x = l.index(/[>^v<]/); y += 1)
}

loop {
  c = b[y += [-1, 0, 1, 0][d]][x += [0, 1, 0, -1][d]]

  c == 47 ? d = [1, 0, 3, 2][d] :
  c == 92 ? d = 3 - d :
  c == 35 ? (p !1; exit) :
  c < ?x ? 0 : (p !!1; exit)
}

약간 리팩토링 :

board = readlines

direction = x = y = -1
board.each do |line|
  if direction < 0
    x = line.index(/[>^v<]/)
    if x
      direction = "^>v<".index line[x]
    end
    y += 1
  end
end

loop do
  x += [0, 1, 0, -1][direction]
  y += [-1, 0, 1, 0][direction]

  ch = board[y][x].chr
  case ch
  when "/"
    direction = [1, 0, 3, 2][direction]
  when "\\"
    direction = 3 - direction
  when "x"
    puts "true"
    exit
  when "#"
    puts "false"
    exit
  end
end

그러나 ... 이름 ch을 바꾸 C거나 다른 1 문자로 2 문자를 저장할 수 있습니다!
LiraNuna

알았어, 알았어 ... 사실 한 번만 사용하므로 전체 변수가 필요하지 않다는 것을 실제로 깨달았습니다. 이것과 몇 가지 다른 개선으로 247 자로 줄었습니다.
Jeremy Ruten

1
아니오 i++(대신 i+=1)?
LiraNuna

6
아니. ++ i를 할 수는 있지만 예전처럼 실제로 긍정적으로 만듭니다.
DigitalRoss

나는 압축 된 버전 좋아 #을, P
SeanJA

17

파이썬

바꿈을 포함하여 294 277 253 240 232 문자 :

(4 행과 5 행의 첫 문자는 공백이 아닌 탭입니다)

l='>v<^';x={'/':'^<v>','\\':'v>^<',' ':l};b=[1];r=p=0
while b[-1]:
 b+=[raw_input()];r+=1
 for g in l:
    c=b[r].find(g)
    if-1<c:p=c+1j*r;d=g
while' '<d:z=l.find(d);p+=1j**z;c=b[int(p.imag)][int(p.real)];d=x.get(c,' '*4)[z]
print'#'<c

나는 파이썬조차도 옵션 세미콜론을 가지고 있다는 것을 잊었다.

작동 원리

이 코드의 핵심은 복잡한 숫자를 사용하여 위치와 방향을 나타내는 것입니다. 행은 가상 축이며 아래쪽으로 증가합니다. 열은 실제 축이며 오른쪽으로 증가합니다.

l='>v<^';레이저 기호 목록. 순서는 레이저 방향 문자의 인덱스가 sqrt (-1)의 거듭 제곱과 일치하도록 선택됩니다.

x={'/':'^<v>','\\':'v>^<',' ':l};빔이 다른 타일을 떠날 때 방향이 어떻게 변하는지를 결정하는 변환 테이블. 타일이 핵심이며 새로운 방향은 값입니다.

b=[1];보드를 보유합니다. while 루프가 최소한 한 번 실행되도록 첫 번째 요소는 1입니다 (true로 평가됨).

r=p=0 r입력의 현재 행 번호 p이고, 레이저 빔의 현재 위치입니다.

while b[-1]: raw_input이 빈 문자열을 반환 할 때 보드 데이터로드 중지

b+=[raw_input()];r+=1 다음 입력 줄을 보드에 추가하고 행 카운터를 증가시킵니다.

for g in l: 각 레이저 방향을 차례로 추측

c=b[r].find(g) 열을 레이저의 위치로 설정하거나 라인에 있지 않은 경우 (또는 다른 방향을 가리키는 경우) -1

if-1<c:p=c+1j*r;d=g레이저를 찾았다면 현재 위치 p와 방향 을 설정하십시오 d. d문자 중 하나입니다l

보드를에 넣은 후 b현재 위치 p와 방향 d이 레이저 소스의 위치 와 방향 으로 설정되었습니다.

while' '<d: space는 방향 기호보다 ASCII 값이 낮으므로 중지 플래그로 사용합니다.

z=l.find(d);l문자열 에서 현재 방향 문자의 색인 z나중에 x테이블을 사용하여 새 빔 방향을 결정 하고 위치를 증가시키는 데 사용됩니다.

p+=1j**z;i의 거듭 제곱을 사용하여 위치를 증가시킵니다. 예를 들어, l.find('<')==2-> i ^ 2 = -1이며 왼쪽 열로 이동합니다.

c=b[int(p.imag)][int(p.real)]; 현재 위치에서 문자를 읽습니다

d=x.get(c,' '*4)[z]변환 테이블에서 빔의 새 방향을 찾으십시오. 현재 문자가 테이블에 없으면 d공백으로 설정 하십시오.

print'#'<c 대상 이외의 다른 것을 중지하면 false로 인쇄합니다.


9
p+=1j**z: 달콤합니다.
dmckee --- 전 운영자 고양이

16

되어 있었다 C # 3 브라이언의 솔루션의 직접적인 포트, 마이너스 콘솔 상호 작용. 이것은 완전한 프로그램이 아니기 때문에 도전 과제의 항목이 아니며, 그가 사용한 F # 구문 중 일부가 C #으로 어떻게 표현되는지 궁금합니다.

bool Run(string input) {
    var a = input.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
    var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
             .First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));
    var NEXT = new[] {
            new {d = '>', dx = 1, dy = 0, s = '^', b = 'v'},
            new {d = 'v', dx = 0, dy = 1, s = '<', b = '>'},
            new {d = '<', dx = -1, dy = 0, s = 'v', b = '^'},
            new {d = '^', dx = 0, dy = -1, s = '>', b = '<'}
        }.ToDictionary(x => x.d);
    while (true) {
        var n = NEXT[p.d];
        int x = p.x + n.dx,
            y = p.y + n.dy;
        var d = a[y][x];
        switch (d) {
            case '/':  d = n.s; break;
            case '\\': d = n.b; break;
            case ' ':  d = p.d; break;
            default: return d == 'x';
        }
        p = new {x, y, d};
    }
}

편집 : 몇 가지 실험 후 다음과 같은 자세한 검색 코드가 있습니다.

int X = a[0].Length, Y = a.Length;
var p = new {x = 0, y = 0, d = 'v'};
for (var y = 0; y < Y; y++) {
    for (var x = 0; x < X; x++) {
        var d = a[y][x];
        switch (d) {
            case 'v': case '^': case '<': case '>':
                p = new {x, y, d}; break;
        }
    }
}

훨씬 더 간단한 LINQ to Objects 코드로 대체되었습니다.

var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
         .First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));

8
omg. linq와 c #이 얼마나 강력한지를 보여주는 좋은 예입니다. 나는 거대한 C # 팬입니다. x)
Emiswelt

16

F #, 255 자 (그리고 여전히 읽을 수 있습니다!) :

좋아, 밤의 휴식 후, 나는 이것을 많이 개선했다.

let a=System.Console.In.ReadToEnd()
let w,c=a.IndexOf"\n"+1,a.IndexOfAny[|'^';'<';'>';'v'|]
let rec n(c,d)=
 let e,s=[|-w,2;-1,3;1,0;w,1|].[d]
 n(c+e,match a.[c+e]with|'/'->s|'\\'->3-s|' '->d|c->printfn"%A"(c='x');exit 0)
n(c,"^<>v".IndexOf a.[c])

한 줄씩 살펴 보겠습니다.

먼저, 모든 입력을 큰 1 차원 배열로 처리하십시오 (2D 배열은 코드 골프에 좋지 않을 수 있습니다. 1D 배열을 사용하고 한 행의 너비를 인덱스에 더하거나 빼서 한 줄 위 / 아래로 이동하십시오).

다음으로 입력 행의 너비 'w'와 시작 위치 인 'c'를 배열에 색인하여 계산합니다.

이제 현재 위치 'c'와 위쪽, 왼쪽, 오른쪽, 아래쪽에 대해 0,1,2,3 인 방향 'd'를 취하는 '다음'기능 'n'을 정의 해 봅시다.

인덱스 엡실론 'e'와 슬래시 '무엇에 대한 새로운 방향'은 테이블로 계산됩니다. 예를 들어, 현재 방향 'd'가 0 (위쪽) 인 경우 테이블의 첫 번째 요소에 "-w, 2"가 표시됩니다. 이는 인덱스를 w 씩 줄이며 슬래시를 칠 경우 새 방향은 2입니다. (권리).

이제 우리는 (1) 다음 인덱스 ( "c + e"-현재 플러스 엡실론)와 (2) 새로운 방향을 사용하여 다음 함수 'n'으로 되풀이합니다. 그 다음 세포. lookahead char가 슬래시 인 경우 새 방향은 's'입니다. 백 슬래시 인 경우 새로운 방향은 3 초입니다 (인코딩 0123을 선택하면이 효과가 나타납니다). 그것이 공간이라면, 우리는 계속 같은 방향 'd'로 진행합니다. 그리고 다른 캐릭터 'c'라면 게임이 종료되고 char가 'x'이면 'true'를 인쇄하고 그렇지 않으면 false를 인쇄합니다.

시작하기 위해 초기 위치 'c'와 시작 방향 (0123으로 방향의 초기 인코딩을 수행)과 함께 재귀 함수 'n'을 호출합니다.

나는 아마 여전히 더 많은 캐릭터를 면도 할 수 있다고 생각하지만, 이것처럼 꽤 기뻐합니다 (255는 좋은 숫자입니다).


11

18203 자 무게는 다음을 수행 할 수있는 Python 솔루션입니다.

  • '방'밖에서 거울에 대처
  • 2D 제한에 따라 '방'이 없을 때 궤적 계산
  • 오류보고

여전히 약간의 정리가 필요하며 2D 물리학이 빔이 스스로 교차 할 수 없다는 것을 알 수 있는지 모르겠습니다 ...

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
The shortest code by character count to input a 2D representation of a board, 
and output 'true' or 'false' according to the input.

The board is made out of 4 types of tiles:

# - A solid wall
x - The target the laser has to hit
/ or \ - Mirrors pointing to a direction (depends on laser direction)
v, ^, > or < - The laser pointing to a direction (down, up, right and left
respectively)

There is only one laser and only one target. Walls must form a solid rectangle 
of any size, where the laser and target are placed inside. Walls inside the
'room' are possible.

Laser ray shots and travels from it's origin to the direction it's pointing. If
a laser ray hits the wall, it stops. If a laser ray hits a mirror, it is bounces
90 degrees to the direction the mirror points to. Mirrors are two sided, meaning
both sides are 'reflective' and may bounce a ray in two ways. If a laser ray
hits the laser (^v><) itself, it is treated as a wall (laser beam destroys the
beamer and so it'll never hit the target).
"""



SOLID_WALL, TARGET, MIRROR_NE_SW, MIRROR_NW_SE, LASER_DOWN, LASER_UP, \
LASER_RIGHT, LASER_LEFT = range(8)

MIRRORS = (MIRROR_NE_SW, MIRROR_NW_SE)

LASERS = (LASER_DOWN, LASER_UP, LASER_RIGHT, LASER_LEFT)

DOWN, UP, RIGHT, LEFT = range(4)

LASER_DIRECTIONS = {
    LASER_DOWN : DOWN,
    LASER_UP   : UP,
    LASER_RIGHT: RIGHT,
    LASER_LEFT : LEFT
}

ROW, COLUMN = range(2)

RELATIVE_POSITIONS = {
    DOWN : (ROW,     1),
    UP   : (ROW,    -1),
    RIGHT: (COLUMN,  1),
    LEFT : (COLUMN, -1)
}

TILES = {"#" : SOLID_WALL,
         "x" : TARGET,
         "/" : MIRROR_NE_SW,
         "\\": MIRROR_NW_SE,
         "v" : LASER_DOWN,
         "^" : LASER_UP,
         ">" : LASER_RIGHT,
         "<" : LASER_LEFT}

REFLECTIONS = {MIRROR_NE_SW: {DOWN : LEFT,
                              UP   : RIGHT,
                              RIGHT: UP,
                              LEFT : DOWN},
               MIRROR_NW_SE: {DOWN : RIGHT,
                              UP   : LEFT,
                              RIGHT: DOWN,
                              LEFT : UP}}



def does_laser_hit_target(tiles):
    """
        Follows a lasers trajectory around a grid of tiles determining if it
        will reach the target.

        Keyword arguments:
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
    """

    #Obtain the position of the laser
    laser_pos = get_laser_pos(tiles)

    #Retrieve the laser's tile
    laser = get_tile(tiles, laser_pos)

    #Create an editable starting point for the beam
    beam_pos = list(laser_pos)

    #Create an editable direction for the beam
    beam_dir = LASER_DIRECTIONS[laser]

    #Cache the number of rows
    number_of_rows = len(tiles)

    #Keep on looping until an ultimate conclusion
    while True:

        #Discover the axis and offset the beam is travelling to
        axis, offset = RELATIVE_POSITIONS[beam_dir]

        #Modify the beam's position
        beam_pos[axis] += offset

        #Allow for a wrap around in this 2D scenario
        try:

            #Get the beam's new tile
            tile = get_tile(tiles, beam_pos)

        #Perform wrapping
        except IndexError:

            #Obtain the row position
            row_pos = beam_pos[ROW]

            #Handle vertical wrapping
            if axis == ROW:

                #Handle going off the top
                if row_pos == -1:

                    #Move beam to the bottom
                    beam_pos[ROW] = number_of_rows - 1

                #Handle going off the bottom
                elif row_pos == number_of_rows:

                    #Move beam to the top
                    beam_pos[ROW] = 0

            #Handle horizontal wrapping
            elif axis == COLUMN:

                #Obtain the row
                row = tiles[row_pos]

                #Calculate the number of columns
                number_of_cols = len(row)

                #Obtain the column position
                col_pos = beam_pos[COLUMN]

                #Handle going off the left hand side
                if col_pos == -1:

                    #Move beam to the right hand side
                    beam_pos[COLUMN] = number_of_cols - 1

                #Handle going off the right hand side
                elif col_pos == number_of_cols:

                    #Move beam to the left hand side
                    beam_pos[COLUMN] = 0

            #Get the beam's new tile
            tile = get_tile(tiles, beam_pos)

        #Handle hitting a wall or the laser
        if tile in LASERS \
        or tile == SOLID_WALL:
            return False

        #Handle hitting the target
        if tile == TARGET:
            return True

        #Handle hitting a mirror
        if tile in MIRRORS:
            beam_dir = reflect(tile, beam_dir)

def get_laser_pos(tiles):
    """
        Returns the current laser position or an exception.

        Keyword arguments:
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
    """

    #Calculate the number of rows
    number_of_rows = len(tiles)

    #Loop through each row by index
    for row_pos in range(number_of_rows):

        #Obtain the current row
        row = tiles[row_pos]

        #Calculate the number of columns
        number_of_cols = len(row)

        #Loop through each column by index
        for col_pos in range(number_of_cols):

            #Obtain the current column
            tile = row[col_pos]

            #Handle finding a laser
            if tile in LASERS:

                #Return the laser's position
                return row_pos, col_pos

def get_tile(tiles, pos):
    """
        Retrieves a tile at the position specified.

        Keyword arguments:
        pos --- a row/column position of the tile
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
    """

    #Obtain the row position
    row_pos = pos[ROW]

    #Obtain the column position
    col_pos = pos[COLUMN]

    #Obtain the row
    row = tiles[row_pos]

    #Obtain the tile
    tile = row[col_pos]

    #Return the tile
    return tile

def get_wall_pos(tiles, reverse=False):
    """
        Keyword arguments:
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
        reverse --- whether to search in reverse order or not (defaults to no)
    """

    number_of_rows = len(tiles)

    row_iter = range(number_of_rows)

    if reverse:
        row_iter = reversed(row_iter)

    for row_pos in row_iter:
        row = tiles[row_pos]

        number_of_cols = len(row)

        col_iter = range(number_of_cols)

        if reverse:
            col_iter = reversed(col_iter)

        for col_pos in col_iter:
            tile = row[col_pos]

            if tile == SOLID_WALL:
                pos = row_pos, col_pos

                if reverse:
                    offset = -1
                else:
                    offset = 1

                for axis in ROW, COLUMN:
                    next_pos = list(pos)

                    next_pos[axis] += offset

                    try:
                        next_tile = get_tile(tiles, next_pos)
                    except IndexError:
                        next_tile = None

                    if next_tile != SOLID_WALL:
                        raise WallOutsideRoomError(row_pos, col_pos)

                return pos

def identify_tile(tile):
    """
        Returns a symbolic value for every identified tile or None.

        Keyword arguments:
        tile --- the tile to identify
    """

    #Safely lookup the tile
    try:

        #Return known tiles
        return TILES[tile]

    #Handle unknown tiles
    except KeyError:

        #Return a default value
        return

def main():
    """
        Takes a board from STDIN and either returns a result to STDOUT or an
        error to STDERR.

        Called when this file is run on the command line.
    """

    #As this function is the only one to use this module, and it can only be
    #called once in this configuration, it makes sense to only import it here.
    import sys

    #Reads the board from standard input.
    board = sys.stdin.read()

    #Safely handles outside input
    try:

        #Calculates the result of shooting the laser
        result = shoot_laser(board)

    #Handles multiple item errors
    except (MultipleLaserError, MultipleTargetError) as error:

        #Display the error
        sys.stderr.write("%s\n" % str(error))

        #Loop through all the duplicated item symbols
        for symbol in error.symbols:

            #Highlight each symbol in green
            board = board.replace(symbol, "\033[01;31m%s\033[m" % symbol)

        #Display the board
        sys.stderr.write("%s\n" % board)

        #Exit with an error signal
        sys.exit(1)

    #Handles item missing errors
    except (NoLaserError, NoTargetError) as error:

        #Display the error
        sys.stderr.write("%s\n" % str(error))

        #Display the board
        sys.stderr.write("%s\n" % board)

        #Exit with an error signal
        sys.exit(1)

    #Handles errors caused by symbols
    except (OutsideRoomError, WallNotRectangleError) as error:

        #Displays the error
        sys.stderr.write("%s\n" % str(error))

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

        line = "%s\033[01;31m%s\033[m%s" % (before, symbol, after)

        lines[error.row_pos] = line

        board = "\n".join(lines)

        #Display the board
        sys.stderr.write("%s\n" % board)

        #Exit with an error signal
        sys.exit(1)

    #Handles errors caused by non-solid walls
    except WallNotSolidError as error:

        #Displays the error
        sys.stderr.write("%s\n" % str(error))

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

        line = "%s\033[01;5;31m#\033[m%s" % (before, after)

        lines[error.row_pos] = line

        board = "\n".join(lines)

        #Display the board
        sys.stderr.write("%s\n" % board)

        #Exit with an error signal
        sys.exit(1)

    #If a result was returned
    else:

        #Converts the result into a string
        result_str = str(result)

        #Makes the string lowercase
        lower_result = result_str.lower()

        #Returns the result
        sys.stdout.write("%s\n" % lower_result)

def parse_board(board):
    """
        Interprets the raw board syntax and returns a grid of tiles.

        Keyword arguments:
        board --- the board containing the tiles (walls, laser, target, etc)
    """

    #Create a container for all the lines
    tiles = list()

    #Loop through all the lines of the board
    for line in board.split("\n"):

        #Identify all the tiles on the line 
        row = [identify_tile(tile) for tile in line]

        #Add the row to the container
        tiles.append(row)

    #Return the container
    return tiles

def reflect(mirror, direction):
    """
        Returns an updated laser direction after it has been reflected on a
        mirror.

        Keyword arguments:
        mirror --- the mirror to reflect the laser from
        direction --- the direction the laser is travelling in
    """

    try:
        direction_lookup = REFLECTIONS[mirror]
    except KeyError:
        raise TypeError("%s is not a mirror.", mirror)

    try:
        return direction_lookup[direction]
    except KeyError:
        raise TypeError("%s is not a direction.", direction)

def shoot_laser(board):
    """
        Shoots the boards laser and returns whether it will hit the target.

        Keyword arguments:
        board --- the board containing the tiles (walls, laser, target, etc)
    """

    tiles = parse_board(board)

    validate_board(tiles)

    return does_laser_hit_target(tiles)

def validate_board(tiles):
    """
        Checks an board to see if it is valid and raises an exception if not.

        Keyword arguments:
        tiles --- row/column based version of a board containing symbolic
                  versions of the tiles (walls, laser, target, etc)
    """

    found_laser = False
    found_target = False

    try:
        n_wall, w_wall = get_wall_pos(tiles)
        s_wall, e_wall = get_wall_pos(tiles, reverse=True)
    except TypeError:
        n_wall = e_wall = s_wall = w_wall = None

    number_of_rows = len(tiles)

    for row_pos in range(number_of_rows):
        row = tiles[row_pos]

        number_of_cols = len(row)

        for col_pos in range(number_of_cols):

            tile = row[col_pos]

            if ((row_pos in (n_wall, s_wall) and
                 col_pos in range(w_wall, e_wall))
                or
                (col_pos in (e_wall, w_wall) and
                 row_pos in range(n_wall, s_wall))):
                if tile != SOLID_WALL:
                    raise WallNotSolidError(row_pos, col_pos)
            elif (n_wall != None and
                  (row_pos < n_wall or
                   col_pos > e_wall or
                   row_pos > s_wall or
                   col_pos < w_wall)):

                if tile in LASERS:
                    raise LaserOutsideRoomError(row_pos, col_pos)
                elif tile == TARGET:
                    raise TargetOutsideRoomError(row_pos, col_pos)
                elif tile == SOLID_WALL:
                    if not (row_pos >= n_wall and
                            col_pos <= e_wall and
                            row_pos <= s_wall and
                            col_pos >= w_wall):
                        raise WallOutsideRoomError(row_pos, col_pos)
            else:
                if tile in LASERS:
                    if not found_laser:
                        found_laser = True
                    else:
                        raise MultipleLaserError(row_pos, col_pos)
                elif tile == TARGET:
                    if not found_target:
                        found_target = True
                    else:
                        raise MultipleTargetError(row_pos, col_pos)

    if not found_laser:
        raise NoLaserError(tiles)

    if not found_target:
        raise NoTargetError(tiles)



class LasersError(Exception):
    """Parent Error Class for all errors raised."""

    pass

class NoLaserError(LasersError):
    """Indicates that there are no lasers on the board."""

    symbols = "^v><"

    def __str__ (self):
        return "No laser (%s) to fire." % ", ".join(self.symbols)

class NoTargetError(LasersError):
    """Indicates that there are no targets on the board."""

    symbols = "x"

    def __str__ (self):
        return "No target (%s) to hit." % ", ".join(self.symbols)

class MultipleLaserError(LasersError):
    """Indicates that there is more than one laser on the board."""

    symbols = "^v><"

    def __str__ (self):
        return "Too many lasers (%s) to fire, only one is allowed." % \
               ", ".join(self.symbols)

class MultipleTargetError(LasersError):
    """Indicates that there is more than one target on the board."""

    symbols = "x"

    def __str__ (self):
        return "Too many targets (%s) to hit, only one is allowed." % \
               ", ".join(self.symbols)

class WallNotSolidError(LasersError):
    """Indicates that the perimeter wall is not solid."""

    __slots__ = ("__row_pos", "__col_pos", "n_wall", "s_wall", "e_wall",
                 "w_wall")

    def __init__(self, row_pos, col_pos):
        self.__row_pos = row_pos
        self.__col_pos = col_pos

    def __str__ (self):
        return "Walls must form a solid rectangle."

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

    row_pos = property(__get_row_pos)
    col_pos = property(__get_col_pos)

class WallNotRectangleError(LasersError):
    """Indicates that the perimeter wall is not a rectangle."""

    __slots__ = ("__row_pos", "__col_pos")

    def __init__(self, row_pos, col_pos):
        self.__row_pos = row_pos
        self.__col_pos = col_pos

    def __str__ (self):
        return "Walls must form a rectangle."

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

    row_pos = property(__get_row_pos)
    col_pos = property(__get_col_pos)

class OutsideRoomError(LasersError):
    """Indicates an item is outside of the perimeter wall."""

    __slots__ = ("__row_pos", "__col_pos", "__name")

    def __init__(self, row_pos, col_pos, name):
        self.__row_pos = row_pos
        self.__col_pos = col_pos
        self.__name = name

    def __str__ (self):
        return "A %s was found outside of a 'room'." % self.__name

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

    row_pos = property(__get_row_pos)
    col_pos = property(__get_col_pos)

class LaserOutsideRoomError(OutsideRoomError):
    """Indicates the laser is outside of the perimeter wall."""

    def __init__ (self, row_pos, col_pos):
        OutsideRoomError.__init__(self, row_pos, col_pos, "laser")

class TargetOutsideRoomError(OutsideRoomError):
    """Indicates the target is outside of the perimeter wall."""

    def __init__ (self, row_pos, col_pos):
        OutsideRoomError.__init__(self, row_pos, col_pos, "target")

class WallOutsideRoomError(OutsideRoomError):
    """Indicates that there is a wall outside of the perimeter wall."""

    def __init__ (self, row_pos, col_pos):
        OutsideRoomError.__init__(self, row_pos, col_pos, "wall")



if __name__ == "__main__":
    main()

색상 오류보고를 보여주는 bash 스크립트 :

#!/bin/bash

declare -a TESTS

test() {
    echo -e "\033[1m$1\033[0m"
    tput sgr0
    echo "$2" | ./lasers.py
    echo
}

test \
"no laser" \
"    ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"multiple lasers" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\  ^ #
    ##########"

test \
"no target" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"multiple targets" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\  x #
    ##########"

test \
"wall not solid" \
"    ##### ####
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"laser_outside_room" \
"    ##########
 >  #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"laser before room" \
" >  ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"laser row before room" \
"   >
    ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"laser after room" \
"    ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########  >"

test \
"laser row after room" \
"    ##########
    #     x  #
    # /      #
    #       /#
    #   \\    #
    ##########
  > "

test \
"target outside room" \
"    ##########
 x  #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"target before room" \
" x  ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"target row before room" \
"   x
    ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"target after room" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########   x"

test \
"target row after room" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\    #
    ##########
  x "

test \
"wall outside room" \
"    ##########
 #  #   v    #
    # /      #
    #       /#
    #   \\  x #
    ##########"

test \
"wall before room" \
" #  ##########
    #   v    #
    # /      #
    #       /#
    #   \\  x #
    ##########"

test \
"wall row before room" \
"    #
    ##########
    #   v    #
    # /      #
    #       /#
    #   \\  x #
    ##########"

test \
"wall after room" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\  x #
    ########## #"

test \
"wall row after room" \
"    ##########
    #   v    #
    # /      #
    #       /#
    #   \\  x #
    ##########
  #"

test \
"mirror outside room positive" \
"    ##########
 /  #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## "

test \
"mirrors outside room negative" \
"    ##########
 \\  #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"mirror before room positive" \
" \\  ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## "

test \
"mirrors before room negative" \
" /  ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"mirror row before room positive" \
"     \\
    ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## "

test \
"mirrors row before room negative" \
"     \\
    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"mirror after row positive" \
"    ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## /  "

test \
"mirrors after row negative" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########   /  "

test \
"mirror row after row positive" \
"    ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## 
 /  "

test \
"mirrors row after row negative" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ########## 
 /  "

test \
"laser hitting laser" \
"    ##########
    #   v   \\#
    #        #
    #        #
    #x  \\   /#
    ##########"

test \
"mirrors positive" \
"    ##########
    #   / \\  #
    #        #
    #   \\   x#
    # >   /  #
    ########## "

test \
"mirrors negative" \
"    ##########
    #   v x  #
    # /      #
    #       /#
    #   \\    #
    ##########"

test \
"wall collision" \
"    #############
    #     #     #
    # >   #     #
    #     #     #
    #     #   x #
    #     #     #
    #############"

test \
"extreme example" \
"    ##########
    #/\\/\\/\\  #
    #\\\\//\\\\\\ #
    #//\\/\\/\\\\#
    #\\/\\/\\/x^#
    ##########"

test \
"brian example 1" \
"##########
#   / \\  #
#        #
#/    \\ x#
#\\>   /  #
##########"

test \
"brian example 2" \
"##########
#  /    \\#
# / \\    #
#/    \\ x#
#\\^/\\ /  #
##########"

개발에 사용 된 단위 테스트 :

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import unittest

from lasers import *

class TestTileRecognition(unittest.TestCase):
    def test_solid_wall(self):
        self.assertEqual(SOLID_WALL, identify_tile("#"))

    def test_target(self):
        self.assertEqual(TARGET, identify_tile("x"))

    def test_mirror_ne_sw(self):
        self.assertEqual(MIRROR_NE_SW, identify_tile("/"))

    def test_mirror_nw_se(self):
        self.assertEqual(MIRROR_NW_SE, identify_tile("\\"))

    def test_laser_down(self):
        self.assertEqual(LASER_DOWN, identify_tile("v"))

    def test_laser_up(self):
        self.assertEqual(LASER_UP, identify_tile("^"))

    def test_laser_right(self):
        self.assertEqual(LASER_RIGHT, identify_tile(">"))

    def test_laser_left(self):
        self.assertEqual(LASER_LEFT, identify_tile("<"))

    def test_other(self):
        self.assertEqual(None, identify_tile(" "))

class TestReflection(unittest.TestCase):
    def setUp(self):
        self.DIRECTION = LEFT
        self.NOT_DIRECTIO

6
레이저 물리학은 빔 스스로 교차 할 수 있도록 지시 합니다. 위의 의견은 중요한 문화 참고 자료입니다.
dmckee --- 전 운영자 고양이

5
골프를 코딩하는 거북이와 토끼 접근. 캐릭터가 너무 많으면 (현재 우승자보다 91 배 더 많은) 무언가를 제공하지만 스펙의 모든 문자에주의를 기울이십시오. 느리고 꾸준한 계약은 일반적으로 계약 업무를 덜어줍니다.
Metalshark

단위 테스트에 일부 부분이 누락 된 것 같습니다. "self.NOT_DIRECTIO"에서 차단
BioGeek

@BioGeek-게시물 길이의 한계에 도달했습니다.). BASH 스타일 테스트 외에도 색상 강조 표시가 나타납니다.
메탈 샤크

11

루비, 176 자

x=!0;y=0;e="^v<>#x";b=readlines;b.map{|l|(x||=l=~/[v^<>]/)||y+=1};c=e.index(b[y][x])
loop{c<2&&y+=c*2-1;c>1&&x+=2*c-5;e.index(n=b[y][x])&&(p n==?x;exit);c^='  \/'.index(n)||0}

나는 대부분의 포스터와 같은 간단한 상태 머신을 사용했지만 아무 것도 화려하지 않았습니다. 나는 생각할 수있는 모든 트릭을 사용하여 계속 엉망이되었습니다. 방향을 변경하는 데 사용 된 비트 XOR (변수에 정수로 저장 c)은 이전 버전의 조건보다 크게 개선되었습니다.

코드가 증가 x하고 y짧아 질 수 있다는 의혹 이 있습니다. 다음은 증분을 수행하는 코드 섹션입니다.

c<2&&y+=c*2-1;c>1&&x+=(c-2)*2-1

편집 : 위의 내용을 약간 단축 할 수있었습니다.

c<2&&y+=c*2-1;c>1&&x+=2*c-5

레이저의 현재 방향은 c다음과 같이 저장됩니다.

0 => 위로
1 => 아래로
2 => 왼쪽
3 => 오른쪽

증분 코드는이 사실에 의존 x하고 y정확한 양으로 (0, 1, -1). 나는 숫자가 각 방향으로 매핑되는 것을 재 배열하려고 시도했는데, 그것은 산술 버전보다 짧을 것이라는 잔소리가 있기 때문에 값을 증가시키기 위해 약간의 비트 조작을 할 수있는 배열을 찾았습니다.


9

C # 3.0

259 자

bool S(char[]m){var w=Array.FindIndex(m,x=>x<11)+1;var s=Array.FindIndex(m,x=>x>50&x!=92&x<119);var t=m[s];var d=t<61?-1:t<63?1:t<95?-w:w;var u=0;while(0<1){s+=d;u=m[s];if(u>119)return 0<1;if(u==47|u==92)d+=d>0?-w-1:w+1;else if(u!=32)return 0>1;d=u>47?-d:d;}}

약간 더 읽기 쉽다 :

bool Simulate(char[] m)
{
    var w = Array.FindIndex(m, x => x < 11) + 1;
    var s = Array.FindIndex(m, x => x > 50 & x != 92 & x < 119);
    var t = m[s];
    var d = t < 61 ? -1 : t < 63 ? 1 : t < 95 ? -w : w;
    var u = 0;
    while (0 < 1)
    {
        s += d;
        u = m[s];
        if (u > 119)
            return 0 < 1;
        if (u == 47 | u == 92)
            d += d > 0 ? -w - 1 : w + 1;
        else if (u != 32)
            return 0 > 1;
        d = u > 47 ? -d : d;
    }
}

문자의 주요 낭비는 맵의 너비와 레이저 소스의 위치를 ​​찾는 것 같습니다. 이것을 단축하는 방법에 대한 아이디어가 있습니까?


나는 이것이 더 짧은 지 확실하지 않지만 레이저를 찾고 너비를 찾는 것에 대한 나의 기회입니다 : using L = List <string>; using P = System.Drawing.Point; using L = List <string>; L r = new L () { "v", "<", ">", "^"}; P p = new P (); r.ForEach (a => {int c = 0; v.ForEach (s => {c ++ ; if (s.IndexOf (a)! =-1) {pX = s.IndexOf (a); pY = c;}});}); int l = v [0]. 길이; v는 테이블을 포함하는 List <string>이며 레이저 위치를 나타내는 Point + 너비를 나타내는 int를 출력합니다.
RCIX

더 나은 방법 : L = List <string>; L l = new L (4) { "v", "<", ">", "^"}; var point = new {x = 0, y = 0}; int c = 0; l.ForEach (a => {m.ForEach (s => {if (s.IndexOf (a)! =-1)) {point = new {x = s.IndexOf (a), y = c};}}); c ++;}); int w = m [0]. 길이;
RCIX

4
문제는 기능이 아닌 전체 프로그램을 요구합니다.
strager

방법에 대한 while(1)
SSpoke

9

C + ASCII, 197 자 :

G[999],*p=G,w,z,t,*b;main(){for(;(*p++=t=getchar()^32)>=0;w=w|t-42?w:p-G)z=t^86?t^126?t^28?t^30?z:55:68:56:75,b=z?b:p;for(;t=z^55?z^68?z^56?z^75?0:w:-w:-1:1;z^=*b)b+=t;puts(*b^88?"false":"true");}

이 C 솔루션은 ASCII 문자 세트를 가정하여 XOR 미러 트릭을 사용할 수 있습니다. 예를 들어, 모든 입력 라인의 길이가 같아야합니다.

그것은 200 문자 표시 아래에서 깨지지 만 당황하지만 여전히 Perl 솔루션을 이길 수는 없습니다!


= O! +1! 나를 때리는 것에 감사합니다. =]
strager

2
여기서 가장 좋은 솔루션은 "모든 라인의 길이가 같다"는 가정입니다. 골프와 전쟁에서 모두 공정합니다.
hobbs

라인 길이가 동일하지 않은 경우 테스트 케이스를 추가합니다. 그러나 나는 명확하게 :) 의도적했다
LiraNuna

9

골프 스크립트 (83 자)

안녕하세요, ibble 블러!

:\'><v^'.{\?}%{)}?:P@=?{:O[1-1\10?).~)]=P+
:P\=' \/x'?[O.2^.1^'true''false']=.4/!}do

3
golfscript : perl ~ = 1 : 1.7
John La Rooy

9

파이썬-152

"L"이라는 파일에서 입력을 읽습니다.

A=open("L").read()
W=A.find('\n')+1
D=P=-1
while P<0:D+=1;P=A.find(">^<v"[D])
while D<4:P+=[1,-W,-1,W][D];D=[D,D^3,D^1,4,5][' \/x'.find(A[P])]
print D<5

stdin에서 읽으려면 첫 번째 줄을 다음으로 바꿉니다.

import os;A=os.read(0,1e9)

소문자 true / false가 필요한 경우 마지막 행을 다음으로 변경하십시오.

print`D<5`.lower()

얼마나 많은 문자가 변화에 걸립니까 TruetrueFalsefalse? ;-)
mob

"print D<5"를 "print D <5" 로 변경하여 1자를 제거 할 수 없습니까? 아니면 내가 놓친 것이 있습니까?
Ponkadoodle

@ wallacoloo, 물론 할 수 있습니다. 그것은 단지 소문자 참 / 거짓을 위해 필요한
존 라 Rooy을

7

자바 스크립트-265 자

업데이트 IV- 승률은 마지막 업데이트 라운드이며, do-while 루프로 전환하고 이동 방정식을 다시 작성하여 두 문자를 더 절약 할 수 있습니다.

업데이트 III -Math.abs ()를 제거하고 전역 네임 스페이스에 변수를 배치하는 것과 관련하여 strager의 제안 덕분에 변수 할당의 재배 열과 함께 코드가 282 자로 줄었습니다.

업데이트 II- ! = -1 사용을 제거하기위한 코드에 대한 추가 업데이트와 더 긴 작업을위한 변수 사용 개선.

업데이트 -indexOf 함수에 대한 참조 (LiraNuna 덕분에)에 대한 참조를 작성하고 필요하지 않은 괄호를 제거하여 변경 및 변경을 수행 한 경우

코드 골프를하는 것은 이번이 처음이기 때문에 이것이 얼마나 좋은지 잘 모르겠습니다. 모든 피드백에 감사드립니다.

완전히 최소화 된 버전 :

a;b;c;d;e;function f(g){a=function(a){return g.indexOf(a)};b=a("\n")+1;a=g[c=e=a("v")>0?e:e=a("^")>0?e:e=a("<")>0?e:a(">")];d=a=="<"?-1:a==">"?1:a=="^"?-b:b;do{e=d==-1|d==1;a=g[c+=d=a=="\\"?e?b*d:d>0?1:-1:a=="/"?e?-b*d:d>0?1:-1:d];e=a=="x"}while(a!="#"^e);return e}

주석이있는 원본 버전 :

character; length; loc; movement; temp;
function checkMaze(maze) {
        // Use a shorter indexOf function
        character = function(string) { return maze.indexOf(string); }
        // Get the length of the maze
        length = character("\n") + 1;
        // Get the location of the laser in the string
        character = maze[loc = temp = character("v") > 0 ? temp :
                               temp = character("^") > 0 ? temp :
                               temp = character("<") > 0 ? temp : character(">")];
        // Get the intial direction that we should travel
        movement = character == "<" ? -1 :
                   character == ">" ? 1 :
                   character == "^" ? -length : length;
        // Move along until we reach the end
        do {
            // Get the current character
            temp = movement == -1 | movement == 1;
            character = maze[loc += movement = character == "\\" ? temp ? length * movement : movement > 0 ? 1 : -1 :
                                               character == "/" ? temp ? -length * movement : movement > 0 ? 1 : -1 : movement];                                   
            // Have we hit a target?
            temp = character == "x";
            // Have we hit a wall?
        } while (character != "#" ^ temp);
        // temp will be false if we hit the target
        return temp;
    }

테스트 할 웹 페이지 :

<html>
  <head>
    <title>Code Golf - Lasers</title>
    <script type="text/javascript">
    a;b;c;d;e;function f(g){a=function(a){return g.indexOf(a)};b=a("\n")+1;a=g[c=e=a("v")>0?e:e=a("^")>0?e:e=a("<")>0?e:a(">")];d=a=="<"?-1:a==">"?1:a=="^"?-b:b;do{e=d==-1|d==1;a=g[c+=d=a=="\\"?e?b*d:d>0?1:-1:a=="/"?e?-b*d:d>0?1:-1:d];e=a=="x"}while(a!="#"^e);return e}
    </script>
  </head>
  <body>
    <textarea id="maze" rows="10" cols="10"></textarea>
    <button id="checkMaze" onclick="alert(f(document.getElementById('maze').value))">Maze</button>
  </body>
</html>

어떻게 입력합니까? 이것을 테스트하고 확인하고 싶습니다. 당신이 a.indexOf에 심판을 저장하는 경우 또한, 당신은 문자를 많이 절약 할 수 있습니다
LiraNuna

교체 index != -1와 함께 index > 0하시기 바랍니다! (아무도 아무도 왼쪽 상단에 lazer를 0넣지 않으므로 반환되지 않습니다. =]) var명령문을 연결하거나 제거 할 수 있습니다 (글로벌 네임 스페이스에 변수를 넣음). 나는 Math.abs(m)==1로 대체 될 수 있다고 생각 m==-1|m==1합니다. 에 movement = ...; location += movement최적화 할 수 있습니까 location += movement =?
strager

@ strager- 귀하의 의견을 보았습니다. 코드를 업데이트하는 동안 게시 한 것처럼 보였으며 300 자로 줄었습니다. Math.abs ()를 제거하여 무엇을 할 수 있는지 살펴 보겠습니다.
rjzii

function(a){return g.indexOf(a)}function(a)g.indexOf(a)최신 자바 스크립트 버전 으로 대체 할 수 있습니다 .
user1686 2016 년

6

거울의 집

도전에 대한 실제 입장은 아니지만이 개념을 기반으로 게임을 작성했습니다 (너무 오래되지 않았습니다).

Scala로 작성되었으며 오픈 소스이며 여기에서 사용할 수 있습니다 .

조금 더합니다; 색상 및 다양한 유형의 미러 및 장치를 다루지 만 버전 0.00001은이 문제가 요구하는대로 정확하게 수행했습니다. 나는 그 버전을 잃어 버렸고 어쨌든 문자 수에 최적화되지 않았습니다.


스칼라를 설치하지 않고 Windows에서 작동하는 컴파일 된 버전을 업로드 할 수 있습니까?
밀라노

Scala 라이브러리가 포함 된 버전이 있습니다. 다운로드 목록을보십시오. 그러나 어쨌든, 지금까지 스칼라를 설치했다면, 그렇게하게되어 기쁩니다. :)
HRJ

6

c (K & R) 스 트래 거가 제안한 후 339 개의 필요한 캐릭터.

필자의 물리학자는 전파 및 반사 작업이 시간에 따라 변하지 않기 때문에 대상에서 광선 던져 레이저 방출기에 도달하는지 확인합니다.

구현의 나머지 부분은 매우 직설적이며 이전에 진행 한 노력에서 다소 정확하게 가져옵니다.

압축 :

#define R return
#define C case
#define Z x,y
int c,i,j,m[99][99],Z;s(d,e,Z){for(;;)switch(m[x+=d][y+=e]){C'^':R 1==e;
C'>':R-1==d;C'v':R-1==e;C'<':R 1==d;C'#':C'x':R 0;C 92:e=-e;d=-d;C'/':c=d;
d=-e;e=-c;}}main(){while((c=getchar())>0)c==10?i=0,j++:(c==120?x=i,y=j:
i,m[i++][j]=c);puts(s(1,0,Z)|s(0,1,Z)|s(-1,0,Z)|s(0,-1,Z)?"true":"false");}

비 압축 (ish) :

#define R return
#define C case
#define Z x,y
int c,i,j,m[99][99],Z;
s(d,e,Z)
{
  for(;;)
    switch(m[x+=d][y+=e]){
    C'^': 
      R 1==e;
    C'>': 
      R-1==d;
    C'v': 
      R-1==e;
    C'<': 
      R 1==d;
    C'#':
    C'x':
      R 0;
    C 92:
      e=-e;
      d=-d;
    C'/':
      c=d;
      d=-e;
      e=-c;
    }
}
main(){
  while((c=getchar())>0)
    c==10?i=0,j++:
      (c==120?x=i,y=j:i,m[i++][j]=c);
  puts(s(1,0,Z)|s(0,1,Z)|s(-1,0,Z)|s(0,-1,Z)?"true":"false");
}

입력 유효성 검사가 없으며 잘못된 입력은 무한 루프로 보낼 수 있습니다. 99 x 99 이하의 입력에서 올바르게 작동합니다. 헤더를 포함하지 않고 표준 라이브러리를 링크하는 컴파일러가 필요합니다. 그리고 나는 내가 끝났다고 생각한다. 스 트래 거는 그의 도움으로도 상당히 스트레치했다.

오히려 누군가가 작업을 수행하는 더 미묘한 방법을 보여주기를 바랍니다. 이것에는 아무런 문제가 없지만 깊은 마술은 아닙니다.


=0전역은 기본적으로 0으로 초기화되므로 전역에서 필요하지 않습니다 . 문자 상수를 10 진수로 바꿉니다. EOF (및 ) 를 확인하는 >0대신 사용하십시오 . 내가했던 것처럼 일부 코드를 버릴 수 있습니다 . 추가에 대한 필요 의 등은 어쨌든 개행 문자를 인쇄하지해야합니다. 보다 짧습니다 . 도움이 되었기를 바랍니다. =]!=EOF\0#definecaseif\nputsputsfor(;;)while(1)
strager

@strager : 감사합니다. 내가 그렇게 생각하지 않기 때문에 나는 항상 반복적으로 이것에 온다 ...
dmckee --- 전 운영자 고양이

2
"There is no input validation"-없어야합니다. 골퍼가 쉽게 사용할 수 있도록 달리 명시하지 않는 한 입력은 항상 '깨끗한'것으로 가정합니다.
LiraNuna

@dmckee, 걱정하지 마십시오. Code Golf 전문가들도 반복적으로 작업합니다. 그러나 우리는 일반적으로 처음부터 몇 가지 트릭을 사용하지만 (내가 언급 한 트릭과 같은) 트릭은 경험과 함께 제공됩니다. =]
strager

내가 잘못 계산하지 않는 한, 프로그램은 380자가 아니라 390 자입니다.
strager September

6

루비-146 문자

A=$<.read
W=A.index('
')+1
until
q=A.index(">^<v"[d=d ?d+1:0])
end
while d<4
d=[d,d^3,d^1,4,5][(' \/x'.index(A[q+=[1,-W,-1,W][d]])or 4)]
end
p 5>d

5

포스트 스크립트 , 359 바이트

첫 번째 시도, 개선의 여지가 많습니다 ...

/a[{(%stdin)(r)file 99 string readline not{exit}if}loop]def a{{[(^)(>)(<)(v)]{2
copy search{stop}if pop pop}forall}forall}stopped/r count 7 sub def pop
length/c exch def[(>)0(^)1(<)2(v)3>>exch get/d exch def{/r r[0 -1 0 1]d get
add def/c c[1 0 -1 0]d get add def[32 0 47 1 92 3>>a r get c get .knownget
not{exit}if/d exch d xor def}loop a r get c get 120 eq =

4

Haskell, 395 391 383 361 339 자 (최적화)

여전히 영리한 것이 아니라 일반적인 상태 머신을 사용합니다.

k="<>^v"
o(Just x)=x
s y(h:t)=case b of{[]->s(y+1)t;(c:_)->(c,length a,y)}where(a,b)=break(flip elem k)h
r a = f$s 0 a where f(c,x,y)=case i(a!!v!!u)"x /\\"["true",g k,g"v^><",g"^v<>"]of{Just r->r;_->"false"}where{i x y=lookup x.zip y;j=o.i c k;u=j[x-1,x+1,x,x];v=j[y,y,y-1,y+1];g t=f(j t,u,v)}
main=do{z<-getContents;putStrLn$r$lines z}

읽을 수있는 버전 :

k="<>^v"    -- "key" for direction
o(Just x)=x -- "only" handle successful search
s y(h:t)=case b of  -- find "start" state
  []->s(y+1)t
  (c:_)->(c,length a,y)
 where (a,b)=break(flip elem k)h
r a = f$s 0 a where -- "run" the state machine (iterate with f)
 f(c,x,y)=case i(a!!v!!u)"x /\\"["true",g k,g"v^><",g"^v<>"] of
   Just r->r
   _->"false"
  where
   i x y=lookup x.zip y -- "index" with x using y as key
   j=o.i c k -- use c as index k as key; assume success
   u=j[x-1,x+1,x,x] -- new x coord
   v=j[y,y,y-1,y+1] -- new y coord
   g t=f(j t,u,v) -- recurse; use t for new direction
main=do
 z<-getContents
 putStrLn$r$lines z


3

C ++ : 388

#include<iostream>
#include<string>
#include<deque>
#include<cstring>
#define w v[y][x]
using namespace std;size_t y,x,*z[]={&y,&x};int main(){string p="^v<>",s;deque<string>v;
while(getline(cin,s))v.push_back(s);while(x=v[++y].find_first_of(p),!(x+1));int 
i=p.find(w),d=i%2*2-1,r=i/2;do while(*z[r]+=d,w=='/'?d=-d,0:w==' ');while(r=!r,
!strchr("#x<^v>",w));cout<<(w=='x'?"true":"false");}

( 헤더없는 318 )


작동 방식 :

먼저 모든 라인을 읽은 다음 레이저를 찾습니다. 다음은 0레이저 화살표가 아직 발견되지 않은 x한 수평 위치 에 지정된 시간으로 평가됩니다 .

x=v[++y].find_first_of(p),!(x+1)

그런 다음 찾은 방향을 찾아서 저장합니다 i. 짝수 값 i은 상단 / 왼쪽 ( "감소")이고 홀수 값은 하단 / 오른쪽 ( "증가")입니다. 이 개념에 따라 d( "방향") 및 r( "방향")이 설정됩니다. 우리는 z방향으로 포인터 배열 을 인덱싱 하고 우리가 얻는 정수에 방향을 추가합니다. 슬래시를 칠 경우에만 방향이 바뀌고 백 슬래시를 칠 때도 방향이 동일합니다. 물론 거울에 부딪히면 항상 방향 ( r = !r)이 바뀝니다 .


내 C ++ 솔루션을 직접 만들게합니다. =]
strager

2
@strager, 이것은 지루해지고 있습니다. 컴파일 타임 xD에 "true"또는 "false"를 표시하는 솔루션을 해보자
Johannes Schaub-litb

내가 이것에 그것을 유지할 것이라고 생각하기 때문에 추가 설명 :)
Johannes Schaub-litb

2

그루비 @ 279 캐릭터

m=/[<>^v]/
i={'><v^'.indexOf(it)}
n=['<':{y--},'>':{y++},'^':{x--},'v':{x++}]
a=['x':{1},'\\':{'v^><'[i(d)]},'/':{'^v<>'[i(d)]},'#':{},' ':{d}]
b=[]
System.in.eachLine {b<<it.inject([]) {r,c->if(c==~m){x=b.size;y=r.size;d=c};r<<c}}
while(d==~m){n[d]();d=a[b[x][y]]()}
println !!d

2

씨#

1020 자
1088 자 (콘솔에서 추가 된 입력)
925 자 (리팩터링 된 변수)
875 자 (중복 사전 이니셜 라이저 제거, 이진 및 연산자로 변경)

게시하기 전에 다른 사람을 보지 않도록 포인트를 만들었습니다. 나는 그것이 약간 LINQ 될 수 있다고 확신합니다. 그리고 읽기 가능한 버전의 전체 FindLaser 메소드는 나에게 비린 것처럼 보입니다. 그러나 작동하고 늦었습니다 :)

읽기 가능한 클래스에는 레이저가 움직일 때 현재 Arena를 인쇄하는 추가 메소드가 포함되어 있습니다.

class L{static void Main(){
A=new Dictionary<Point,string>();
var l=Console.ReadLine();int y=0;
while(l!=""){var a=l.ToCharArray();
for(int x=0;x<a.Count();x++)
A.Add(new Point(x,y),l[x].ToString());
y++;l=Console.ReadLine();}new L();}
static Dictionary<Point,string>A;Point P,O,N,S,W,E;
public L(){N=S=W=E=new Point(0,-1);S.Offset(0,2);
W.Offset(-1,1);E.Offset(1,1);D();
Console.WriteLine(F());}bool F(){
var l=A[P];int m=O.X,n=O.Y,o=P.X,p=P.Y;
bool x=o==m,y=p==n,a=x&p<n,b=x&p>n,c=y&o>m,d=y&o<m;
if(l=="\\"){if(a)T(W);if(b)T(E);if(c)T(S);
if(d)T(N);if(F())return true;}
if(l=="/"){if(a)T(E);if(b)T(W);if(c)T(N);
if(d)T(S);if(F())return true;}return l=="x";}
void T(Point p){O=P;do P.Offset(p);
while(!("\\,/,#,x".Split(',')).Contains(A[P]));}
void D(){P=A.Where(x=>("^,v,>,<".Split(',')).
Contains(x.Value)).First().Key;var c=A[P];
if(c=="^")T(N);if(c=="v")T(S);if(c=="<")T(W);
if(c==">")T(E);}}

읽을 수있는 버전 (최종 골프 버전은 아니지만 동일한 전제) :

class Laser
{
    private Dictionary<Point, string> Arena;
    private readonly List<string> LaserChars;
    private readonly List<string> OtherChars;

    private Point Position;
    private Point OldPosition;
    private readonly Point North;
    private readonly Point South;
    private readonly Point West;
    private readonly Point East;

    public Laser( List<string> arena )
    {
        SplitArena( arena );
        LaserChars = new List<string> { "^", "v", ">", "<" };
        OtherChars = new List<string> { "\\", "/", "#", "x" };
        North = new Point( 0, -1 );
        South = new Point( 0, 1 );
        West = new Point( -1, 0 );
        East = new Point( 1, 0 );
        FindLaser();
        Console.WriteLine( FindTarget() );
    }

    private void SplitArena( List<string> arena )
    {
        Arena = new Dictionary<Point, string>();
        int y = 0;
        foreach( string str in arena )
        {
            var line = str.ToCharArray();
            for( int x = 0; x < line.Count(); x++ )
            {
                Arena.Add( new Point( x, y ), line[x].ToString() );
            }
            y++;
        }
    }

    private void DrawArena()
    {
        Console.Clear();
        var d = new Dictionary<Point, string>( Arena );

        d[Position] = "*";
        foreach( KeyValuePair<Point, string> p in d )
        {
            if( p.Key.X == 0 )
                Console.WriteLine();

            Console.Write( p.Value );
        }
        System.Threading.Thread.Sleep( 400 );
    }

    private bool FindTarget()
    {
        DrawArena();

        string chr = Arena[Position];

        switch( chr )
        {
            case "\\":
                if( ( Position.X == Position.X ) && ( Position.Y < OldPosition.Y ) )
                {
                    OffSet( West );
                }
                else if( ( Position.X == Position.X ) && ( Position.Y > OldPosition.Y ) )
                {
                    OffSet( East );
                }
                else if( ( Position.Y == Position.Y ) && ( Position.X > OldPosition.X ) )
                {
                    OffSet( South );
                }
                else
                {
                    OffSet( North );
                }
                if( FindTarget() )
                {
                    return true;
                }
                break;
            case "/":
                if( ( Position.X == Position.X ) && ( Position.Y < OldPosition.Y ) )
                {
                    OffSet( East );
                }
                else if( ( Position.X == Position.X ) && ( Position.Y > OldPosition.Y ) )
                {
                    OffSet( West );
                }
                else if( ( Position.Y == Position.Y ) && ( Position.X > OldPosition.X ) )
                {
                    OffSet( North );
                }
                else
                {
                    OffSet( South );
                }
                if( FindTarget() )
                {
                    return true;
                }
                break;
            case "x":
                return true;
            case "#":
                return false;
        }
        return false;
    }

    private void OffSet( Point p )
    {
        OldPosition = Position;
        do
        {
            Position.Offset( p );
        } while( !OtherChars.Contains( Arena[Position] ) );
    }

    private void FindLaser()
    {
        Position = Arena.Where( x => LaserChars.Contains( x.Value ) ).First().Key;

        switch( Arena[Position] )
        {
            case "^":
                OffSet( North );
                break;
            case "v":
                OffSet( South );
                break;
            case "<":
                OffSet( West );
                break;
            case ">":
                OffSet( East );
                break;
        }
    }
}

2
프로그램은 입력을 받아야합니다. 가장 일반적으로 stdin에서.
LiraNuna

0

219 펄
내 펄 버전입니다 392 : (I 레이저 타격 빔의 경우 처리했다) 길이 342 문자를
업데이트 나에게 상기시켜, 감사 홉스를 tr//지금 250 자입니다 :
업데이트 의 제거 mm//두 변경 while가져 루프를 약간의 절약; 이제 필요한 공간이 하나뿐입니다.
( L:it;goto L와 길이가 같습니다 do{it;redo}) :

@b=map{($y,$x,$s)=($a,$-[0],$&)if/[<>^v]/;$a++;[split//]}<>;L:$_=$s;$x++if/>/;
$x--if/</;$y++if/v/;$y--if/\^/;$_=$b[$y][$x];die"true\n"if/x/;die"false\n"if
/[<>^v#]/;$s=~tr/<>^v/^v<>/if/\\/;$s=~tr/<>^v/v^></if/\//;goto L

나는 일부를 깎았 지만 늦었지만 그럼에도 불구하고 일부와 거의 경쟁 하지 않습니다.
다음과 같이 조금 나아 보입니다.

#!/usr/bin/perl
@b = map {
    ($y, $x, $s) = ($a, $-[0], $&) if /[<>^v]/;
    $a++;
    [split//]
} <>;
L:
    $_ = $s;
    $x++ if />/;
    $x-- if /</;
    $y++ if /v/;
    $y-- if /\^/;
    $_ = $b[$y][$x];
    die "true\n"  if /x/;
    die "false\n" if /[<>^v#]/;
    $s =~ tr/<>^v/^v<>/ if /\\/;
    $s =~ tr/<>^v/v^></ if /\//;
goto L

글쎄 ... 솔직히 이것은 @b각 줄에 문자의 배열 배열이며 간단한 정규 표현식과 tr문장을 읽을 수 있다는 것을 이해하면 자명해야합니다 .


팁 : 미러 코드를 단축 할 수 있습니다. $_=$s;tr/^v<>/<>^v/그리고 $_=$s;tr/v^<>/<>^v/각각. 또한 min이 필요하지 않습니다 m//.
hobbs

죄송합니다, 그 두 번째 만들기$_=$s;tr/v^></<>^v/;
홉스

두 문자를 팝 if m/.../으로 if/.../저장할 수있는 문자 가 여전히 있습니다 .
hobbs

y///대신 tr///두 문자를 저장할 수 있습니다 .
Platinum Azure

0

F #-454 (또는 그 주변)

게임에 늦었지만 내 2D 시도 게시에 저항 할 수는 없습니다.

업데이트는 약간 수정했습니다. 트랜스미터에 맞으면 이제 정확하게 멈 춥니 다. IndexOfAny에 대한 Brian의 아이디어를 꼬집었습니다 (그 줄은 너무 장황합니다). 실제로 콘솔에서 ReadToEnd를 반환하는 방법을 실제로 관리하지 못했기 때문에 그 비트를 신뢰하고 있습니다 ...

이 답변은 매우 짧지 만 여전히 읽을 수있는 것처럼 기쁘게 생각합니다.

let s=System.Console.In.ReadToEnd()       //(Not sure how to get this to work!)
let w=s.IndexOf('\n')+1                   //width
let h=(s.Length+1)/w                      //height
//wodge into a 2d array
let a=Microsoft.FSharp.Collections.Array2D.init h (w-1)(fun y x -> s.[y*w+x])
let p=s.IndexOfAny[|'^';'<';'>';'v'|]     //get start pos
let (dx,dy)=                              //get initial direction
 match "^<>v".IndexOf(s.[p]) with
 |0->(0,-1)
 |1->(-1,0)
 |2->(1,0)
 |_->(0,1)
let mutable(x,y)=(p%w,p/w)                //translate into x,y coords
let rec f(dx,dy)=
 x<-x+dx;y<-y+dy                          //mutate coords on each call
 match a.[y,x] with
 |' '->f(dx,dy)                           //keep going same direction
 |'/'->f(-dy,-dx)                         //switch dx/dy and change sign
 |'\\'->f(dy,dx)                          //switch dx/dy and keep sign
 |'x'->"true"
 |_->"false"
System.Console.Write(f(dx,dy))

그들은 장식입니다. 다른 도전 과제를 확인하십시오. 포맷 일뿐입니다.
LiraNuna

@ LiraNuna, 알았어, 알다시피,이 반복은 어쨌든 그들을 먹습니다 :)
Benjol

1-d 구현과 비교하면 좋을 것입니다. 왼쪽과 오른쪽에 1을 더하거나 빼고 위아래에 w를 더하거나 빼기 만하면됩니다. 나는 당신이 꽤 많은 문자를 절약 할 것으로 기대합니다
John La Rooy

@ gnibbler, Brian은 이미 그렇게했습니다. 나는 그를 이길 수 있는지 확실하지 않지만 시도해 볼 수도 있습니다.
Benjol
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.