Mã Golf: Laser


152

Các thách thức

Mã ngắn nhất theo số ký tự để nhập đại diện 2D của bảng và xuất ra 'true' hoặc 'false' theo đầu vào .

Bảng được làm từ 4 loại gạch:

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

Chỉ có một tia laser và chỉ có một mục tiêu . Tường phải tạo thành một hình chữ nhật rắn có kích thước bất kỳ, trong đó tia laser và mục tiêu được đặt bên trong. Tường trong 'phòng' là có thể.

Tia laser bắn và đi từ điểm gốc của nó tới hướng nó đang chỉ. Nếu một tia laser chiếu vào tường, nó dừng lại. Nếu một tia laser chiếu vào gương, nó sẽ phản xạ 90 độ theo hướng mà gương hướng tới. Gương có hai mặt, nghĩa là cả hai mặt đều 'phản chiếu' và có thể nảy một tia theo hai cách. Nếu một tia laser tự chiếu vào tia laser ( ^v><), nó được coi như một bức tường (tia laser phá hủy chùm tia và do đó nó sẽ không bao giờ bắn trúng mục tiêu).

Các trường hợp thử nghiệm

Đầu vào:
    ##########
    # / \ #
    # #
    # \ x #
    #> / #
    ########## 
Đầu ra:
    thật

Đầu vào:
    ##########
    # vx #
    # / #
    # / #
    # \ #
    ##########
Đầu ra:    
    sai

Đầu vào:
    #############
    # # #
    #> # #
    # # #
    # # x #
    # # #
    #############
Đầu ra:
    sai

Đầu vào:
    ##########
    # / \ / \ / \ #
    # \\ // \\\ #
    # // \ / \ / \\ #
    # \ / \ / \ / x ^ #
    ##########
Đầu ra:
    thật

Số lượng mã bao gồm đầu vào / đầu ra (tức là chương trình đầy đủ).


84
IMMA CHARGIN 'MAH LAZER!
Chờ đợi Ólafur

37
Điều này thật tuyệt vời .
GManNickG

33
ĐỪNG
CHIA SẺ CÁC BÉ

49
@GameFreak: Điều đó thực sự cũ.
Artelius

24
Đó có phải là '^' thực sự là một con cá mập với một kẻ lười biếng trên đầu không?
Nathan Feger

Câu trả lời:


78

Perl, 166 160 ký tự

Perl, 251 248 246 222 214 208 203 201 193 190 180 176 173 170 166 -> 160 ký tự.

Giải pháp có 166 nét khi cuộc thi này kết thúc, nhưng A. Rex đã tìm ra một vài cách để loại bỏ thêm 6 nhân vật:

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,$/

Dòng đầu tiên tải đầu vào vào %t, một bảng của bảng $t{99*i+j}chứa ký tự ở hàng i , cột j . Sau đó,

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

nó tìm kiếm các phần tử của %tmột ký tự khớp > ^ <hoặc v, đồng thời đặt $dthành giá trị từ 0 đến 3 cho biết hướng ban đầu của chùm tia laser.

Vào đầu mỗi lần lặp trong vòng lặp chính, chúng tôi cập nhật $dnếu chùm sáng hiện trên gương. XOR'ing by 3 đưa ra hành vi đúng cho \gương và XOR'ing by 1 đưa ra hành vi đúng cho /gương.

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

Tiếp theo, vị trí hiện tại $rđược cập nhật theo hướng hiện tại.

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

Chúng tôi chỉ định nhân vật ở vị trí hiện tại để $_sử dụng thuận tiện cho các toán tử khớp.

/[\/\\ ]/ && redo

Tiếp tục nếu chúng ta ở trên một không gian trống hoặc một nhân vật gương. Nếu không, chúng tôi chấm dứt truenếu chúng tôi đang ở trên mục tiêu ( $_ =~ /x/) và falsenếu không.

Giới hạn: có thể không hoạt động trên các vấn đề với hơn 99 cột. Giới hạn này có thể được loại bỏ với chi phí thêm 3 ký tự,


Được rồi, có tới 323 ký tự. = D
strager

5
Tôi có thể thay đổi 99 thành 1E5 để làm cho nó rất mạnh mẽ với chi phí là 3 ký tự.
mob

2
Giải pháp tốt nhất của bạn sẽ được chú ý hơn ở đầu bài.
strager

13
Nhưng sử dụng biểu thức thông thường để xoay bảng? Đó là bệnh. Điều đó giống như một phần thưởng 20 đột quỵ tự động.
mob

1
@mobrule: Lưu sáu nét: sắp xếp lại dòng đầu tiên dưới dạng s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;, thay đổi %d=split//,.." to % d = .. = ~ /./ g , and change grep {..}% t` thànhgrep..,%t
A. Rex

75

Perl, 177 ký tự

Dòng đầu tiên có thể được gỡ bỏ; hai cái còn lại là bắt buộc.

$/=%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}

Giải trình:

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

Nếu một chùm chuyển động phải chạy vào {không gian trống, gương hướng lên, gương hướng xuống} thì nó sẽ trở thành {chùm chuyển động phải, chùm chuyển động lên, chùm chuyển động xuống}. Khởi tạo $/trên đường đi - may mắn thay "6" không phải là một char đầu vào hợp lệ.

$_ = <>;

Đọc bảng vào $_.

$s="#";

$slà biểu tượng của bất cứ thứ gì mà chùm tia đang ngồi trên đầu bây giờ. Vì bộ phát laser sẽ được coi như một bức tường, hãy đặt nó thành một bức tường để bắt đầu.

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

Nếu chùm tia laser đang chỉ bất kỳ cách nào ngoại trừ bên phải, hãy xoay biểu tượng của nó, sau đó xoay toàn bộ bảng tại chỗ (cũng xoay các biểu tượng cho gương). Đó là một góc xoay trái 90 độ, được thực hiện một cách hiệu quả bằng cách đảo ngược các hàng trong khi hoán đổi các hàng và cột, trong một chút sai lầm s///evới các tác dụng phụ. Trong mã đánh gôn, tr được viết dưới dạng y'''cho phép tôi bỏ qua dấu gạch chéo ngược một dấu gạch chéo ngược.

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

Chấm dứt với thông điệp phù hợp nếu chúng ta bắn trúng mục tiêu hoặc một bức tường.

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

Nếu có một khoảng trống phía trước tia laser, hãy tiến về phía trước. Nếu có một tấm gương ở phía trước tia laser, hãy tiến về phía trước và xoay chùm tia. Trong cả hai trường hợp, đặt "biểu tượng đã lưu" trở lại vị trí chùm cũ và đặt thứ chúng ta vừa ghi đè lên biểu tượng đã lưu.

redo;

Lặp lại cho đến khi chấm dứt. {...;redo}là hai ký tự ít hơn for(;;){...}và ba ít hơn while(1){...}.


4
Xoay bảng ... Crazy. Tái chế ... Crazier. O_o
strager

39
Bạn ... Bạn quái vật!
LiraNuna

4
LiraNuna: Tôi chọn coi đó là một lời khen.
hobbs

21
Sân golf đã kết thúc. Làm thế nào bạn có thể đánh bại xoay một bảng 2D với các biểu thức thông thường?!
Konrad Rudolph

13
wtf? lập trình viên perl là phù thủy.
Julian Schaub - litb

39

C89 (209 ký tự)

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

Giải trình

Sự quái dị này có lẽ sẽ khó theo dõi nếu bạn không hiểu C. Chỉ là một lời cảnh báo trước.

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

Macro nhỏ này kiểm tra xem ký tự hiện tại ( *p) có bằng bất cứ thứ gì aở dạng ký tự ( *#a) không. Nếu chúng bằng nhau, đặt vectơ chuyển động thành b( m=b), đánh dấu ký tự này là tường ( *p=1) và đặt điểm bắt đầu thành vị trí hiện tại ( q=p). Macro này bao gồm phần "khác".

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

Khai báo một số biến. * qlà vị trí hiện tại của ánh sáng. * Glà bảng trò chơi dưới dạng mảng 1D. * plà vị trí đọc hiện tại khi dân cư G. * wlà chiều rộng của bảng.

main(m){

Rõ ràng main. mlà một biến lưu trữ các vectơ chuyển động. (Đây là một tham số để maintối ưu hóa.)

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

Lặp lại tất cả các ký tự, Gsử dụng p. Bỏ qua G[0]như một tối ưu hóa (không cần lãng phí một ký tự viết plại trong phần thứ ba của for).

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

Sử dụng macro đã nói ở trên để xác định lazer, nếu có thể. -11tương ứng với trái và phải, tương ứng, -wwlên và xuống.

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

Nếu ký tự hiện tại là điểm đánh dấu cuối dòng (ASCII 10), hãy đặt độ rộng nếu nó chưa được đặt. Việc bỏ qua G[0]cho phép chúng tôi viết w=p-Gthay vì w=p-G+1. Ngoài ra, điều này kết thúc ?:chuỗi từ M's.

    for(;
        q+=m,

Di chuyển ánh sáng bằng vectơ chuyển động.

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

Phản ánh vectơ chuyển động.

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

Nếu đây là một bức tường hoặc x, thoát với thông điệp thích hợp ( m=0chấm dứt vòng lặp). Nếu không, không làm gì cả (noop; m=m)

    );
}

8
Ừ! Tôi đang làm việc trên một giải pháp C thì chuông báo cháy vang lên trong khu chung cư của tôi. Bây giờ tôi đã đánh bại. Giải pháp tốt đẹp mặc dù.
rlbond

Methinks sử dụng biến tạm thời cho các bước hoán đổi và hoán đổi / phủ định của bạn sẽ giúp bạn tiết kiệm được một vài ký tự.
Artelius

@Artelius, Vâng, tôi nhận ra điều đó, và một vài thứ khác. Cảm ơn.
strager

1
TCC thực sự không thích các khai báo và lỗi chưa được xử lý với g.c:3: declaration expected:(
Mark Rushakoff

2
Xóa bỏ putstuyên bố đã giúp, nhưng không đủ để đưa nó dưới 170. 209 là khá tốt, vì vậy tôi nghĩ rằng tôi sẽ để nó ở đó. Cảm ơn sự giúp đỡ của các bạn. Tôi rất trân trọng điều này. =] (Bất cứ điều gì để truất ngôi những phù thủy Perl đó!)
strager

36

Tôi cá là mọi người đã chờ đợi điều này trong một thời gian LOOOOONG. (Ý bạn là gì, thử thách đã kết thúc và không ai quan tâm nữa?)

Kìa ... tôi ở đây trình bày một giải pháp trong

Befunge-93!

Nó nặng tới 973 charaters (hoặc 688 nếu bạn đủ từ thiện để bỏ qua khoảng trắng, vốn chỉ được sử dụng để định dạng và không có gì trong mã thực tế).

Hãy cẩn thận : Tôi đã viết trình thông dịch Befunge-93 của riêng tôi ở Perl cách đây không lâu, và thật không may, đây là tất cả những gì tôi thực sự có thời gian để kiểm tra nó. Tôi hoàn toàn tin tưởng vào tính chính xác của nó nói chung, nhưng nó có thể có một hạn chế kỳ lạ liên quan đến EOF: Vì <>toán tử của Perl trả về undef ở cuối tệp, nên điều này được xử lý là 0 trong ngữ cảnh số. Đối với các triển khai dựa trên C trong đó EOF có giá trị khác (-1 nói), mã này có thể không hoạt động.

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"\:"<"\: "^"   -!#^_-!#^_-!      ^
               >                       ^

Giải trình

Nếu bạn không quen với cú pháp và thao tác Befunge, hãy kiểm tra tại đây .

Befunge là ngôn ngữ dựa trên ngăn xếp, nhưng có các lệnh cho phép một người viết các ký tự vào mã Befunge. Tôi tận dụng điều đó ở hai nơi. Đầu tiên, tôi sao chép toàn bộ đầu vào vào bảng Befunge, nhưng đặt một vài dòng bên dưới mã viết thực tế. (Tất nhiên, điều này không bao giờ thực sự hiển thị khi mã chạy.)

Một nơi khác nằm gần phía trên bên trái:

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

Trong trường hợp này, khu vực tôi đã nêu ở trên là nơi tôi lưu trữ một vài tọa độ. Cột đầu tiên ở hàng giữa có nơi tôi lưu trữ tọa độ x cho "vị trí con trỏ" hiện tại; cột thứ hai là nơi tôi lưu trữ tọa độ y; hai cột tiếp theo là để lưu trữ tọa độ x và y của nguồn tia laser khi tìm thấy; và cột cuối cùng (có ký tự 'a' trong đó) cuối cùng được ghi đè để chứa hướng chùm tia hiện tại, điều này rõ ràng thay đổi khi đường đi của chùm tia được vạch ra.

Chương trình bắt đầu bằng cách đặt (0,27) làm vị trí con trỏ ban đầu. Sau đó, đầu vào được đọc một ký tự tại một thời điểm và được đặt ở vị trí con trỏ; dòng mới chỉ làm cho tọa độ y tăng và tọa độ x trở về 0, giống như trở về vận chuyển thực sự. Cuối cùng, undef được đọc bởi trình thông dịch và giá trị 0 ký tự được sử dụng để báo hiệu kết thúc đầu vào và chuyển sang các bước lặp laser. Khi ký tự laser [<> ^ v] được đọc, nó cũng được sao chép vào kho lưu trữ bộ nhớ (qua ký tự 'a') và tọa độ của nó được sao chép sang các cột ở bên trái.

Kết quả cuối cùng của tất cả những điều này là toàn bộ tệp về cơ bản được sao chép vào mã Befunge, một chút cách bên dưới mã thực tế đi qua.

Sau đó, vị trí chùm tia được sao chép lại vào các vị trí con trỏ và việc lặp lại sau đây được thực hiện:

  • Kiểm tra hướng chùm hiện tại và tăng hoặc giảm tọa độ con trỏ một cách thích hợp. (Tôi làm điều này trước tiên để tránh phải xử lý trường hợp góc của chùm tia laser ngay trong lần di chuyển đầu tiên.)
  • Đọc nhân vật ở vị trí đó.
  • Nếu ký tự là "#", hãy đặt dòng mới và "false" vào ngăn xếp, in và kết thúc.
  • So sánh nó với tất cả các ký tự chùm [<> ^ v]; nếu có một trận đấu, cũng in "false \ n" và kết thúc.
  • Nếu nhân vật là một khoảng trắng, làm trống ngăn xếp và tiếp tục.
  • Nếu ký tự là một dấu gạch chéo về phía trước, hãy lấy hướng chùm tia lên ngăn xếp và so sánh nó với từng ký tự hướng. Khi tìm thấy một hướng, hướng mới được lưu trữ tại cùng một điểm trong mã và vòng lặp lặp lại.
  • Nếu ký tự là dấu gạch chéo ngược, về cơ bản thực hiện tương tự như ở trên (ngoại trừ ánh xạ thích hợp cho dấu gạch chéo ngược).
  • Nếu nhân vật là 'x', chúng tôi đã đạt được mục tiêu. In "true \ n" và thoát.
  • Nếu ký tự không có gì trong số này, hãy in "error \ n" và thoát.

Nếu có đủ nhu cầu cho nó, tôi sẽ cố gắng chỉ ra chính xác nơi mà mã này được thực hiện.


14
+1 - Chỉ vì có thể bị hiểu sai là EXE được mở trong notepad.
Kyle Rosendo

1
Ừm ... thánh ****. Tôi đã nhầm lẫn với Befunge, và điều này thực sự, thực sự ấn tượng.
Almo

Mã golf trong các ngôn ngữ bị xáo trộn ... như bơ đậu phộng và cayenne!
dâu

29

F #, 36 dòng, rất dễ đọc

Ok, chỉ để có được một câu trả lời ngoài đó:

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    

Mẫu:

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

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

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

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

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

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

54
TÔI CÓ THỂ THỰC SỰ ĐỌC MỘT NÀY! PHONG CÁCH!
Jeff Atwood

17
Golf mã Java / C # được tính bằng các dòng không phải ký tự. Đó là sự bất lợi.
Nathan Feger

3
@strager nó không bị giảm trong 3 năm khi bạn được thuê để duy trì mã và nhà phát triển ban đầu đã rời đi từ lâu.
Nathan Feger

Điều này không sử dụng F # trong Visual Studio 2010. Seq.to_list không tồn tại (ok, đã đổi nó thành List), và sau đó là Dòng 25, khớp mẫu không hoàn chỉnh.
Russell

2
Có, thay đổi to_list thành ListList ngay. Cảnh báo trận đấu không đầy đủ là tốt; đó là mã golf, vì vậy tôi đã không làm mã như: | _ -> failwith "không thể"
Brian

29

Golfscript - 83 ký tự (mashup của tôi và strager)

Dòng mới chỉ ở đây để gói

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

Golfscript - 107 ký tự

Dòng mới chỉ ở đó cho rõ ràng

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

Làm thế nào nó hoạt động.

Dòng đầu tiên làm việc ra vị trí và hướng ban đầu.
Dòng thứ hai bước qua xoay bất cứ khi nào tia laser chạm vào gương.


18

353 ký tự trong Ruby:

314 277 ký tự ngay bây giờ!

OK, 256 ký tự trong Ruby và bây giờ tôi đã hoàn thành. Số tròn đẹp để dừng lại ở. :)

247 ký tự. Tôi không thể dừng lại.

223 203 201 ký tự trong Ruby

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

Với khoảng trắng:

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

Hơi tái cấu trúc:

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

Nhưng ... bạn có thể đổi tên chthành Choặc bất kỳ chữ cái char nào khác để lưu 2 ký tự!
LiraNuna

Ok ok, tốt ... Tôi thực sự nhận ra rằng toàn bộ biến là không cần thiết vì tôi chỉ sử dụng nó một lần. Điều này và một vài cải tiến khác đã đưa nó xuống còn 247 ký tự.
Jeremy Ruten

1
Không i++(thay vì i+=1)?
LiraNuna

6
Không. Bạn có thể làm ++ i, nhưng nó chỉ làm cho nó thực sự tích cực như trước đây.
DigitalRoss

Tôi thích phiên bản nén: #; p
SeanJA

17

Con trăn

294 277 253 240 232 ký tự bao gồm cả dòng mới:

(ký tự đầu tiên trong dòng 4 và 5 là một tab, không phải khoảng trắng)

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

Tôi đã quên Python thậm chí có dấu chấm phẩy tùy chọn.

Làm thế nào nó hoạt động

Ý tưởng chính đằng sau mã này là sử dụng các số phức để biểu diễn các vị trí và hướng. Các hàng là trục tưởng tượng, tăng dần xuống. Các cột là trục thực, tăng sang phải.

l='>v<^';một danh sách các ký hiệu laser. Thứ tự được chọn sao cho chỉ số của một ký tự hướng laser tương ứng với sức mạnh của sqrt (-1)

x={'/':'^<v>','\\':'v>^<',' ':l};một bảng biến đổi xác định hướng thay đổi khi chùm tia rời các ô khác nhau. Ngói là chìa khóa, và hướng mới là các giá trị.

b=[1];giữ bảng. Phần tử đầu tiên là 1 (đánh giá là đúng) để vòng lặp while sẽ chạy ít nhất một lần.

r=p=0 rlà số hàng hiện tại của đầu vào, plà vị trí hiện tại của chùm tia laser.

while b[-1]: dừng tải dữ liệu bảng khi raw_input trả về một chuỗi trống

b+=[raw_input()];r+=1 nối dòng đầu vào tiếp theo vào bảng và tăng bộ đếm hàng

for g in l: đoán lần lượt từng hướng laser

c=b[r].find(g) đặt cột thành vị trí của tia laser hoặc -1 nếu nó không nằm trong đường thẳng (hoặc đang chỉ theo một hướng khác)

if-1<c:p=c+1j*r;d=gnếu chúng tôi tìm thấy một tia laser, sau đó đặt vị trí pvà hướng hiện tại d. dlà một trong những ký tự trongl

Sau khi nạp bảng vào b, vị trí pvà hướng hiện tại dđã được đặt thành các vị trí của nguồn laser.

while' '<d: không gian có giá trị ASCII thấp hơn bất kỳ ký hiệu hướng nào, vì vậy chúng tôi sử dụng nó làm cờ dừng.

z=l.find(d);chỉ số của char hướng hiện tại trong lchuỗi. zđược sử dụng sau này để xác định hướng chùm tia mới bằng cách sử dụng xbảng và để tăng vị trí.

p+=1j**z;tăng vị trí sử dụng sức mạnh của i. Ví dụ: l.find('<')==2-> i ^ 2 = -1, sẽ di chuyển sang một cột bên trái.

c=b[int(p.imag)][int(p.real)]; đọc char ở vị trí hiện tại

d=x.get(c,' '*4)[z]tìm hướng mới cho chùm tia trong bảng biến đổi. Nếu char hiện tại không tồn tại trong bảng, sau đó đặt dthành không gian.

print'#'<c in sai nếu chúng tôi dừng lại trên bất cứ thứ gì khác ngoài mục tiêu.


9
p+=1j**z: Thật ngọt ngào.
dmckee --- ex-moderator mèo con

16

Đây một cổng trực tiếp của giải pháp của Brian C # 3, trừ giao diện điều khiển tương tác. Đây không phải là một mục trong thử thách vì nó không phải là một chương trình hoàn chỉnh, tôi chỉ tự hỏi làm thế nào một số cấu trúc F # mà anh ấy sử dụng có thể được thể hiện trong 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};
    }
}

Chỉnh sửa: Sau một số thử nghiệm, mã tìm kiếm khá dài dòng sau đây:

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

đã được thay thế bằng một số mã LINQ to Object nhỏ gọn hơn nhiều:

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

8
Chúa ơi. Thật là một ví dụ hay để chứng minh linq và c # hùng mạnh đã trở thành như thế nào. 1+ cho tôi là một fan hâm mộ c # lớn. x)
Emiswelt

16

F #, 255 ký tự (và vẫn còn dễ đọc hơn!):

Ok, sau một đêm nghỉ ngơi, tôi đã cải thiện điều này rất nhiều:

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])

Hãy nói chuyện qua từng dòng một.

Đầu tiên, hãy nhét tất cả đầu vào vào một mảng lớn một chiều (mảng 2D có thể không tốt cho môn đánh gôn, chỉ cần sử dụng mảng 1D và cộng / trừ độ rộng của một dòng vào chỉ mục để di chuyển lên / xuống một dòng).

Tiếp theo, chúng tôi tính toán 'w', chiều rộng của một dòng đầu vào và 'c', vị trí bắt đầu, bằng cách lập chỉ mục vào mảng của chúng tôi.

Bây giờ, hãy xác định hàm 'tiếp theo' n ', có vị trí hiện tại' c 'và hướng' d 'là 0,1,2,3 cho lên, trái, phải, xuống.

Chỉ số-epsilon 'e' và what-new-direction-if-we-hit-a-slash 's' được tính bằng một bảng. Ví dụ: nếu hướng hiện tại 'd' là 0 (lên), thì phần tử đầu tiên của bảng cho biết "-w, 2" có nghĩa là chúng ta giảm chỉ số theo w và nếu chúng ta nhấn một dấu gạch chéo thì hướng mới là 2 (đúng).

Bây giờ chúng ta lặp lại hàm tiếp theo 'n' với (1) chỉ mục tiếp theo ("c + e" - hiện tại cộng với epsilon) và (2) hướng mới, mà chúng ta tính toán bằng cách nhìn về phía trước để xem những gì trong mảng trong tế bào tiếp theo. Nếu char lookahead là một dấu gạch chéo, hướng mới là 's'. Nếu đó là dấu gạch chéo ngược, hướng mới là 3 giây (lựa chọn mã hóa 0123 của chúng tôi làm cho công việc này). Nếu đó là một không gian, chúng ta sẽ tiếp tục đi theo cùng một hướng 'd'. Và nếu đó là bất kỳ nhân vật nào khác 'c', thì trò chơi kết thúc, in 'đúng' nếu char là 'x' và sai khác.

Để khởi động mọi thứ, chúng tôi gọi hàm đệ quy 'n' với vị trí ban đầu 'c' và hướng bắt đầu (mã hóa hướng ban đầu thành 0123).

Tôi nghĩ rằng tôi có thể vẫn có thể loại bỏ một vài nhân vật nữa, nhưng tôi khá hài lòng với nó như thế này (và 255 là một con số đẹp).


11

Có trọng lượng 18203 ký tự là một giải pháp Python có thể:

  • đối phó với gương bên ngoài 'căn phòng'
  • tính toán quỹ đạo khi không có 'phòng' trên cơ sở giới hạn 2D (thông số kỹ thuật nói rất nhiều về những gì phải có trong 'phòng' nhưng không phải là nếu phòng phải tồn tại)
  • báo cáo lại lỗi

Nó vẫn cần được dọn dẹp phần nào và tôi không biết liệu vật lý 2D có cho rằng chùm tia không thể tự vượt qua ...

#!/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()

Một tập lệnh bash để hiển thị báo cáo lỗi màu:

#!/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#
#\\^/\\ /  #
##########"

Các unittests được sử dụng trong phát triển:

#!/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
Vật lý laser ra lệnh rằng chùm tia có thể tự xuyên qua. Các bình luận ở trên là một tài liệu tham khảo văn hóa quan trọng.
dmckee --- ex-moderator mèo con

5
Rùa và phương pháp tiếp cận Hare để mã golf. Cung cấp một cái gì đó với quá nhiều ký tự (nhiều hơn 91 lần so với người chiến thắng hiện tại) nhưng chú ý đến từng chữ cái của thông số kỹ thuật. Chậm và ổn định thường làm cho tôi ít hợp đồng làm việc mặc dù.
Metalshark

Unittest của bạn dường như đang thiếu một phần. Nó bị cắt ở "self.NOT_DIRECTIO"
BioGeek

@BioGeek - đạt giới hạn về độ dài bài đăng;). Bên cạnh các bài kiểm tra phong cách BASH cho thấy màu sắc nổi bật.
Metalshark

11

Ruby, 176 ký tự

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}

Tôi đã sử dụng một máy trạng thái đơn giản (như hầu hết các áp phích), không có gì lạ mắt. Tôi chỉ tiếp tục sử dụng mọi thủ thuật mà tôi có thể nghĩ ra. XOR bitwise được sử dụng để thay đổi hướng (được lưu dưới dạng số nguyên trong biến c) là một cải tiến lớn so với các điều kiện tôi có trong các phiên bản trước.

Tôi có một nghi ngờ rằng mã tăng xycó thể được rút ngắn hơn. Đây là phần của mã làm tăng:

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

Chỉnh sửa : Tôi đã có thể rút ngắn một chút ở trên:

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

Hướng hiện tại của laser cđược lưu trữ như sau:

0 => lên
1 => xuống
2 => trái
3 => đúng

Mã dựa trên thực tế này để tăng xytheo số tiền chính xác (0, 1 hoặc -1). Tôi đã cố gắng sắp xếp lại các số ánh xạ theo từng hướng, tìm kiếm sự sắp xếp cho phép tôi thực hiện một số thao tác bitwise để tăng các giá trị, bởi vì tôi có cảm giác khó chịu rằng nó sẽ ngắn hơn phiên bản số học.


9

C # 3.0

259 ký tự

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

Hơi dễ đọc hơn:

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

Sự lãng phí chính của ký tự dường như là trong việc tìm ra chiều rộng của bản đồ và vị trí của nguồn laser. Bất kỳ ý tưởng làm thế nào để rút ngắn điều này?


Tôi không chắc liệu nó có ngắn hơn không nhưng đó là nỗ lực của tôi trong việc tìm kiếm tia laser và tìm độ rộng: sử dụng L = List <string>; bằng P = System.Drawing.Point; sử dụng 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] .Lạng; v là Danh sách <chuỗi> chứa bảng và nó xuất ra Điểm đại diện cho vị trí laser + chiều rộng đại diện int
RCIX

tốt hơn: sử dụng L = Danh sách <chuỗi>; 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] .Lipse;
RCIX

4
Các vấn đề yêu cầu một chương trình đầy đủ, không phải là một chức năng.
strager

làm thế nào về while(1)
SSpoke

9

C + ASCII, 197 ký tự:

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

Giải pháp C này giả định một bộ ký tự ASCII, cho phép chúng ta sử dụng thủ thuật nhân bản XOR. Nó cũng cực kỳ dễ vỡ - ví dụ, tất cả các dòng đầu vào phải có cùng độ dài.

Nó phá vỡ dưới mốc 200 ký tự - nhưng thật nguy hiểm, vẫn không đánh bại các giải pháp Perl đó!


= Ôi! +1! Grats đánh tôi. =]
strager

2
Hầu hết các giải pháp tốt ở đây làm cho giả định "tất cả các dòng có cùng độ dài". Tất cả công bằng trong golf và chiến tranh.
hobbs

Nếu nó được yêu cầu các dòng không có cùng độ dài, tôi sẽ thêm trường hợp kiểm tra cho nó. nhưng tôi nói rõ ràng đó là cố ý :)
LiraNuna

9

Golfscript (83 ký tự)

Xin chào, gnibbler!

:\'><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

Con trăn - 152

Đọc đầu vào từ một tệp có tên "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

Để đọc từ stdin thay thế dòng đầu tiên bằng này

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

Nếu bạn cần chữ thường đúng / sai, hãy thay đổi dòng cuối cùng thành

print`D<5`.lower()

Có bao nhiêu ký tự hiện nó đi để thay đổi Trueđể trueFalseđể false? ;-)
mob

Bạn không thể xóa 1 ký tự bằng cách thay đổi "in D<5" thành "in D <5"? Hay là tôi đang thiếu thứ gì đó?
Ponkadoodle

@wallacoloo, chắc chắn có thể. Nó chỉ cần cho chữ thường đúng / sai
John La Rooy

7

JavaScript - 265 ký tự

Cập nhật IV - Điểm lạ là đây sẽ là vòng cập nhật cuối cùng, được quản lý để lưu thêm một vài ký tự bằng cách chuyển sang vòng lặp do-while và viết lại phương trình chuyển động.

Cập nhật III - Nhờ đề xuất của strager liên quan đến việc loại bỏ Math.abs () và đặt các biến trong không gian tên toàn cầu, cùng với việc sắp xếp lại các phép gán biến có mã giảm xuống còn 282 ký tự.

Cập nhật II - Một số cập nhật thêm cho mã để loại bỏ việc sử dụng! = -1 cũng như sử dụng các biến tốt hơn cho các hoạt động lâu hơn.

Cập nhật - Khi thông qua và thực hiện một số thay đổi bằng cách tạo tham chiếu đến hàm indexOf (cảm ơn LiraNuna!) Và xóa dấu ngoặc đơn không cần thiết.

Đây là lần đầu tiên tôi chơi golf mã, vì vậy tôi không chắc điều này có thể tốt hơn bao nhiêu, bất kỳ phản hồi nào đều được đánh giá cao.

Phiên bản thu nhỏ hoàn toàn:

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}

Phiên bản gốc với ý kiến:

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

Trang web để kiểm tra với:

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

Làm thế nào để nó đầu vào? Tôi muốn kiểm tra và xác minh điều này. Ngoài ra, bạn có thể lưu rất nhiều ký tự nếu bạn lưu một tham chiếu đến a.indexOf
LiraNuna

Xin vui lòng thay thế index != -1bằng index > 0! (Hy vọng rằng không ai đặt lazer ở góc trên bên trái để 0không bị trả về. =]) Bạn có thể xâu chuỗi các varcâu lệnh hoặc loại bỏ chúng hoàn toàn (đặt các biến trong không gian tên toàn cầu). Tôi nghĩ rằng Math.abs(m)==1có thể được thay thế bằng m==-1|m==1. Có thể movement = ...; location += movementđược tối ưu hóa để location += movement =?
strager

@ strager- Chỉ cần thấy bình luận của bạn, có vẻ như bạn đã đăng nó lên trong khi tôi đang cập nhật mã, xuống tới 300 ký tự. Tôi sẽ xem những gì tôi có thể làm với việc loại bỏ Math.abs ().
rjzii

function(a){return g.indexOf(a)}có thể được thay thế bằng function(a)g.indexOf(a)các phiên bản JavaScript gần đây.
dùng1686

6

Ngôi nhà của gương

Không phải là một mục thực sự cho thử thách, nhưng tôi đã viết một trò chơi dựa trên khái niệm này (không quá lâu trở lại).

Nó được viết bằng Scala, mã nguồn mở và có sẵn ở đây :

Nó làm nhiều hơn một chút; liên quan đến màu sắc và các loại gương và thiết bị khác nhau, nhưng phiên bản 0,00001 đã làm chính xác những gì thử thách này yêu cầu. Tôi đã mất phiên bản đó và dù sao nó cũng không bao giờ được tối ưu hóa cho số lượng nhân vật.


Bạn có thể tải lên phiên bản được biên dịch hoạt động trong Windows mà không phải cài đặt scala không?
Milan

Có một phiên bản với các thư viện Scala đi kèm. Nhìn vào danh sách tải xuống. Nhưng dù sao đi nữa, nếu bây giờ bạn đã cài đặt Scala, tôi rất vui vì tôi đã giúp bạn làm điều đó :)
HRJ

6

c (K & R) 339 nhân vật cần thiết sau khi có thêm gợi ý từ strager.

Nhà vật lý trong tôi lưu ý rằng các hoạt động lan truyền và phản xạ là bất biến đảo ngược thời gian, vì vậy phiên bản này, ném các tia từ mục tiêu và kiểm tra xem liệu có đến máy phát laser hay không.

Phần còn lại của việc thực hiện là rất thẳng về phía trước và được thực hiện ít nhiều chính xác từ nỗ lực đi về phía trước của tôi.

Nén:

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

Không nén (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");
}

Không có xác nhận đầu vào và đầu vào xấu có thể gửi nó vào một vòng lặp vô hạn. Hoạt động đúng với đầu vào không lớn hơn 99 đến 99. Yêu cầu trình biên dịch sẽ liên kết thư viện chuẩn mà không bao gồm bất kỳ tiêu đề nào. Và tôi nghĩ rằng tôi đã hoàn thành, strager đã giúp tôi vượt qua một khoảng thời gian đáng kể, ngay cả với sự giúp đỡ của anh ấy.

Tôi hy vọng ai đó sẽ thể hiện một cách tinh tế hơn để hoàn thành nhiệm vụ. Không có gì sai với điều này, nhưng nó không phải là phép thuật sâu sắc.


Không cần =0trên toàn cầu vì chúng được khởi tạo thành 0 theo mặc định. Thay thế các hằng ký tự bằng số thập phân tương đương của chúng. Sử dụng >0thay vì !=EOFkiểm tra đối với EOF (và \0). Bạn có thể có thể #definebỏ đi một số mã casegiống như tôi đã làm với if. Không cần thêm \nvào putsnhư putsphải in một dòng mới nào. for(;;)ngắn hơn while(1). Hi vọng điêu nay co ich. =]
strager

@strager: Cảm ơn. Tôi luôn luôn đến những lần lặp này, bởi vì tôi không nghĩ như vậy ...
dmckee --- mèo điều hành cũ mèo con

2
"There is no input validation"- Không nên có bất kỳ. Để làm cho người chơi golf dễ dàng, đầu vào được giả định là luôn 'sạch' trừ khi có quy định khác.
LiraNuna

@dmckee, Đừng lo lắng, chúng tôi Code Golf cũng hoạt động lặp đi lặp lại. Tuy nhiên, chúng tôi thường sử dụng một số thủ thuật ngay từ đầu (như một nửa những cái tôi đã đề cập), nhưng điều đó đi kèm với kinh nghiệm. =]
strager

Trừ khi tôi đếm sai, chương trình là 390 ký tự, không phải 380.
strager

6

Ruby - 146 ký tự

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

PostScript , 359 byte

Nỗ lực đầu tiên, rất nhiều chỗ để cải thiện ...

/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ý tự (được tối ưu hóa)

Vẫn sử dụng một máy trạng thái chung, thay vì bất cứ thứ gì thông minh:

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}

Một phiên bản có thể đọc được:

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

Tôi tin vào Tái sử dụng mã, tôi sẽ sử dụng một trong các mã của bạn làm API :).

  đặt Board.new.validate (đầu vào)

32 ký tự \ o / ... wohoooo


6
đó là một bogey kép!
Jeff Atwood

3
Đánh bại bạn: p Board.new.validate nhập 26 ký tự \ o /
Alessandra Pereyra

3

C ++: 388 ký tự

#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 không có tiêu đề)


Làm thế nào nó hoạt động:

Đầu tiên, tất cả các dòng được đọc, sau đó, laser được tìm thấy. Sau đây sẽ đánh giá 0chừng nào chưa tìm thấy mũi tên laser nào, đồng thời gán cho xvị trí nằm ngang.

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

Sau đó, chúng tôi xem hướng nào chúng tôi tìm thấy và lưu trữ nó trong i. Ngay cả các giá trị ilà trên cùng / bên trái ("giảm") và giá trị lẻ là dưới cùng / bên phải ("tăng"). Theo quan niệm đó, d("hướng") và r("hướng") được đặt. Chúng tôi chỉ mục mảng con trỏ zvới định hướng và thêm hướng vào số nguyên chúng tôi nhận được. Hướng chỉ thay đổi nếu chúng ta nhấn một dấu gạch chéo, trong khi nó vẫn giữ nguyên khi chúng ta nhấn một dấu gạch chéo ngược. Tất nhiên, khi chúng ta chạm gương, thì chúng ta luôn thay đổi hướng ( r = !r).


Bạn đang bắt tôi làm giải pháp C ++ của riêng tôi. =]
strager

2
@strager, điều này đang trở nên nhàm chán. Hãy thực hiện một giải pháp hiển thị "đúng" hoặc "sai" tại thời điểm biên dịch xD
Johannes Schaub - litb

thêm lời giải thích vì tôi nghĩ tôi sẽ giữ nó ở đây :)
Johannes Schaub - litb

2

Groovy @ 279 người từ thiện

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

C #

1020 ký tự.
1088 ký tự (thêm đầu vào từ bảng điều khiển).
925 ký tự (biến tái cấu trúc).
875 ký tự (đã loại bỏ trình khởi tạo Từ điển dự phòng; đã đổi thành Binary & toán tử)

Đã đưa ra quan điểm không nhìn vào bất cứ ai khác trước khi đăng. Tôi chắc chắn rằng nó có thể tăng lên một chút. Và toàn bộ phương pháp FindLaser trong phiên bản có thể đọc được dường như vô cùng đáng ghét đối với tôi. Nhưng, nó hoạt động và muộn rồi :)

Lưu ý lớp có thể đọc được bao gồm một phương thức bổ sung in ra Arena hiện tại khi tia laser di chuyển xung quanh.

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

Phiên bản có thể đọc được (không hoàn toàn là phiên bản golf cuối cùng, nhưng cùng tiền đề):

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
Chương trình nên lấy đầu vào. Phổ biến nhất từ ​​stdin.
LiraNuna

0

Perl 219
phiên bản perl của tôi là 392 342 ký tự dài (tôi phải xử lý các trường hợp của chùm nhấn laser):
Cập nhật , nhờ Hobbs đã nhắc nhở tôi về tr//, nó bây giờ 250 ký tự:
Cập nhật , loại bỏ mtrong m//, thay đổi hai whilevòng mang một ít tiền tiết kiệm; bây giờ chỉ có một không gian cần thiết.
( L:it;goto Lcó cùng độ dài với 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

Tôi đã cạo một số, nhưng nó hầu như không cạnh tranh với một số trong số này, mặc dù muộn.
Có vẻ tốt hơn một chút như:

#!/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

Chà ... Thành thật mà nói, điều này nên tự giải thích nếu bạn hiểu rằng đó @blà một mảng các ký tự trong mỗi dòng, và có thể đọc các biểu thức và trbiểu thức chính quy đơn giản .


Mẹo: bạn có thể rút ngắn mã gương của mình lên. $_=$s;tr/^v<>/<>^v/$_=$s;tr/v^<>/<>^v/tương ứng. Ngoài ra, bạn không cần mtrong m//.
hobbs

Xin lỗi, hãy tạo cái thứ hai$_=$s;tr/v^></<>^v/;
hobbs

Bạn vẫn còn một vài if m/.../thứ có thể if/.../cứu hai nhân vật một pop.
hobbs

Bạn có thể sử dụng y///thay vì tr///để lưu hai ký tự.
Bạch kim Azure

0

F # - 454 (hoặc ở đâu đó)

Hơi trễ trò chơi, nhưng không thể cưỡng lại việc đăng 2 lần thử của tôi.

Cập nhật sửa đổi một chút. Bây giờ dừng lại chính xác nếu máy phát bị nhấn. Ý tưởng bị chèn ép của Brian cho IndexOfAny (xấu hổ vì dòng đó quá dài dòng). Tôi thực sự đã xoay sở để tìm ra cách để ReadToEnd trở về từ Bảng điều khiển, vì vậy tôi đang tin tưởng vào điều đó ...

Tôi hài lòng với câu trả lời này, vì nó khá ngắn, nhưng nó vẫn khá dễ đọc.

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

Họ đang trang trí. Kiểm tra những thách thức khác của tôi, nó chỉ là một định dạng.
LiraNuna

@LiraNuna, ok, hóa ra, lần lặp này chỉ ăn chúng thôi :)
Stewol

Sẽ là tốt để so sánh với thực hiện 1-d. Chỉ cần thêm / bớt 1 cho trái và phải và thêm / trừ w cho lên và xuống. Tôi hy vọng bạn sẽ tiết kiệm được một vài ký tự
John La Rooy

@gnibbler, Brian đã làm điều đó, tôi không chắc mình có thể đánh bại anh ta, nhưng tôi có thể thử.
Stewol
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.