Code Golf: Lazerler


152

Meydan okuma

Bir kartın 2B gösterimini girmek için girişe göre karaktere göre en kısa kod sayılır ve girişe göre 'true' veya 'false' çıktısı verilir .

Tahta 4 çeşit fayanstan oluşur:

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

Sadece bir lazer ve sadece bir hedef var . Duvarlar, lazer ve hedefin içine yerleştirildiği herhangi bir boyutta sağlam bir dikdörtgen oluşturmalıdır. 'Oda' içindeki duvarlar mümkündür.

Lazer ışını çeker ve başlangıç ​​noktasından işaret ettiği yöne doğru hareket eder. Lazer ışını duvara çarparsa durur. Lazer ışını bir aynaya çarparsa, aynanın işaret ettiği yöne 90 derece sıçrar. Aynalar iki taraflıdır, yani her iki taraf da 'yansıtıcıdır' ve bir ışın iki şekilde sıçrayabilir. Bir lazer ışını lazere ( ^v><) çarparsa, bir duvar olarak kabul edilir (lazer ışını beamer'ı yok eder ve böylece asla hedefe çarpmaz).

Test senaryoları

Giriş:
    ##########
    # / \ #
    # #
    # \ x #
    #> / #
    ########## 
Çıktı:
    doğru

Giriş:
    ##########
    # vx #
    # / #
    # / #
    # \ #
    ##########
Çıktı:    
    yanlış

Giriş:
    #############
    # # #
    #> # #
    # # #
    # # x #
    # # #
    #############
Çıktı:
    yanlış

Giriş:
    ##########
    # / \ / \ / \ #
    # \\ // \\\ #
    # // \ / \ / \\ #
    # \ / \ / \ / X ^ #
    ##########
Çıktı:
    doğru

Kod sayısı giriş / çıkışı (yani tam program) içerir.


84
IMMA ŞARJ MAH LAZER!
furlafur Ücreti

37
Bu harika .
GManNickG


49
@GameFreak: Gerçekten yaşlanıyor.
09:44

24
Bu '^' aslında kafasında garip bir lazer olan bir köpekbalığı mı?
Nathan Feger

Yanıtlar:


78

Perl, 166160 karakter

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

Bu yarışma sona erdiğinde çözüm 166 vuruş yaptı, ancak A. Rex, 6 karakteri daha tıraş etmenin birkaç yolunu buldu:

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

İlk satır, girişi satır i , sütun j'deki karakteri tutan %tbir tablo tablosuna yükler . Sonra,$t{99*i+j}

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

Bu elemanlarını arama %tbir karakter için stoktaki > ^ <veya v, ve aynı zamanda kümeler $dlazer ışınının ilk yönü belirten ve 0 ile 3 arasında bir değere düşürmektedir.

Ana döngüdeki her yinelemenin başında $d, ışının şu anda bir ayna üzerinde olup olmadığını güncelliyoruz . 3'e göre XOR'ing bir \ayna için doğru davranışı ve 1'e göre XOR'ing bir ayna için doğru davranışı verir /.

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

Ardından, geçerli konum $rgeçerli yöne göre güncellenir.

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

$_Maç operatörlerini rahatça kullanmak için karakteri mevcut pozisyonda atarız .

/[\/\\ ]/ && redo

Boşluk veya ayna karakterine devam edersek devam edin. Aksi takdirde true, hedefte ( $_ =~ /x/) ve falsebaşka türlü olup olmadığımızı feshederiz .

Sınırlama: 99'dan fazla sütunu olan sorunlar üzerinde çalışmayabilir. Bu sınırlama 3 karakter daha eklenebilir,


Tamam, 323 karakter var. = D
strager 26:09

5
3 karakter pahasına çok sağlam hale getirmek için 99'u 1E5'e değiştirebilirim.
mafya

2
En iyi çözümünüz, yazının üst kısmında daha dikkat çekici olacaktır.
strager

13
Ama tahta döndürmek için düzenli ifadeler kullanarak? Bu hastaydı. Bu otomatik 20 vuruş bonusu gibi.
mafya

1
@mobrule: daha fazla altı vuruş: ilk hat yeniden sıralama s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;değişim, %d=split//,.." to % d = .. = ~ /./ gr , and change grep {..}% t 'içingrep..,%t
C. Rex

75

Perl, 177 Karakter

İlk satır kırılması kaldırılabilir; diğer ikisi zorunlu.

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

Açıklama:

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

Sağa doğru hareket eden bir kiriş {boş alan, yukarı açılı ayna, aşağı açılı ayna} içine doğru koşarsa, {sağa doğru hareket eden kiriş, yukarı hareket eden kiriş, aşağı hareket eden kiriş} olur. $/Yol boyunca başlat - neyse ki "6" geçerli bir giriş karakteri değil.

$_ = <>;

Kurulu okuyun $_.

$s="#";

$skirişin şu an üstünde oturduğu şeyin sembolüdür. Lazer vericisi bir duvar gibi muamele göreceğinden, bunu başlangıç ​​için bir duvar olarak ayarlayın.

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

Lazer ışını sağdan başka bir yönü gösteriyorsa, sembolünü döndürün ve ardından tüm kartı yerine döndürün (aynaların sembollerini de döndürün). 90 derecelik bir sola dönüş, s///eyan etkileri ile hafifçe şeytani bir şekilde satırları ve sütunları aktarırken satırları tersine çevirerek etkili bir şekilde gerçekleştirilir . Golf kodunda, tr y'''bir ters eğik çizgi geri atlamayı atlamamı sağlayan formda yazılmıştır .

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

Hedefe veya duvara çarptığımızda doğru mesajla sonlandırın.

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

Lazerin önünde boş bir alan varsa, ilerleyin. Lazerin önünde bir ayna varsa, ileri doğru hareket edin ve ışını döndürün. Her iki durumda da, "kaydedilen sembolü" eski ışın konumuna geri koyun ve üzerine yazdığımız şeyi kaydedilen sembole koyun.

redo;

Sonlandırılana kadar tekrarlayın. {...;redo}iki karakterden küçük for(;;){...}ve üç karakterden küçük while(1){...}.


4
Tahtayı döndür ... Çılgın. Normal ifade ... Crazier. O_o
strager

39
Sen ... Sen canavar!
LiraNuna

4
LiraNuna: Bunu iltifat olarak almayı seçiyorum.
Ocaklar

21
Golf bitti. Bir 2D tahtayı düzenli ifadelerle döndürmeyi nasıl yenebilirsiniz ?!
Konrad Rudolph

13
o ne lan? perl programcıları sihirbazdır.
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;);}

açıklama

C'yi anlamadıysanız, bu canavarlığı takip etmek muhtemelen zor olacaktır. Sadece bir önsöz.

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

Bu küçük makro, geçerli karakterin ( *p) akarakter biçimindeki ( *#a) karaktere eşit olup olmadığını kontrol eder . Eşitlerse, hareket vektörünü b( m=b) olarak ayarlayın, bu karakteri bir duvar ( *p=1) olarak işaretleyin ve başlangıç ​​noktasını geçerli konuma ( q=p) ayarlayın. Bu makro "else" bölümünü içerir.

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

Bazı değişkenler bildirin. * qışığın geçerli konumudur. * G1D dizisi olarak oyun tahtasıdır. * pdoldurma sırasındaki geçerli okuma konumudur G. * wtahta genişliğidir.

main(m){

Açık main. mhareket vektörünü depolayan bir değişkendir. (Bu mainbir optimizasyon parametresidir .)

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

GKullanarak doldurarak tüm karakterler arasında dolaşın p. G[0]Bir optimizasyon olarak atlayın (bir karakterin püçüncü bölümünde tekrar bir yazı yazmanıza gerek yoktur for).

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

Mümkünse lazeri tanımlamak için yukarıda belirtilen makroyu kullanın. -1ve 1tekabül hakkı, sırasıyla sol ve -wve wyukarı ve aşağı.

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

Geçerli karakter bir satır sonu işaretleyicisiyse (ASCII 10), henüz ayarlanmamışsa genişliği ayarlayın. Atlanan G[0], w=p-Gbunun yerine yazmamızı sağlar w=p-G+1. Ayrıca, bu 's ?:zinciri bitirir M.

    for(;
        q+=m,

Işığı hareket vektörü ile hareket ettirin.

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

Hareket vektörünü yansıtın.

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

Bu bir duvarsa veya xuygun mesajla çıkın ( m=0döngüyü sonlandırır). Aksi takdirde, hiçbir şey yapmayın (noop; m=m)

    );
}

8
Ihh! Apartman kompleksimde yangın alarmı çaldığında C çözümü üzerinde çalışıyordum. Şimdi yenildim. Güzel bir çözüm olsa.
rlbond

Takas ve takas / olumsuzlama adımlarınız için geçici bir değişken kullanan methinks size birkaç karakter kazandırır.
Artelius

@Artelius, Evet, bunu fark ettim ve birkaç şey daha. Teşekkürler.
Strager

1
TCC, henüz g.c:3: declaration expected
türetilmemiş

2
Kaldırılması'nın putsaçıklaması yardımcı oldu, ancak 170'in altına getirmek için yeterli değil. 209 oldukça iyi, bu yüzden bence bunu bırakacağım. Yardımın için teşekkürler çocuklar. Gerçekten onu takdir ederim. =] (Bir şey o Perl cadıları koltuğundan indirmeyi!)
strager

36

Eminim insanlar LOOOOONG bir süredir bunu bekliyordu. (Ne demek istiyorsun, meydan okuma bitti ve kimse artık umursamıyor mu?)

Bakın ... Ben burada bir çözüm sunuyorum

Befunge-93!

Ağır bir 973 karakter ağırlığındadır (veya yalnızca biçimlendirme için kullanılan ve gerçek kodda hiçbir şey yapmayan beyaz boşluğu yok saymaya yeteri kadar hayırseverseniz 688 ).

Dikkat : Kısa bir süre önce Perl'e kendi Befunge-93 tercümanımı yazdım ve maalesef test etmek için gerçekten zamanım vardı. Genel olarak doğruluğundan oldukça eminim, ancak EOF ile ilgili garip bir sınırlama olabilir: Perl'ün <>operatörü dosyanın sonunda undef döndürdüğünden, bu sayısal bağlamda 0 olarak işlenir. EOF'un farklı bir değere (-1 say) sahip olduğu C tabanlı uygulamalar için bu kod çalışmayabilir.

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

açıklama

Befunge sözdizimi ve işlemine aşina değilseniz, buraya bakın .

Befunge, yığın tabanlı bir dildir, ancak Befunge koduna karakter yazmasına izin veren komutlar vardır. Bundan iki yerde faydalanıyorum. İlk olarak, tüm girdiyi Befunge kartına kopyalarım, ancak gerçek yazılı kodun altında birkaç satır buldum. (Elbette, kod çalıştığında bu hiçbir zaman görünmez.)

Diğer yer sol üst köşeye yakın:

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

Bu durumda, yukarıda vurguladığım alan birkaç koordinat sakladığım yerdir. Orta satırdaki ilk sütun, geçerli "imleç konumu" için x koordinatını depoladığım yer; ikinci sütun y koordinatını sakladığım yerdir; sonraki iki sütun, bulunduğunda lazer ışını kaynağının x ve y koordinatlarını saklamak içindir; ve son sütunun (içinde 'a' karakteri ile) üzerine, kirişin yolu izlendikçe açıkça değişen mevcut ışın yönünü içerecek şekilde üzerine yazılır.

Program, başlangıçtaki imleç konumu olarak (0,27) yerleştirilerek başlar. Daha sonra giriş her seferinde bir karakter okunur ve imleç konumuna yerleştirilir; yeni satırlar sadece y koordinatının artmasına ve x koordinatının gerçek bir satırbaşı gibi 0'a dönmesine neden olur. Sonunda undef yorumlayıcı tarafından okunur ve girişin sonunu bildirmek ve lazer yineleme adımlarına geçmek için 0 karakter değeri kullanılır. Lazer karakteri [<> ^ v] okunduğunda, bu da bellek havuzuna ('a' karakterinin üzerinde) kopyalanır ve koordinatları hemen soldaki sütunlara kopyalanır.

Tüm bunların sonucu, tüm dosyanın temel olarak Befunge koduna kopyalanmasıdır, çapraz gerçek kodun biraz altında.

Daha sonra, ışın konumu imleç konumlarına geri kopyalanır ve aşağıdaki yineleme gerçekleştirilir:

  • Geçerli ışın yönünü kontrol edin ve imleç koordinatlarını uygun şekilde artırın veya azaltın. (Bunu ilk harekette lazer ışınının köşe kasasıyla uğraşmaktan kaçınmak için yapıyorum.)
  • O konumdaki karakteri okuyun.
  • Karakter "#" ise, yığının üstüne satırsonu, "false" ve "false" yazın, yazdırın ve sonlandırın.
  • Tüm ışın karakterleriyle karşılaştırın [<> ^ v]; bir eşleşme varsa "false \ n" yazıp sonlandırın.
  • Karakter bir boşluksa, yığını boşaltın ve devam edin.
  • Karakter bir eğik çizgi ise, ışın yönünü yığına alın ve sırayla yön karakterlerinin her biri ile karşılaştırın. Bir tane bulunduğunda, yeni yön koddaki aynı noktada saklanır ve döngü tekrar eder.
  • Karakter ters eğik çizgi ise, temel olarak yukarıdakiyle aynı şeyi yapın (ters eğik çizgi için uygun eşleme hariç).
  • Karakter 'x' ise, hedefi vurduk. "True \ n" yazıp çıkın.
  • Karakter bunlardan hiçbiri değilse, "error \ n" yazıp çıkın.

Bunun için yeterli talep varsa, kodun neresinde yapıldığını tam olarak göstermeye çalışacağım.


14
+1 - Yalnızca not defterinde açılan bir EXE olduğu yanlış yorumlanabildiğinden.
Kyle Rosendo

1
Um ... kutsal ****. Befunge ile uğraştım ve bu gerçekten çok etkileyici.
Almo

Gizli dillerde golf kodlayın ... fıstık ezmesi ve acı gibi!
wberry

29

F #, 36 satır, çok okunabilir

Tamam, sadece bir cevap almak için:

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    

Örnekler:

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

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

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

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

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

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

54
GERÇEKTEN BU BİR OKUMA! MUCİZEVİ!
Jeff Atwood

17
Java / C # kodu golf karakter değil satırlarla sayılır. Bu handikap.
Nathan Feger

3
@strager, kodu korumak için işe alındığınızda ve orijinal geliştiricinin çoktan ayrıldığından beri 3 yıl içinde iç karartıcı olmaması.
Nathan Feger

Bu, Visual Studio 2010'da F # kullanılarak başarısız olur. Seq.to_list mevcut değil (tamam, listeyi List olarak değiştirdi) ve sonra Satır 25, eksik desen eşleşmesi.
Russell

2
Evet, şimdi_listesini şimdi Liste olarak değiştirin. Eksik eşleşme uyarısı iyi; Bu kod golf, bu yüzden gibi kod yapmadım: | _ -> başarısız "imkansız"
Brian

29

Golfscript - 83 karakter (benim ve strager'lerin karışımı)

Yeni satır sadece sarmak için burada

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

Golfscript - 107 karakter

Yeni satır netlik için orada

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

Nasıl çalışır.

İlk satır başlangıç ​​konumunu ve yönünü belirler.
İkinci çizgi, lazer bir aynaya çarptığında dönerek ilerler.


18

353 karakter Ruby'de:

314 277 karakter şimdi!

Tamam, Ruby'de 256 karakter ve şimdi işim bitti. Durmak için güzel yuvarlak sayı. :)

247 karakter. Durduramıyorum.

223 203 Ruby 201 karakter

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

Boşluk ile:

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

Biraz yeniden düzenlenmiş:

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

Fakat ... adlandırabilirsiniz chiçin C2 karakter kurtarmak için başka 1 karakter harf veya!
LiraNuna

Tamam tamam, güzel ... Aslında sadece bir kez kullandığım için bütün değişkenin gereksiz olduğunu fark ettim. Bu ve diğer birkaç gelişme 247 karaktere kadar azaldı.
Jeremy Ruten

1
Hayır i++(yerine i+=1)?
LiraNuna

6
Hayır! ++ i yapabilirsiniz, ancak eskiden olduğu kadar gerçekten olumlu yapar.
DigitalRoss

Sıkıştırılmış versiyonu beğendim: #; p
SeanJA 22

17

piton

294 277 253 240 satırbaşıyla dahil 232 karakter:

(4. ve 5. satırlardaki ilk karakter boşluk değil sekmedir)

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

Python'un isteğe bağlı noktalı virgülleri olduğunu bile unutmuştum.

Nasıl çalışır

Bu kodun arkasındaki ana fikir, konumları ve yönleri temsil etmek için karmaşık sayılar kullanmaktır. Satırlar aşağı doğru artan hayali eksendir. Sütunlar sağa doğru artan gerçek eksendir.

l='>v<^';lazer sembollerinin bir listesi. Sıra, lazer yön karakterinin indeksinin sqrt (-1) gücüne karşılık geleceği şekilde seçilir

x={'/':'^<v>','\\':'v>^<',' ':l};kiriş farklı fayanslardan ayrıldığında yönün nasıl değiştiğini belirleyen bir dönüşüm tablosu. Döşeme anahtardır ve yeni yönler değerlerdir.

b=[1];yönetim kurulu tutar. İlk öğe 1'dir (doğru olarak değerlendirilir), bu nedenle while döngüsü en az bir kez çalışır.

r=p=0 rgirişin geçerli satır sayısı p, lazer ışınının geçerli konumudur.

while b[-1]: raw_input boş bir dize döndürdüğünde pano verilerini yüklemeyi durdurma

b+=[raw_input()];r+=1 bir sonraki girdi satırını karta ekle ve satır sayacını artır

for g in l: sırayla her lazer yönünü tahmin

c=b[r].find(g) çizgide değilse (veya farklı bir yönü gösteriyorsa) sütunu lazerin konumuna veya -1'e ayarlayın

if-1<c:p=c+1j*r;d=gbir lazer bulursak, o anki konumu pve yönü ayarlayın d. diçindeki karakterlerden biril

Karta yüklendikten sonra b, geçerli konum pve yön dlazer kaynağına göre ayarlanmıştır.

while' '<d: alan herhangi bir yön sembolünden daha düşük bir ASCII değerine sahiptir, bu yüzden onu dur işareti olarak kullanırız.

z=l.find(d);ldizedeki geçerli yön karakter dizini. zdaha sonra hem xtabloyu kullanarak yeni ışın yönünü belirlemek hem de konumu artırmak için kullanılır.

p+=1j**z;i gücünü kullanarak konumu artırın. Örneğin l.find('<')==2, soldan bir sütuna taşınacak olan -> i ^ 2 = -1.

c=b[int(p.imag)][int(p.real)]; mevcut pozisyondaki karakteri oku

d=x.get(c,' '*4)[z]dönüşüm tablosundaki kirişin yeni yönüne bakın. Geçerli karakter tabloda yoksa, dboşluk olarak ayarlayın .

print'#'<c hedeften başka bir şey üzerinde durduysak false yazdır.


9
p+=1j**z: Çok tatlı.
dmckee --- ex-moderatör kedi yavrusu

16

Bu is oldu C # 3'e Brian'ın çözümün doğrudan bir bağlantı noktası, eksi konsol etkileşimleri. Bu tam bir program olmadığı için meydan okumaya bir giriş değil, sadece kullandığı F # yapılarının bazılarının C # ile nasıl temsil edileceğini merak ediyordum.

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

Düzenleme: Bazı denemelerden sonra, aşağıdaki ayrıntılı arama kodu:

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

bazı daha kompakt LINQ to Objects kodu ile değiştirildi:

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

8
Aman Tanrım. Ne kadar güçlü linq ve c # olduğunu göstermek için ne güzel bir örnek. 1+ için ben büyük bir c # hayranıyım. x)
Emiswelt

16

F #, 255 karakter (ve yine de okunabilir!):

Tamam, bir gece dinlendikten sonra bunu çok geliştirdim:

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

Şimdi satır satır konuşalım.

İlk olarak, tüm girişi büyük bir tek boyutlu diziye kaydırın (2D diziler kod golfü için kötü olabilir; sadece 1D dizisi kullanın ve bir çizgiyi yukarı / aşağı taşımak için bir çizginin genişliğini dizine ekleyin / çıkarın.

Daha sonra dizimize endeksleyerek bir giriş çizgisinin genişliğini 'w' ve başlangıç ​​konumu 'c' hesaplıyoruz.

Şimdi 'c' akımını ve yukarı, sol, sağ, aşağı için 0,1,2,3 olan 'd' yönünü alan 'sonraki' fonksiyonunu 'n' tanımlayalım.

Dizin-epsilon 'e' ve eğik çizgiye çarptığımızda yeni yön 'bir tablo ile hesaplanır. Örneğin, geçerli 'd' yönü 0 (yukarı) ise, tablonun ilk elemanı "-w, 2" yazar, bu da indeksi w ile düşürdüğümüz anlamına gelir ve bir eğik çizgiye çarptığımızda yeni yön 2 olur (sağ).

Şimdi (1) bir sonraki indeks ("c + e" - mevcut artı epsilon) ve (2) dizide ne olduğunu görmek için ileriye doğru baktığımız yeni yönü kullanarak bir sonraki 'n' fonksiyonuna geri dönüyoruz. bir sonraki hücre. Eğer ileriye doğru karakter bir eğik çizgi ise, yeni yön 's' olur. Ters eğik çizgi varsa, yeni yön 3 saniyedir (0123 kodlama seçeneğimiz bu işi yapar). Eğer bir boşluksa, aynı yönde devam ediyoruz 'd'. Ve eğer başka bir 'c' karakteri varsa, oyun biter, eğer karakter 'x' ise aksi takdirde 'true' yazar.

İşleri başlatmak için, başlangıç ​​konumu 'c' ve başlangıç ​​yönü olan (n yönün ilk kodlamasını 0123'e yapan) özyinelemeli işlev 'n' olarak adlandırılır.

Ben muhtemelen hala birkaç karakter daha tıraş olabilir düşünüyorum, ama bunun gibi oldukça memnunum (ve 255 güzel bir sayıdır).


11

18203 karakter ağırlığında bir Python çözümü:

  • 'oda' dışındaki aynalarla başa çık
  • 2B sınırlamalara göre 'oda' olmadığında yörüngeyi hesaplayın (spesifikasyon 'odada' olması gerekenler hakkında çok şey söylüyor, ancak oda olması gerekiyorsa değil)
  • hataları rapor et

Hala biraz toparlanması gerekiyor ve 2D fiziğin ışının kendini geçemediğini dikte edip etmediğini bilmiyorum ...

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

Renk hatası raporlamasını gösteren bir bash betiği:

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

Gelişimde kullanılan birim testler:

#!/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
Lazer fiziği ışın dikte edebilir kendisini geçmeye. Yukarıdaki yorum önemli bir kültürel referanstır.
dmckee --- eski moderatör yavru kedi

5
Kaplumbağa ve Hare golf kod yaklaşımı. Açıkçası çok fazla karakter (mevcut kazanandan 91 kat daha fazla) olan bir şey sunun, ancak spesifikasyonun her harfine dikkat edin. Yavaş ve istikrarlı genellikle bana daha az sözleşme işi alır.
Metalshark

Unittest'inizin bir kısmı eksik gibi görünüyor. "Self.NOT_DIRECTIO" da kesildi
BioGeek

@BioGeek - gönderi uzunluğunun nasıl sınırlandırıldığını;). Ayrıca BASH stil testleri renk vurgulamasını gösterir.
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}

Basit bir durum makinesi kullandım (çoğu poster gibi), hiçbir şey fantezi değil. Sadece aklınıza gelebilecek her numarayı kullanarak aşağı fırlatıp durdum. Yönü değiştirmek için kullanılan bitsel XOR (değişkende tamsayı olarak saklanır c) önceki sürümlerde kullandığım koşullara göre büyük bir gelişmeydi.

Kodun arttığı xve ykısaltılabileceğinden şüpheleniyorum . Kodun artımı yapan bölümü:

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

Düzenleme : Yukarıda biraz kısaltmak mümkün:

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

Lazerin mevcut yönü caşağıdaki gibi saklanır:

0 => yukarı
1 => aşağı
2 => sol
3 => sağ

Kod bu gerçeğe artışa xve ydoğru miktara (0, 1 veya -1) dayanır . Aritmetik versiyondan daha kısa olacağına dair nagging hissim olduğu için, hangi sayıların her yöne eşlendiğini yeniden düzenlemeyi denedim.


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

Biraz daha okunabilir:

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

Karakterlerin ana israfı haritanın genişliğini ve lazer kaynağının konumunu bulmak gibi görünüyor. Bunu kısaltmak için herhangi bir fikrin var mı?


Bu kısa olup olmadığından emin değilim ama lazeri bulma ve genişliği bulmadaki çekimim: L = List <string> kullanarak; P = System.Drawing.Point; L = List <string> kullanarak; L r = yeni L () {"v", "<", ">", "^"}; P p = yeni 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]. uzunluk; v, tabloyu içeren bir <string>
Listesidir

daha iyi: L = Liste <dizgisini> kullanarak; L l = yeni L (4) {"v", "<", ">", "^"}; var noktası = yeni {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]. uzunluk;
RCIX

4
Sorunlar bir fonksiyon değil, tam bir program ister.
Strager

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

Bu C çözümü, XOR ayna hilesi kullanmamızı sağlayan bir ASCII karakter setini varsayar. Ayrıca inanılmaz derecede kırılgandır - örneğin tüm giriş satırları aynı uzunlukta olmalıdır.

200 karakter işaretinin altına iner - ama tehlikeye at, hala bu Perl çözümlerini yenmedi!


= O! 1! Beni dövdüğü için rendeler. =]
strager

2
Buradaki en iyi çözümler "tüm hatlar aynı uzunluktadır" varsayımına sahiptir. Hepsi golf ve savaşta adil.
Ocaklar

Çizgiler aynı uzunlukta olmasaydı, bunun için bir test durumu eklerdim. ama açıkça kasıtlı olduğunu söyledim :)
LiraNuna

9

Golfscript (83 karakter)

Merhaba 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

Python - 152

"L" adlı bir dosyadan girişi okur

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

Stdin'den okumak için ilk satırı bununla değiştirin

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

Küçük / doğru true / false değerine ihtiyacınız varsa, son satırı şu şekilde değiştirin:

print`D<5`.lower()

Değiştirmek ve değiştirmek Trueiçin kaç karakter gerekir ? ;-)trueFalsefalse
mafya

"Print D<5" değerini "print D <5" olarak değiştirerek 1 karakteri kaldıramıyor musunuz? Yoksa özlediğim bir şey var mı?
Ponkadoodle

@ wallacoloo, tabii ki yapabilirsin. Sadece doğru / yanlış küçük harf için gereklidir
John La Rooy

7

JavaScript - 265 Karakter

IV Güncellemesi - Oranlar, bu bir do-while döngüsüne geçip hareket denklemini yeniden yazarak birkaç karakter daha kaydetmeyi başaran son güncelleme turu olacak.

Güncelleme III - Math.abs () 'ı kaldırma ve değişkenleri genel ad boşluğuna koyma konusundaki öneri sayesinde, değişken atamalarının yeniden düzenlenmesi ile birlikte kodu 282 karaktere indirdi.

Güncelleme II -! = -1 kullanımını ve daha uzun işlemler için değişkenlerin daha iyi kullanılmasını kaldırmak için kodda bazı güncellemeler.

Güncelleme - Bittiğinde ve indexOf işlevine (teşekkürler LiraNuna!) Bir referans oluşturarak ve gerekli olmayan parantezleri kaldırarak bazı değişiklikler yaptı.

Bu benim ilk kez bir kod golf yapıyor, bu yüzden ne kadar iyi olabilir emin değilim, herhangi bir geri besleme takdir edilmektedir.

Tamamen küçültülmüş versiyon:

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}

Yorumları içeren orijinal sürüm:

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

Test edilecek web sayfası:

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

nasıl girdi alır? Bunu test etmek ve doğrulamak istiyorum. Ayrıca, bir referansı a.indexOf'a kaydederseniz çok sayıda karakter kaydedebilirsiniz
LiraNuna

Değiştir index != -1ile index > 0lütfen! (Umarım kimse lazeri sol üst köşeye yerleştirmez, bu yüzden 0döndürülmez. =]) varİfadeleri zincirleyebilir veya onlardan tamamen kurtulabilirsiniz (değişkenleri global ad alanına koyabilirsiniz ). Bence Math.abs(m)==1değiştirilebilir m==-1|m==1. İçin movement = ...; location += movementoptimize edilebilir location += movement =?
strager

@ strager- Sadece yorumunuzu gördüm, kodun güncellenmesi sırasında 300 karaktere kadar yayınladığınız anlaşılıyor. Math.abs () 'nin kaldırılmasıyla neler yapabileceğimi göreceğim.
rjzii

function(a){return g.indexOf(a)}, function(a)g.indexOf(a)son JavaScript sürümlerinde değiştirilebilir.
user1686

6

Aynalar Evi

Meydan okumaya gerçek bir giriş değil, ama bu konsepte dayanan bir oyun yazdım (çok uzun değil).

Scala dilinde yazılmış, açık kaynak kodlu ve burada mevcut :

Biraz daha fazlasını yapar; renkler ve çeşitli aynalar ve aygıtlarla ilgilenir, ancak 0.00001 sürümü bu sorunun tam olarak ne istediğini yaptı. Yine de bu sürümü kaybettim ve asla karakter sayımı için optimize edilmedi.


Scala yüklemeye gerek kalmadan Windows altında çalışan derlenmiş bir sürümü yüklemeniz mümkün müdür?
Milan

Scala kütüphanelerinin dahil olduğu bir versiyon var. İndirilenler listesine bakın. Her neyse, Scala'yı şu ana kadar yüklediyseniz, bunu yapmanıza sevindim :)
HRJ

6

c (K&R) Strager'dan daha fazla öneri alındıktan sonra 339 gerekli karakter.

İçimdeki fizikçi, yayılma ve yansıtma işlemlerinin zamana ters değişmez olduğunu kaydetti, bu nedenle bu versiyon, hedeften ışınlar atıyor ve lazer yayıcıya ulaşıp ulaşmadığını kontrol ediyor.

Uygulamanın geri kalanı çok basittir ve az ya da çok tam olarak daha önceki ileriye dönük çabamdan alınır.

Sıkıştırılmış:

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

Sıkıştırılmamış (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");
}

Giriş doğrulaması yoktur ve hatalı giriş bunu sonsuz döngüye gönderebilir. 99'dan 99'a kadar büyük olmayan girdilerle düzgün çalışır. Standart kitaplığı üstbilgileri içermeden bağlayacak bir derleyici gerektirir. Ve sanırım işim bitti, strager beni yardımı ile bile hatırı sayılır bir şekilde yendi .

Birisinin görevi yerine getirmek için daha ince bir yol göstereceğini umuyorum. Bunda yanlış bir şey yok, ama derin bir sihir değil.


=0Varsayılan olarak 0'a ayarlandıkları için globallere gerek yoktur . Karakter sabitlerini ondalık olarak eşdeğerleriyle değiştirin. Kullanım >0yerine !=EOFEOF (ve karşılaştırmalı olarak kontrol edilecek \0). Muhtemelen #definebazı kodları caseile yaptığım gibi uzakta olabilir if. Ekstra gerek yok \niçinde putsolduğu gibi putsyine bir yeni satır yazdırmak gerekir. for(;;)daha kısadır while(1). Bu yardımcı olur umarım. =]
strager

@strager: Teşekkürler. Ben her zaman yinelemeli olarak gelirim, çünkü öyle düşünmüyorum ...
dmckee --- eski moderatör kedi yavrusu

2
"There is no input validation"- Hiç olmamalı. Golfçülerin işini kolaylaştırmak için, aksi belirtilmedikçe, girdilerin her zaman 'temiz' olduğu varsayılır.
LiraNuna

@ dmckee, Endişelenme, bize Code Golf profesyonelleri de tekrar tekrar çalışıyor. Bununla birlikte, genellikle en başından beri bazı hileler kullanırız (bahsettiğimlerin yarısı gibi), ancak bu deneyim ile birlikte gelir. =]
strager

Yanlış
saymadıkça

6

Yakut - 146 Karakter

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 bayt

İlk girişim, iyileştirme için çok fazla alan ...

/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'in 395 391 383 361 339 karakter (optimize edilmiş)

Akıllıca bir şey yerine, hala genel bir durum makinesi kullanıyor:

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}

Okunabilir bir versiyon:

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

Code Reuse inanıyorum, ben bir API gibi kodunuzu kullanmak istiyorum :).

  Board.new.validate (giriş) koyar

32 karakter \ o / ... wohoooo


6
bu bir çift bataklık!
Jeff Atwood

3
Onu yenin: p Board.new.validate giriş 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");}

( Başlıksız 318 )


Nasıl çalışır:

İlk olarak, tüm satırlar okunur, daha sonra lazer bulunur. Aşağıda, 0henüz lazer oku bulunmadığı ve aynı zamanda xyatay konuma getirildiği sürece değerlendirilecektir .

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

Sonra hangi yönde bulduğumuza bakıp saklıyoruz i. Değerleri iüst / sol ("azalan") ve tek değerler alt / sağ ("artan"). Bu görüşe göre, d("yön") ve r("yön") ayarlanır. İşaretçi dizisini zyönlendirmeyle dizinler ve yönü elde ettiğimiz tamsayıya ekleriz. Yön sadece bir eğik çizgiye çarptığımızda değişir, ters eğik çizgiye çarptığımızda aynı kalır. Tabii ki, bir aynaya çarptığımızda, her zaman yönelimi değiştiririz ( r = !r).


Beni kendi C ++ çözümümü yapıyorsun. =]
strager 28:30

2
@strager, bu yine de sıkıcı oluyor. Derleme zamanında "true" veya "false" görüntüleyen bir çözüm yapalım
Johannes Schaub - litb 28:09

Ben bu devam edeceğini düşünüyorum beri açıklama eklendi :)
Johannes Schaub - litb 4

2

Groovy @ 279 karakter

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 karakter.
1088 karakter (konsoldan girdi eklendi).
925 karakter (yeniden düzenlenmiş değişkenler).
875 karakter (gereksiz Sözlük başlatıcısı kaldırıldı; İkili ve operatörler olarak değiştirildi)

Göndermeden önce kimsenin bakmamasına dikkat edin. Eminim biraz LINQ'd olabilir. Ve okunabilir versiyondaki tüm FindLaser yöntemi bana çok balık gibi geliyor. Ama işe yarıyor ve geç oldu :)

Okunabilir sınıfın, lazer hareket ederken mevcut Arena'yı bastıran ek bir yöntem içerdiğine dikkat edin.

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

Okunabilir Sürüm (son golf versiyonu değil, aynı öncül):

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
Program girdi almalıdır. En sık stdin'den.
LiraNuna

0

219 Perl
Benim perl versiyonu 392 : (Ben lazeri isabet ışının durumda idare vardı) uzun 342 karakter
Güncelleme bana hatırlatan için teşekkürler Hobbs tr//şimdi 250 karakter var,:
Güncelleştirme , çıkarmadan miçinde m//, iki değişen whilegetirdi döngüler birkaç tasarruf; artık sadece bir alan gerekiyor.
( L:it;goto Lile aynı uzunluktadır 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

Biraz traş ettim ama geç olsa da, bunlardan bazılarıyla neredeyse hiç rekabet etmiyor.
Biraz daha iyi görünüyor:

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

Şey ... Dürüst olmak gerekirse @b, her satırdaki karakterlerden oluşan bir dizi dizisi olduğunu ve basit regexp ve trifadeleri okuyabileceğinizi anlarsanız bu açıklayıcı olmalıdır .


İpucu: ayna kodunuzu yukarı doğru kısaltabilirsiniz. $_=$s;tr/^v<>/<>^v/ve $_=$s;tr/v^<>/<>^v/sırasıyla. Ayrıca, gerek yok min m//.
Ocaklar

Üzgünüm, ikincisini yap$_=$s;tr/v^></<>^v/;
ocaklar

Hala iki karakteri bir pop kaydedebilir birkaç if m/.../var if/.../.
Ocaklar

İki karakteri kaydetmek y///yerine kullanabilirsiniz tr///.
Platinum Azure

0

F # - 454 (veya civarı)

Oyuna biraz geç kaldım, ancak 2d girişimimi yayınlamaya direnemiyorum.

Güncelleme biraz değiştirildi. Verici vurulursa artık doğru durur. Brian'ın IndexOfAny için fikrini sıkıştırdı (utanç o çizgi çok ayrıntılı). Aslında ReadToEnd konsoldan dönmek için nasıl çalışmayı başaramadım, bu yüzden bu güven üzerine alıyorum ...

Bu cevaptan memnunum, oldukça kısa gibi, hala oldukça okunabilir.

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

Onlar dekorasyon. Diğer zorluklarımı kontrol et, bu sadece biçimlendirici bir şey.
LiraNuna

@LiraNuna, tamam çıkıyor, bu yineleme onları zaten yiyor :)
Benjol

1-boyutlu bir uygulama ile karşılaştırmak güzel olurdu. Sadece sol ve sağ için 1 ekleyin / çıkarın ve yukarı ve aşağı için w ekleyin / çıkarın. Birkaç karakter biriktirmenizi beklerdim
John La Rooy

@gnibbler, Brian zaten bunu yaptı, onu yenebileceğimden emin değilim, ama denemeliyim.
Benjol
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.