Golf Kode: Laser

152

Tantangan

Kode terpendek berdasarkan jumlah karakter untuk memasukkan representasi 2D dari sebuah papan, dan menampilkan 'benar' atau 'salah' sesuai dengan input .

Papan terbuat dari 4 jenis ubin:

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

Hanya ada satu laser dan hanya satu target . Dinding harus membentuk persegi panjang yang solid dengan berbagai ukuran, tempat laser dan target diletakkan di dalamnya. Dinding di dalam 'ruang' dimungkinkan.

Sinar laser memotret dan bergerak dari asalnya ke arah yang ditunjuknya. Jika sinar laser mengenai dinding, itu berhenti. Jika sinar laser mengenai cermin, memantul 90 derajat ke arah yang ditunjuk cermin. Cermin memiliki dua sisi, yang berarti kedua belah pihak 'reflektif' dan dapat memantulkan sinar dengan dua cara. Jika sinar laser mengenai laser ( ^v><) itu sendiri, itu diperlakukan sebagai dinding (sinar laser menghancurkan beamer dan sehingga tidak akan pernah mengenai target).

Uji kasus

Memasukkan:
    ###########
    # / \ #
    # #
    # \ x #
    #> / #
    ########### 
Keluaran:
    benar

Memasukkan:
    ###########
    # vx #
    # / #
    # / #
    # \ #
    ###########
Keluaran:    
    Salah

Memasukkan:
    ##############
    # # #
    #> # #
    # # #
    # # x #
    # # #
    ##############
Keluaran:
    Salah

Memasukkan:
    ###########
    # / \ / \ / \ #
    # \\ // \\ #
    # // \ / \ / \\ #
    # \ / \ / \ / x ^ #
    ###########
Keluaran:
    benar

Hitungan kode termasuk input / output (yaitu program lengkap).

LiraNuna
sumber
84
IMMA CHARGIN 'MAH LAZER!
Ólafur Waage
37
Ini luar biasa .
GManNickG
33
DON'T CROSS THE
BEAMS
49
@GameFreak: Itu menjadi sangat tua.
Artelius
24
Apakah itu benar-benar hiu dengan pemalas di kepalanya?
Nathan Feger

Jawaban:

78

Perl, 166 160 karakter

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

Solution memiliki 166 pukulan ketika kontes ini berakhir, tetapi A. Rex telah menemukan beberapa cara untuk mengurangi 6 karakter lagi:

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

Baris pertama memuat input ke %t, tabel papan tempat $t{99*i+j}memegang karakter di baris i , kolom j . Kemudian,

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

itu mencari elemen %tuntuk karakter yang cocok > ^ <atau v, dan secara bersamaan menetapkan $dnilai antara 0 dan 3 yang menunjukkan arah awal sinar laser.

Di awal setiap iterasi di loop utama, kami memperbarui $djika balok saat ini di cermin. XOR'ing oleh 3 memberikan perilaku yang benar untuk \cermin dan XOR'ing oleh 1 memberikan perilaku yang benar untuk /cermin.

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

Selanjutnya, posisi saat $rini diperbarui sesuai dengan arah saat ini.

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

Kami menetapkan karakter pada posisi saat ini $_untuk memanfaatkan operator pertandingan yang sesuai.

/[\/\\ ]/ && redo

Lanjutkan jika kita berada di ruang kosong atau karakter cermin. Kalau tidak, kita mengakhiri truejika kita berada di target ( $_ =~ /x/) dan falsesebaliknya.

Batasan: mungkin tidak berfungsi pada masalah dengan lebih dari 99 kolom. Batasan ini dapat dihapus dengan mengorbankan 3 karakter lagi,

mob
sumber
Oke, harus 323 karakter. = D
strager
5
Saya dapat mengubah 99 ke 1E5 untuk membuatnya sangat kuat dengan mengorbankan 3 karakter.
mob
2
Solusi terbaik Anda akan lebih terlihat di bagian atas pos.
strager
13
Tetapi menggunakan ekspresi reguler untuk memutar papan? Itu sakit. Itu seperti bonus 20 tak otomatis.
mob
1
@mobrule: Hemat enam pukulan: susun ulang baris pertama sebagai s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;, ubah %d=split//,.." to % d = .. = ~ /./ g , and change grep {..}% t` kegrep..,%t
A. Rex
75

Perl, 177 Karakter

Linebreak pertama dapat dihapus; dua lainnya wajib.

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

Penjelasan:

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

Jika sinar yang bergerak ke kanan berjalan ke {ruang kosong, cermin sudut atas, cermin sudut bawah} ia menjadi {balok bergerak kanan, balok bergerak atas, balok bergerak bawah}. Inisialisasi $/sepanjang jalan - untungnya "6" bukan input char yang valid.

$_ = <>;

Baca papan tulis $_.

$s="#";

$sadalah simbol dari apa pun yang balok duduk di atas sekarang. Karena penghasil laser harus diperlakukan seperti dinding, setel ini sebagai dinding untuk memulai.

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

Jika sinar laser menunjuk dengan cara apa pun kecuali benar, putar simbolnya, lalu putar seluruh papan pada tempatnya (juga putar simbol untuk cermin). Ini adalah rotasi kiri 90 derajat, dicapai secara efektif dengan membalikkan baris sambil mentransposisi baris dan kolom, dalam sedikit lebih buruk s///edengan efek samping. Dalam kode golf, tr ditulis dalam bentuk y'''yang memungkinkan saya untuk melewatkan backslashing satu backslash.

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

Hentikan dengan pesan yang tepat jika kita mengenai target atau tembok.

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

Jika ada ruang kosong di depan laser, bergerak maju. Jika ada cermin di depan laser, maju dan putar bilah. Dalam kedua kasus tersebut, masukkan "simbol yang disimpan" kembali ke lokasi balok lama, dan masukkan benda yang baru saja kita timpa ke dalam simbol yang disimpan.

redo;

Ulangi sampai penghentian. {...;redo}adalah dua karakter kurang dari for(;;){...}dan tiga kurang dari while(1){...}.

hobbs
sumber
4
Putar papan ... Gila. Regexp ... Lebih gila. O_o
strager
39
Kamu ... Kamu monster!
LiraNuna
4
LiraNuna: Saya memilih untuk menganggap itu sebagai pujian.
hobbs
21
Golf sudah berakhir. Bagaimana Anda bisa mengalahkan memutar papan 2D dengan ekspresi reguler ?!
Konrad Rudolph
13
wtf? programmer perl adalah penyihir.
Johannes Schaub - litb
39

C89 (209 karakter)

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

Penjelasan

Monstrositas ini mungkin akan sulit diikuti jika Anda tidak mengerti C. Hanya peringatan.

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

Makro kecil ini memeriksa apakah karakter saat ini ( *p) sama dengan apa pun yang aada dalam bentuk karakter ( *#a). Jika sama, atur vektor gerakan ke b( m=b), tandai karakter ini sebagai dinding ( *p=1), dan atur titik awal ke lokasi saat ini ( q=p). Makro ini termasuk bagian "lain".

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

Nyatakan beberapa variabel. * qadalah lokasi cahaya saat ini. * Gadalah papan permainan sebagai larik 1D. * padalah lokasi baca saat ini ketika mengisi G. * wadalah lebar papan.

main(m){

Jelas main. madalah variabel yang menyimpan vektor gerakan. (Ini adalah parameter untuk mainsebagai optimasi.)

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

Ulangi semua karakter, isi Gmenggunakan p. Lewati G[0]sebagai pengoptimalan (tidak perlu membuang karakter plagi di bagian ketiga for).

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

Gunakan makro yang disebutkan di atas untuk mendefinisikan lazer, jika mungkin. -1dan 1sesuai dengan kiri dan kanan, masing-masing, dan -wdan ke watas dan ke bawah.

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

Jika karakter saat ini adalah penanda garis akhir (ASCII 10), setel lebar jika belum ditetapkan. Dilompati yang G[0]memungkinkan kita untuk menulis w=p-Gbukan w=p-G+1. Juga, ini selesai dari ?:rantai dari M's.

    for(;
        q+=m,

Pindahkan cahaya oleh vektor gerakan.

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

Refleksikan vektor gerakan.

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

Jika ini adalah tembok atau x, berhenti dengan pesan yang sesuai ( m=0mengakhiri loop). Kalau tidak, jangan lakukan apa pun (noop; m=m)

    );
}
strager
sumber
8
Ugh! Saya sedang mengerjakan solusi C ketika alarm kebakaran berbunyi di kompleks apartemen saya. Sekarang saya dikalahkan. Solusi yang bagus.
rlbond
Methinks menggunakan variabel temp untuk swap dan swap / langkah negasi Anda akan menghemat beberapa karakter.
Artelius
@ Artelius, Ya, saya menyadari itu, dan beberapa hal lainnya. Terima kasih.
strager
1
TCC sebenarnya tidak suka deklarasi yang tidak diketik dan kesalahan dengan g.c:3: declaration expected:(
Mark Rushakoff
2
putsDeklarasi Menghapus membantu, tetapi tidak cukup untuk membawanya di bawah 170. 209 cukup bagus, jadi saya pikir saya akan membiarkannya begitu. Terima kasih atas bantuannya, kawan. Saya sangat menghargai itu. =] (Apa pun untuk melengserkan para penyihir Perl!)
strager
36

Saya berani bertaruh orang telah menunggu yang satu ini untuk waktu yang lama. (Apa maksudmu, tantangannya sudah berakhir dan tidak ada yang peduli lagi?)

Lihatlah ... Saya di sini menyajikan solusi

Befunge-93!

Beratnya adalah pada 973 charaters kekalahan (atau 688 jika Anda cukup amal untuk mengabaikan spasi putih, yang hanya digunakan untuk memformat dan tidak melakukan apa pun dalam kode aktual).

Peringatan : Saya menulis juru bahasa Befunge-93 saya sendiri di Perl beberapa waktu yang lalu, dan sayangnya ini semua yang saya punya waktu untuk mengujinya. Saya cukup yakin dengan kebenarannya secara umum, tetapi mungkin memiliki batasan aneh sehubungan dengan EOF: Karena <>operator Perl mengembalikan undef di akhir file, ini diproses sebagai 0 dalam konteks numerik. Untuk implementasi berbasis C di mana EOF memiliki nilai yang berbeda (-1 say), kode ini mungkin tidak berfungsi.

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

Penjelasan

Jika Anda tidak terbiasa dengan sintaks dan operasi Befunge, periksa di sini .

Befunge adalah bahasa berbasis tumpukan, tetapi ada perintah yang memungkinkan seseorang untuk menulis karakter ke kode Befunge. Saya memanfaatkan itu di dua tempat. Pertama, saya menyalin seluruh input ke papan Befunge, tetapi terletak beberapa baris di bawah kode tertulis yang sebenarnya. (Tentu saja, ini tidak pernah benar-benar terlihat ketika kode berjalan.)

Tempat lain di dekat kiri atas:

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

Dalam hal ini, area yang saya soroti di atas adalah tempat saya menyimpan beberapa koordinat. Kolom pertama di baris tengah ada tempat saya menyimpan koordinat x untuk "posisi kursor" saat ini; kolom kedua adalah tempat saya menyimpan koordinat y; dua kolom berikutnya adalah untuk menyimpan koordinat x dan y dari sumber sinar laser ketika ditemukan; dan kolom terakhir (dengan karakter 'a' di dalamnya) akhirnya ditimpa untuk memuat arah balok saat ini, yang jelas berubah ketika jalur balok dilacak.

Program dimulai dengan menempatkan (0,27) sebagai posisi kursor awal. Kemudian input dibaca satu karakter pada satu waktu dan ditempatkan di posisi kursor; baris baru hanya menyebabkan koordinat y meningkat dan koordinat x kembali ke 0, sama seperti pengembalian kereta nyata. Akhirnya undef dibaca oleh interpreter dan nilai 0 karakter digunakan untuk menandai akhir input dan beralih ke langkah iterasi laser. Ketika karakter laser [<> ^ v] dibaca, itu juga disalin ke repositori memori (di atas karakter 'a') dan koordinatnya disalin ke kolom tepat di sebelah kiri.

Hasil akhir dari semua ini adalah bahwa seluruh file pada dasarnya disalin ke dalam kode Befunge, sedikit cara di bawah kode aktual yang dilalui.

Setelah itu, lokasi berkas disalin kembali ke lokasi kursor, dan iterasi berikut dilakukan:

  • Periksa arah sinar saat ini dan kenaikan atau penurunan koordinat kursor dengan tepat. (Saya melakukan ini terlebih dahulu untuk menghindari harus berurusan dengan kasus sudut sinar laser tepat pada langkah pertama.)
  • Baca karakter di lokasi itu.
  • Jika karakternya "#", masukkan baris baru dan "false" pada tumpukan, cetak, dan akhir.
  • Bandingkan dengan semua karakter balok [<> ^ v]; jika ada kecocokan, cetak juga "false \ n" dan akhiri.
  • Jika karakter adalah spasi, kosongkan tumpukan dan lanjutkan.
  • Jika karakter adalah garis miring ke depan, dapatkan arah sinar ke tumpukan dan bandingkan dengan masing-masing karakter arah secara bergantian. Ketika satu ditemukan, arah baru disimpan di tempat yang sama dalam kode dan loop berulang.
  • Jika karakter adalah backslash, pada dasarnya lakukan hal yang sama seperti di atas (kecuali dengan pemetaan yang tepat untuk backslash).
  • Jika karakternya 'x', kami telah mencapai target. Cetak "true \ n" dan keluar.
  • Jika karakternya tidak ada, cetak "error \ n" dan keluar.

Jika ada cukup permintaan untuk itu, saya akan mencoba menunjukkan dengan tepat di mana dalam kode semua ini tercapai.

Platinum Azure
sumber
14
+1 - Hanya karena itu bisa disalahartikan sebagai EXE yang dibuka di notepad.
Kyle Rosendo
1
Um ... suci ****. Saya telah mengacaukan Befunge, dan ini benar-benar mengesankan.
Almo
Golf kode dalam bahasa yang dikaburkan ... seperti selai kacang dan cabai!
wberry
29

F #, 36 baris, sangat mudah dibaca

Oke, hanya untuk mendapatkan jawaban di luar sana:

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    

Sampel:

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

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

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

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

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

##########
#  /    \#
# / \    #
#/    \ x#
#\^/\ /  #
##########
false
Brian
sumber
54
SAYA DAPAT MEMBACA YANG INI! AJAIB!
Jeff Atwood
17
Golf kode Java / C # dihitung oleh garis, bukan karakter. Itu cacatnya.
Nathan Feger
3
@ strager tidak tertekan dalam 3 tahun ketika Anda disewa untuk mempertahankan kode dan pengembang asli telah lama meninggalkan.
Nathan Feger
Ini gagal menggunakan F # di Visual Studio 2010. Seq.to_list tidak ada (ok, ubah ke toList), lalu Line 25, pencocokan pola tidak lengkap.
Russell
2
Ya, ubah to_list ke toList sekarang. Peringatan kecocokan yang tidak lengkap baik-baik saja; itu kode golf, jadi saya tidak melakukan kode seperti: | _ -> failwith "impossible"
Brian
29

Golfscript - 83 chars (mashup of my and strager's)

Baris baru ada di sini untuk pembungkus

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

Golfscript - 107 karakter

Baris baru hanya ada untuk kejelasan

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

Bagaimana itu bekerja.

Baris pertama menentukan lokasi dan arah awal.
Langkah kedua melalui memutar setiap kali laser menyentuh cermin.

gnibbler
sumber
18

353 karakter di Ruby:

314 277 karakter sekarang!

OK, 256 karakter di Ruby dan sekarang saya selesai. Angka bulat yang bagus untuk berhenti. :)

247 karakter. Saya tidak bisa berhenti.

223 203 201 karakter di 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)}

Dengan spasi putih:

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

Sedikit refactored:

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
Jeremy Ruten
sumber
Tapi ... Anda dapat mengubah nama chke Catau lainnya surat 1 char menyimpan 2 karakter!
LiraNuna
Ok ok, baiklah ... Saya sebenarnya menyadari bahwa seluruh variabel tidak perlu karena saya hanya menggunakannya sekali. Ini dan beberapa perbaikan lainnya menguranginya menjadi 247 karakter.
Jeremy Ruten
1
Tidak i++(bukannya i+=1)?
LiraNuna
6
Nggak. Anda dapat melakukan ++ i, tetapi itu membuatnya benar-benar positif seperti dulu.
DigitalRoss
Saya suka versi terkompresi: #; p
SeanJA
17

Python

294 277 253 240 232 karakter termasuk baris baru:

(karakter pertama dalam baris 4 dan 5 adalah tab, bukan spasi)

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

Saya lupa Python bahkan memiliki titik koma opsional.

Bagaimana itu bekerja

Gagasan kunci di balik kode ini adalah menggunakan bilangan kompleks untuk mewakili posisi dan arah. Baris adalah sumbu imajiner, meningkat ke bawah. Kolom adalah sumbu nyata, meningkat ke kanan.

l='>v<^';daftar simbol laser. Urutan dipilih sehingga indeks karakter arah laser sesuai dengan kekuatan sqrt (-1)

x={'/':'^<v>','\\':'v>^<',' ':l};tabel transformasi menentukan bagaimana arah berubah ketika balok meninggalkan ubin yang berbeda. Ubin adalah kuncinya, dan arah baru adalah nilainya.

b=[1];memegang papan. Elemen pertama adalah 1 (dievaluasi sebagai benar) sehingga loop sementara akan berjalan setidaknya sekali.

r=p=0 radalah nomor baris input saat ini, padalah posisi saat ini dari sinar laser.

while b[-1]: berhenti memuat data papan ketika raw_input mengembalikan string kosong

b+=[raw_input()];r+=1 tambahkan baris input berikutnya ke papan tulis dan tambahkan penghitung baris

for g in l: tebak setiap arah laser secara bergantian

c=b[r].find(g) atur kolom ke lokasi laser atau -1 jika tidak di garis (atau menunjuk ke arah yang berbeda)

if-1<c:p=c+1j*r;d=gjika kami menemukan laser, maka atur posisi pdan arah saat ini d. dadalah salah satu karakter dil

Setelah memuat papan ke dalam b, posisi pdan arah saat dini telah diatur ke orang-orang dari sumber laser.

while' '<d: space memiliki nilai ASCII lebih rendah daripada simbol arah mana pun, jadi kami menggunakannya sebagai flag berhenti.

z=l.find(d);indeks arahan arah saat ini di lstring. zterbiasa nanti untuk menentukan arah balok baru menggunakan xtabel, dan untuk meningkatkan posisi.

p+=1j**z;increment posisi menggunakan kekuatan i. Misalnya, l.find('<')==2-> i ^ 2 = -1, yang akan bergerak ke kiri satu kolom.

c=b[int(p.imag)][int(p.real)]; baca char di posisi saat ini

d=x.get(c,' '*4)[z]mencari arah baru untuk balok di tabel transformasi. Jika karakter saat ini tidak ada di tabel, maka setel dke spasi.

print'#'<c cetak false jika kita berhenti pada apa pun selain target.

Theran
sumber
9
p+=1j**z: Itu manis.
dmckee --- ex-moderator kitten
16

Ini yaitu adalah port langsung dari solusi Brian untuk C # 3, minus interaksi konsol. Ini bukan entri dalam tantangan karena ini bukan program yang lengkap, saya hanya ingin tahu bagaimana beberapa konstruksi F # yang digunakannya dapat diwakili dalam 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};
    }
}

Sunting: Setelah beberapa percobaan, kode pencarian ini agak bertele-tele:

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

telah diganti dengan beberapa LINQ yang lebih ringkas untuk kode Objek:

var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
         .First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));
Nathan Baulch
sumber
8
Oh Tuhan. Betapa contoh yang bagus untuk menunjukkan betapa hebatnya linq dan c # menjadi. 1+ karena saya penggemar c # yang besar. x)
Emiswelt
16

F #, 255 karakter (dan masih bisa dibaca!):

Ok, setelah istirahat malam, saya banyak meningkatkan ini:

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

Mari kita bicarakan satu per satu.

Pertama, slurp semua input ke dalam array satu dimensi yang besar (array 2D bisa berakibat buruk untuk kode golf; cukup gunakan array 1D dan tambahkan / kurangi lebar satu baris ke indeks untuk bergerak ke atas / ke bawah baris).

Selanjutnya kita menghitung 'w', lebar jalur input, dan 'c', posisi awal, dengan mengindeks ke dalam array kita.

Sekarang mari kita mendefinisikan fungsi 'next' 'n', yang mengambil posisi saat ini 'c' dan arah 'd' yaitu 0,1,2,3 untuk naik, kiri, kanan, bawah.

Indeks-epsilon 'e' dan apa-arah-baru-jika-kita-tekan-a-garis miring 'dihitung' oleh tabel. Misalnya, jika arah saat ini 'd' adalah 0 (atas), maka elemen pertama dari tabel mengatakan "-w, 2" yang berarti kita mengurangi indeks dengan w, dan jika kita menekan garis miring arah yang baru adalah 2 (Baik).

Sekarang kita kembali ke fungsi berikutnya 'n' dengan (1) indeks berikutnya ("c + e" - current plus epsilon), dan (2) arah baru, yang kita hitung dengan melihat ke depan untuk melihat apa yang ada dalam array di sel selanjutnya. Jika char lookahead adalah garis miring, arah baru adalah 's'. Jika backslash, arah baru adalah 3-s (pilihan kami untuk encoding 0123 berhasil). Jika ini ruang, kita terus berjalan ke arah yang sama 'd'. Dan jika itu karakter lain 'c', maka permainan berakhir, mencetak 'benar' jika karakter itu 'x' dan salah jika sebaliknya.

Untuk memulai, kita memanggil fungsi rekursif 'n' dengan posisi awal 'c' dan arah awal (yang melakukan pengkodean awal arah ke 0123).

Saya pikir saya mungkin masih bisa mencukur beberapa karakter lagi, tapi saya cukup senang dengan itu seperti ini (dan 255 adalah angka yang bagus).

Brian
sumber
11

Beratnya pada 18203 karakter adalah solusi Python yang dapat:

  • mengatasi cermin di luar 'kamar'
  • menghitung lintasan ketika tidak ada 'ruang' berdasarkan batasan 2D (spec mengatakan banyak tentang apa yang harus ada di 'ruang' tetapi tidak jika ruangan itu ada)
  • melaporkan kembali kesalahan

Masih perlu dirapikan agak dan saya tidak tahu apakah fisika 2D menentukan bahwa balok tidak dapat melintasi sendiri ...

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

Skrip bash untuk memamerkan pelaporan kesalahan warna:

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

Unittests yang digunakan dalam pembangunan:

#!/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
Metalshark
sumber
6
Fisika laser menentukan bahwa sinar dapat melintas dengan sendirinya. Komentar di atas adalah referensi budaya yang penting.
dmckee --- ex-moderator kitten
5
Kura-kura dan pendekatan Kelinci untuk kode golf. Kirim sesuatu dengan karakter yang jelas terlalu banyak (91x lebih banyak dari pemenang saat ini) tetapi perhatikan setiap huruf dari spec. Lambat dan mantap umumnya membuat saya lebih sedikit pekerjaan kontrak.
Metalshark
Bagian Anda yang paling kecil tampaknya kehilangan sebagian. Itu terputus di "self.NOT_DIRECTIO"
BioGeek
@BioGeek - tekan batas berapa panjang posting;). Selain itu tes gaya BASH memamerkan highlighting warna.
Metalshark
11

Ruby, 176 karakter

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}

Saya menggunakan mesin negara sederhana (seperti kebanyakan poster), tidak ada yang mewah. Saya terus mengurangi menggunakan setiap trik yang bisa saya pikirkan. Bitor XOR yang digunakan untuk mengubah arah (disimpan sebagai integer dalam variabel c) adalah peningkatan besar atas kondisi yang saya miliki di versi sebelumnya.

Saya curiga bahwa kode itu bertambah xdan ybisa dibuat lebih pendek. Berikut adalah bagian dari kode yang melakukan penambahan:

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

Sunting : Saya dapat mempersingkat sedikit di atas:

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

Arah laser saat cini disimpan sebagai berikut:

0 => ke atas
1 => bawah
2 => kiri
3 => benar

Kode ini bergantung pada fakta ini untuk ditambahkan xdan ydengan jumlah yang benar (0, 1, atau -1). Saya mencoba mengatur ulang nomor mana yang dipetakan ke setiap arah, mencari pengaturan yang akan membiarkan saya melakukan manipulasi bitwise untuk meningkatkan nilai, karena saya memiliki perasaan yang mengganggu bahwa itu akan lebih pendek daripada versi aritmatika.

Mike Spross
sumber
9

C # 3.0

259 karakter

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

Sedikit lebih mudah dibaca:

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

Limbah utama dari karakter tampaknya adalah menemukan lebar peta dan posisi sumber laser. Adakah cara untuk mempersingkat ini?

Noldorin
sumber
Saya tidak yakin apakah ini lebih pendek tetapi ini adalah kesempatan saya untuk menemukan laser dan lebar temuan: menggunakan L = Daftar <string>; menggunakan P = System.Drawing.Point; menggunakan L = Daftar <string>; L r = new L () {"v", "<", ">", "^"}; P p = P baru (); 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] .Length; v adalah Daftar <string> yang berisi tabel, dan output Point yang mewakili posisi laser + sebuah int mewakili lebar
RCIX
lebih baik: menggunakan L = Daftar <string>; L l = L baru (4) {"v", "<", ">", "^"}; var point = baru {x = 0, y = 0}; int c = 0; l.ForEach (a => {m.ForEach (s => {if (s.IndexOf (a)! = - 1) {point = baru {x = s.IndexOf (a), y = c};}}); c ++;}); int w = m [0] .Length;
RCIX
4
Masalah meminta program lengkap, bukan fungsi.
strager
bagaimana while(1)
SSpoke
9

C + ASCII, 197 karakter:

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

Solusi C ini mengasumsikan rangkaian karakter ASCII, memungkinkan kita untuk menggunakan trik cermin XOR. Ini juga sangat rapuh - semua jalur input harus sama panjang, misalnya.

Itu pecah di bawah tanda 200 karakter - tapi ya, masih belum mengalahkan solusi Perl!

kaf
sumber
= O! +1! Terima kasih sudah mengalahkan saya. =]
strager
2
Sebagian besar solusi yang baik di sini membuat asumsi "semua garis sama panjang". Semua adil dalam golf dan perang.
hobbs
Jika diperlukan, garisnya tidak sama, saya akan menambahkan test case untuk itu. tapi saya jelas mengatakan itu disengaja :)
LiraNuna
9

Golfscript (83 karakter)

Halo, Gnibbler!

:\'><v^'.{\?}%{)}?:P@=?{:O[1-1\10?).~)]=P+
:P\=' \/x'?[O.2^.1^'true''false']=.4/!}do
strager
sumber
3
golfscript: perl ~ = 1: 1.7
John La Rooy
9

Python - 152

Membaca input dari file yang disebut "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

Untuk membaca dari stdin ganti baris pertama dengan ini

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

Jika Anda membutuhkan huruf kecil benar / salah ubah baris terakhir menjadi

print`D<5`.lower()
gnibbler
sumber
Berapa banyak karakter yang diperlukan untuk berubah Trueke truedan Falseke false? ;-)
mob
Tidak bisakah Anda menghapus 1 karakter dengan mengubah "cetak D<5" menjadi "cetak D <5"? Atau ada sesuatu yang saya lewatkan?
Ponkadoodle
@wallacoloo, pasti bisa. Ini hanya diperlukan untuk huruf kecil benar / salah
John La Rooy
7

JavaScript - 265 Karakter

Pembaruan IV - Mustahil ini akan menjadi putaran terakhir pembaruan, berhasil menyelamatkan beberapa karakter dengan beralih ke loop do-while dan menulis ulang persamaan gerakan.

Pembaruan III - Berkat saran oleh strager dalam hal menghapus Math.abs () dan menempatkan variabel dalam ruang nama global, yang digabungkan dengan beberapa penataan ulang variabel penugasan membuat kode hingga 282 karakter.

Pembaruan II - Beberapa pembaruan lagi pada kode untuk menghapus penggunaan! = -1 serta beberapa variabel yang lebih baik untuk operasi yang lebih lama.

Pembaruan - Ketika melewati dan membuat beberapa perubahan dengan membuat referensi ke fungsi indexOf (terima kasih LiraNuna!) Dan menghapus tanda kurung yang tidak diperlukan.

Ini adalah pertama kalinya saya melakukan kode golf jadi saya tidak yakin seberapa baik ini, umpan balik akan dihargai.

Versi yang sepenuhnya diperkecil:

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}

Versi asli dengan komentar:

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

Halaman web untuk diuji dengan:

<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>
Rob Z
sumber
bagaimana cara mengambil input? Saya ingin menguji dan memverifikasi ini. Juga, Anda dapat menyimpan banyak karakter jika Anda menyimpan referensi ke a.indexOf
LiraNuna
Ganti index != -1dengan index > 0tolong! (Mudah-mudahan tidak ada yang meletakkan lazer di sudut kiri atas sehingga 0tidak akan dikembalikan. =]) Anda dapat rantai varpernyataan atau menyingkirkan semuanya (meletakkan variabel di namespace global). Saya pikir Math.abs(m)==1bisa diganti dengan m==-1|m==1. Dapat movement = ...; location += movementdioptimalkan location += movement =?
strager
@ strager- Baru saja melihat komentar Anda, sepertinya Anda mempostingnya sementara saya memperbarui kode, hingga 300 karakter. Saya akan melihat apa yang bisa saya lakukan dengan menghilangkan Math.abs ().
rjzii
function(a){return g.indexOf(a)}dapat diganti dengan function(a)g.indexOf(a)dalam versi JavaScript terbaru.
user1686
6

House of Mirrors

Bukan entri yang sebenarnya untuk tantangan, tetapi saya menulis permainan berdasarkan konsep ini (tidak terlalu lama kembali).

Itu ditulis dalam Scala, open-source dan tersedia di sini :

Itu sedikit lebih banyak; berurusan dengan warna dan berbagai jenis cermin dan perangkat, tetapi versi 0,00001 melakukan apa yang diminta oleh tantangan ini. Saya telah kehilangan versi itu dan itu tidak pernah dioptimalkan untuk jumlah karakter.

HRJ
sumber
Apakah mungkin bagi Anda untuk mengunggah versi yang dikompilasi yang bekerja di Windows tanpa harus menginstal scala?
Milan
Ada versi dengan perpustakaan Scala disertakan. Lihatlah daftar unduhan. Tapi bagaimanapun, jika Anda telah menginstal Scala sekarang, saya senang saya mendapat Anda untuk melakukan itu :)
HRJ
6

c (K&R) 339 karakter yang diperlukan setelah lebih banyak saran dari strager.

Fisikawan dalam saya mencatat bahwa operasi propagasi dan refleksi invarian pembalikan waktu, jadi versi ini, melempar sinar dari target dan memeriksa untuk melihat apakah tiba di penghasil laser.

Sisa implementasi sangat lurus ke depan dan diambil kurang lebih persis dari upaya saya sebelumnya yang maju.

Terkompresi:

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

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

Tidak ada validasi input, dan input buruk dapat mengirimkannya ke infinite loop. Bekerja dengan baik dengan input tidak lebih besar dari 99 kali 99. Membutuhkan kompiler yang akan menghubungkan perpustakaan standar tanpa menyertakan header apa pun. Dan saya pikir saya sudah selesai, strager telah saya kalahkan dengan peregangan yang cukup, bahkan dengan bantuannya.

Saya agak berharap seseorang akan menunjukkan cara yang lebih halus untuk menyelesaikan tugas. Tidak ada yang salah dengan ini, tetapi ini bukan sihir yang dalam.

dmckee
sumber
Tidak perlu untuk =0global karena mereka diinisialisasi ke 0 secara default. Ganti konstanta karakter dengan padanannya dalam desimal. Gunakan >0sebagai ganti !=EOFuntuk mengecek terhadap EOF (dan \0). Anda mungkin dapat #definemenghapus beberapa kode caseseperti yang saya lakukan dengan kode if. Tidak perlu untuk tambahan \ndalam putskarena putsharus mencetak baris baru. for(;;)lebih pendek dariwhile(1) . Semoga ini membantu. =]
strager
@ strager: Terima kasih. Aku selalu datang di ini iteratif, karena saya tidak berpikir seperti itu ...
dmckee --- mantan moderator kitten
2
"There is no input validation"- Seharusnya tidak ada. Untuk memudahkan pegolf, input diasumsikan selalu 'bersih' kecuali ditentukan lain.
LiraNuna
@ Dmckee, Jangan khawatir, kami pro Golf Code bekerja iteratif juga. Namun, kami biasanya menggunakan beberapa trik sejak awal (seperti setengah dari yang saya sebutkan), tetapi itu datang dengan pengalaman. =]
strager
Kecuali saya salah menghitung, program ini 390 karakter, bukan 380.
strager
6

Ruby - 146 Chars

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
John La Rooy
sumber
5

PostScript , 359 byte

Upaya pertama, banyak ruang untuk perbaikan ...

/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 =
KirarinSnow
sumber
4

Haskell, 395 391 383 361 339 karakter (dioptimalkan)

Masih menggunakan mesin keadaan umum, bukan apa pun yang pintar:

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}

Versi yang dapat dibaca:

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
comingstorm
sumber
3

Saya percaya pada Penggunaan Kembali Kode, saya akan menggunakan salah satu kode Anda sebagai API :).

  menempatkan Board.new.validate (input)

32 karakter \ o / ... wohoooo

Rishav Rastogi
sumber
6
itu momok ganda!
Jeff Atwood
3
Mengalahkan Anda untuk itu: p Board.new.validate input 26 karakter \ o /
Alessandra Pereyra
3

C ++: 388 karakter

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


Bagaimana itu bekerja:

Pertama, semua baris dibaca, kemudian, laser ditemukan. Berikut ini akan dievaluasi 0selama tidak ada panah laser yang ditemukan, dan waktu yang sama akan ditetapkan ke xposisi horizontal.

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

Kemudian kita melihat ke arah mana kita menemukan dan menyimpannya i. Nilai igenap atas / kiri ("menurun") dan nilai ganjil adalah bawah / kanan ("meningkat"). Menurut gagasan itu, d("arah") dan r("orientasi") ditetapkan. Kami mengindeks array pointer zdengan orientasi dan menambahkan arah ke integer yang kami dapatkan. Arah berubah hanya jika kita memukul garis miring, sementara itu tetap sama ketika kita memukul garis miring. Tentu saja, ketika kita menabrak cermin, maka kita selalu mengubah orientasi ( r = !r).

Johannes Schaub - litb
sumber
Anda membuat saya melakukan solusi C ++ saya sendiri. =]
strager
2
@ Strager, ini semakin membosankan. Mari kita lakukan solusi yang menampilkan "benar" atau "salah" pada waktu kompilasi xD
Johannes Schaub - litb
menambahkan penjelasan karena saya pikir saya akan tetap melakukannya :)
Johannes Schaub - litb
2

Karakter Groovy @ 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
Pendeta Gonzo
sumber
2

C #

1020 karakter.
1088 karakter (input ditambahkan dari konsol).
925 karakter (variabel refactored).
875 karakter (dihapus initializer Kamus berlebihan; diubah ke Biner & operator)

Membuat titik untuk tidak melihat orang lain sebelum memposting. Saya yakin itu bisa sedikit sedikit LINQ. Dan seluruh metode FindLaser dalam versi yang dapat dibaca tampaknya sangat mencurigakan bagi saya. Tapi, itu berhasil dan sudah terlambat :)

Perhatikan bahwa kelas yang dapat dibaca mencakup metode tambahan yang mencetak Arena saat ini saat laser bergerak.

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

Versi yang Dapat Dibaca (bukan versi golf final, tetapi premis yang sama):

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;
        }
    }
}
Metro Smurf
sumber
2
Program harus mengambil input. Paling umum dari stdin.
LiraNuna
0

Perl 219
Versi perl saya memiliki panjang 392 342 karakter (saya harus menangani kasus balok yang mengenai laser):
Perbarui , terima kasih Hobbs untuk mengingatkan saya tr//, sekarang 250 karakter:
Perbarui , hapus mdalam m//, ubah dua whileloop yang dibawa sedikit tabungan; sekarang hanya ada satu ruang yang dibutuhkan.
( L:it;goto Lpanjangnya sama dengan 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

Saya mencukur beberapa, tetapi hampir tidak hanya bersaing dengan beberapa dari ini, meskipun terlambat.
Itu terlihat sedikit lebih baik sebagai:

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

Yah ... Sejujurnya ini harus cukup jelas jika Anda mengerti bahwa @bini adalah array array karakter di setiap baris, dan dapat membaca regexp dan trpernyataan sederhana .

dlamblin
sumber
Kiat: Anda dapat mempersingkat kode mirror Anda lebih tinggi. $_=$s;tr/^v<>/<>^v/dan $_=$s;tr/v^<>/<>^v/masing - masing. Juga, Anda tidak perlu mmasuk m//.
hobbs
Maaf, buat yang kedua$_=$s;tr/v^></<>^v/;
hobbs
Anda masih memiliki beberapa if m/.../yang dapat if/.../menyimpan dua karakter dalam satu pop.
hobbs
Anda dapat menggunakan y///alih-alih tr///menyimpan dua karakter.
Platinum Azure
0

F # - 454 (atau sekitar itu)

Agak terlambat ke permainan, tetapi tidak bisa menahan memposting upaya 2d saya.

Pembaruan sedikit dimodifikasi. Sekarang berhenti dengan benar jika pemancar dipukul. Jepit ide Brian untuk IndexOfAny (memalukan kalau kalimat itu sangat bertele-tele) Saya belum benar-benar berhasil mencari cara agar ReadToEnd kembali dari Konsol, jadi saya mengambil sedikit kepercayaan itu ...

Saya senang dengan jawaban ini, seolah-olah cukup pendek, masih cukup mudah dibaca.

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))
Benjol
sumber
Mereka adalah dekorasi. Periksa tantangan saya yang lain, itu hanya hal format.
LiraNuna
@LiraNuna, ok ternyata, iterasi ini hanya memakan mereka :)
Benjol
Akan lebih baik untuk membandingkan dengan implementasi 1-d. Cukup tambahkan / kurangi 1 untuk kiri dan kanan dan tambahkan / kurangi w untuk naik dan turun. Saya berharap Anda akan menghemat beberapa karakter
John La Rooy
@gnibbler, Brian sudah melakukan itu, saya tidak yakin saya bisa mengalahkannya, tapi saya mungkin mencobanya.
Benjol