152

チャレンジ

ボードの 2D 表現を入力し、入力に応じて「true」または「false」を出力する文字数による最短コード。

ボードは 4 種類のタイルで構成されています。

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

レーザーターゲットは 1 つだけです。壁は、レーザーとターゲットが内部に配置される、任意のサイズのしっかりした長方形を形成する必要があります。「部屋」内の壁が可能です。

レーザー光線は発射され、その原点から指している方向に移動します。レーザー光線が壁に当たると止まります。レーザー光線がミラーに当たると、ミラーが指す方向に 90 度跳ね返ります。ミラーは両面です。つまり、両面が「反射」し、光線を 2 つの方法で跳ね返すことができます。レーザー光線がレーザー ( ^v><) 自体に当たると、それは壁として扱われます (レーザー ビームはビーマーを破壊するため、ターゲットに当たることはありません)。

テストケース

入力:
    ##########
    # / \ #
    # #
    # \ バツ#
    # > / #
    ##########
出力:
    真実

入力:
    ##########
    # vx #
    # / #
    # /#
    # \ #
    ##########
出力:    
    間違い

入力:
    ############
    # # #
    # > # #
    # # #
    # # バツ #
    # # #
    ############
出力:
    間違い

入力:
    ##########
    #/\/\/\ #
    #\\//\\\ #
    #//\/\/\\#
    #\/\/\/x^#
    ##########
出力:
    真実

コード カウントには、入力/出力 (つまり、完全なプログラム) が含まれます。

4

28 に答える 28

78

Perl、166 160 文字

Perl、251 248 246 222 214 208 203 201 193 190 180 176 173 170 166 --> 160 文字。

このコンテストが終了したとき、ソリューションは 166 ストロークでしたが、A. Rex はさらに 6 文字を削る方法をいくつか見つけました。

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

最初の行は、行i、列jに文字を保持する%tボードのテーブルである に入力をロードします。それで、$t{99*i+j}

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

の要素からまたはに%t一致する文字を検索し、同時にレーザー ビームの初期方向を示す 0 ~ 3 の値を設定します。> ^ <v$d

$dメイン ループの各反復の開始時に、ビームが現在ミラー上にあるかどうかを更新します。3\で XOR するとミラーの正しい動作が得られ、1 で XOR するとミラーで正しい動作が得られます/

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

$r次に、現在の方向に従って現在位置が更新されます。

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

$_一致演算子を便利に使用するために、現在の位置にある文字を に割り当てます。

/[\/\\ ]/ && redo

空白またはミラー キャラクターにいる場合は続行します。trueそれ以外の場合は、ターゲット ( $_ =~ /x/)にいる場合は終了し、そうでない場合は終了しfalseます。

制限: 99 列を超える問題では機能しない場合があります。この制限は、さらに 3 文字を犠牲にして削除できます。

于 2009-09-26T02:19:42.397 に答える
75

Perl、177 文字

最初の改行は削除できます。他の 2 つは必須です。

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

説明:

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

右に移動するビームが{空のスペース、上向きのミラー、下向きのミラー}にぶつかると、{右に移動するビーム、上に移動するビーム、下に移動するビーム}になります。$/途中で初期化します。幸いなことに、「6」は有効な入力文字ではありません。

$_ = <>;

ボードを に読み込み$_ます。

$s="#";

$sビームが現在上にあるもののシンボルです。レーザー発光部は壁として扱うので、最初はこれを壁に設定します。

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

レーザー ビームが右以外の方向を向いている場合は、そのシンボルを回転させてから、ボード全体を所定の位置で回転させます (ミラーのシンボルも回転させます)。これは 90 度の左回転であり、行と列を入れ替えながら行を逆にすることで効果的に達成されますが、これはs///e副作用を伴うやや悪魔的なものです。golfed コードでは、tr はy'''バックスラッシュを 1 つスキップできる形式で記述されています。

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

ターゲットまたは壁に当たった場合は、正しいメッセージで終了します。

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

レーザーの前に空きスペースがある場合は、前進します。レーザーの前にミラーがある場合は、前方に移動してビームを回転させます。どちらの場合でも、「保存されたシンボル」を古いビーム位置に戻し、上書きしたばかりのものを保存されたシンボルに入れます。

redo;

終了するまで繰り返します。{...;redo}は 2 文字未満for(;;){...}および 3文字未満ですwhile(1){...}

于 2009-09-26T04:25:12.830 に答える
39

C89(209文字)

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

説明

Cを理解していないと、この怪物を追跡するのはおそらく難しいでしょう。ただの警告です。

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

この小さなマクロは、現在の文字()が文字形式( )*pにあるものと等しいかどうかをチェックします。それらが等しい場合は、移動ベクトルを()に設定し、このキャラクターを壁()としてマークし、開始点を現在の位置()に設定します。このマクロには「else」部分が含まれます。a*#abm=b*p=1q=p

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

いくつかの変数を宣言します。*qはライトの現在の場所です。*Gは1D配列としてのゲームボードです。*pは、入力時の現在の読み取り位置Gです。*wはボードの幅です。

main(m){

明らかmainです。 m移動ベクトルを格納する変数です。main(これは最適化としてのパラメーターです。)

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

Gを使用して入力し、すべての文字をループしpます。最適化としてスキップします(の3番目の部分でG[0]文字の書き込みを無駄にする必要はありません)。pfor

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

可能であれば、前述のマクロを使用してレーザーを定義します。 -11はそれぞれ左と右、そして上下に対応-wwます。

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

現在の文字が行末マーカー(ASCII 10)の場合、幅がまだ設定されていなければ設定します。スキップすると、の代わりにG[0]書き込むことができます。また、これは'sからのチェーンを終了します。w=p-Gw=p-G+1?:M

    for(;
        q+=m,

移動ベクトルでライトを移動します。

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

移動ベクトルを反映します。

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

これが壁またはの場合はx、適切なメッセージで終了します(m=0ループを終了します)。それ以外の場合は、何もしません(noop; m=m

    );
}
于 2009-09-26T01:42:30.183 に答える
36

人々はこれを長い間待っていたに違いありません。(どういう意味ですか、挑戦は終わり、もう誰も気にしませんか?)

見よ...私はここで解決策を提示します

Befunge-93!

なんと973文字(書式設定にのみ使用され、実際のコードでは何もしない空白を無視するほど慈悲深い場合は688文字) の重さです。

警告: 私は少し前に Perl で独自の Befunge-93 インタープリターを作成しましたが、残念ながらこれだけでテストする時間がありました。私は一般的にその正確性にかなりの自信を持っていますが、EOF に関して奇妙な制限があるかもしれません: Perl の<>演算子はファイルの最後で undef を返すため、これは数値コンテキストでは 0 として処理されます。EOF が異なる値 (-1 など) を持つ C ベースの実装では、このコードは機能しない可能性があります。

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

説明

Befunge の構文と操作に慣れていない場合は、こちらを確認してください。

Befunge はスタックベースの言語ですが、Befunge コードに文字を書き込めるコマンドがあります。私はそれを2つの場所で利用しています。まず、入力全体を Befunge ボードにコピーしますが、実際に記述されたコードの数行下に配置します。(もちろん、これはコードの実行時に実際に表示されることはありません。)

他の場所は左上付近です。

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

この場合、上で強調表示した領域は、いくつかの座標を保存する場所です。中央の行の最初の列には、現在の「カーソル位置」の x 座標を格納する場所があります。2 番目の列は、y 座標を格納する場所です。次の 2 つの列は、レーザー光源が見つかった場合の x 座標と y 座標を格納するためのものです。最後の列 (「a」文字を含む) は最終的に現在のビーム方向を含むように上書きされますが、これはビームの経路が追跡されるにつれて明らかに変化します。

プログラムは、最初のカーソル位置として (0,27) を配置することから始まります。次に、入力が一度に 1 文字ずつ読み取られ、カーソル位置に配置されます。改行は、実際の改行と同じように、y 座標を増加させ、x 座標を 0 に戻すだけです。最終的に undef はインタプリタによって読み取られ、その 0 文字値は入力の終了を通知するために使用され、レーザー反復ステップに進みます。レーザー文字 [<>^v] が読み取られると、それもメモリ リポジトリに ('a' 文字の上に) コピーされ、その座標がすぐ左の列にコピーされます。

これらすべての最終的な結果として、基本的にファイル全体が Befunge コードにコピーされ、実際のコードの少し下に移動されます。

その後、ビーム位置がカーソル位置にコピーされ、次の反復が実行されます。

  • 現在のビーム方向を確認し、カーソル座標を適切に増減します。(これを最初に行うのは、最初の移動でレーザー ビームのコーナー ケースに対処する必要がないようにするためです。)
  • その場所の文字を読み取ります。
  • 文字が「#」の場合は、スタックに改行と「false」を入れて出力し、終了します。
  • すべてのビーム文字 [<>^v] と比較してください。一致する場合は、「false\n」も出力して終了します。
  • 文字がスペースの場合、スタックを空にして続行します。
  • 文字がスラッシュの場合、ビーム方向をスタックに取得し、それを各方向文字と順番に比較します。方向が見つかると、新しい方向がコード内の同じ場所に格納され、ループが繰り返されます。
  • 文字がバックスラッシュの場合、基本的に上記と同じことを行います (バックスラッシュの適切なマッピングを除く)。
  • 文字が「x」の場合、ターゲットにヒットしました。"true\n" を出力して終了します。
  • 文字がこれらのどれでもない場合、"error\n" を出力して終了します。

十分な需要がある場合は、コードのどこでこれがすべて達成されているかを正確に指摘しようとします。

于 2010-07-22T22:07:12.787 に答える
29

F#、36 行、非常に読みやすい

わかりました、そこに答えを得るために:

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

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

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

while true do
    p <- next p    

サンプル:

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

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

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

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

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

##########
#  /    \#
# / \    #
#/    \ x#
#\^/\ /  #
##########
false
于 2009-09-26T01:26:42.043 に答える
29

Golfscript - 83 文字 (私のものと見知らぬ人のマッシュアップ)

改行は折り返しのためにここにあります

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

Golfscript - 107 文字

改行はわかりやすくするためにあります

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

使い方。

最初の行は、最初の位置と方向を示します。
2 番目の行は、レーザーがミラーに当たるたびに回転します。

于 2009-11-09T01:19:59.253 に答える
18

Ruby で 353 文字:

314 277文字になりました!

OK、Ruby で 256 文字、これで完了です。停止するのに最適なラウンド数。:)

247文字。止まらない。

Ruby では223 203 201 文字

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

空白あり:

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

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

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

少しリファクタリング:

board = readlines

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

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

  ch = board[y][x].chr
  case ch
  when "/"
    direction = [1, 0, 3, 2][direction]
  when "\\"
    direction = 3 - direction
  when "x"
    puts "true"
    exit
  when "#"
    puts "false"
    exit
  end
end
于 2009-09-26T02:37:13.473 に答える
17

パイソン

改行を含む294 277 253 240 232 文字:

(4 行目と 5 行目の最初の文字はタブであり、スペースではありません)

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

Python にはオプションのセミコロンさえあることを忘れていました。

使い方

このコードの背後にある重要なアイデアは、複素数を使用して位置と方向を表すことです。行は虚数軸で、下に向かって増加します。列は実際の軸で、右に向かって増加します。

l='>v<^';レーザーシンボルのリスト。順序は、レーザー方向文字のインデックスが sqrt(-1) の累乗に対応するように選択されます

x={'/':'^<v>','\\':'v>^<',' ':l};ビームが異なるタイルを離れたときに方向がどのように変化するかを決定する変換テーブル。タイルが鍵であり、新しい方向性が価値です。

b=[1];ボードを保持します。while ループが少なくとも 1 回実行されるように、最初の要素は 1 (true と評価される) です。

r=p=0 rは入力の現在の行番号、pはレーザー ビームの現在の位置です。

while b[-1]:raw_input が空の文字列を返したときにボード データのロードを停止する

b+=[raw_input()];r+=1入力の次の行をボードに追加し、行カウンターをインクリメントします

for g in l:各レーザーの方向を順番に推測する

c=b[r].find(g)列をレーザーの位置に設定するか、列にない場合 (または別の方向を指している場合) は -1 に設定します。

if-1<c:p=c+1j*r;d=gレーザーが見つかった場合は、現在の位置pと方向を設定しdます。dの文字の 1 つです。l

ボードを にロードするbと、現在の位置pと方向dがレーザー光源の位置と方向に設定されます。

while' '<d:スペースはどの方向記号よりも小さい ASCII 値を持つため、停止フラグとして使用します。

z=l.find(d);文字列内の現在の方向文字のインデックスlz後で、テーブルを使用して新しいビーム方向を決定しx、位置をインクリメントするために使用されます。

p+=1j**z;i の累乗を使用して位置をインクリメントします。たとえば、l.find('<')==2-> i^2 = -1 の場合、1 列左に移動します。

c=b[int(p.imag)][int(p.real)];現在位置の文字を読み取る

d=x.get(c,' '*4)[z]変換テーブルでビームの新しい方向を調べます。現在の文字がテーブルに存在しない場合は、dスペースに設定します。

print'#'<cターゲット以外で停止した場合は false を出力します。

于 2009-09-26T02:59:48.413 に答える
16

F#、255文字(そしてそれでもかなり読みやすい!):

さて、一晩休んだ後、私はこれをたくさん改善しました:

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

それを一行ずつ話してみましょう。

まず、すべての入力を大きな1次元配列に丸呑みします(2D配列はコードゴルフに悪い場合があります。1D配列を使用し、インデックスに1行の幅を加算/減算して、行を上下に移動します)。

次に、配列にインデックスを付けて、入力行の幅である「w」と開始位置である「c」を計算します。

次に、現在の位置「c」と方向「d」(上、左、右、下)をとる「次の」関数「n」を定義しましょう。

index-epsilon'e'とwhat-new-direction-if-we-hit-a-slash's'は、テーブルによって計算されます。たとえば、現在の方向'd'が0(上)の場合、テーブルの最初の要素は "-w、2"と表示されます。これは、インデックスをwだけデクリメントすることを意味し、スラッシュを押すと、新しい方向は2になります。 (右)。

ここで、次の関数'n'に戻り、(1)次のインデックス( "c + e"-現在とイプシロン)、および(2)新しい方向を計算します。これは、配列の内容を確認することで計算されます。その次のセル。先読み文字がスラッシュの場合、新しい方向は「s」です。バックスラッシュの場合、新しい方向は3秒です(エンコード0123を選択すると、これが機能します)。スペースの場合は、同じ方向に進み続けます'd'。そして、それが他の文字「c」の場合、ゲームは終了し、文字が「x」の場合は「true」を出力し、それ以外の場合はfalseを出力します。

開始するために、初期位置「c」と開始方向(0123への方向の初期エンコードを行う)を使用して再帰関数「n」を呼び出します。

おそらくまだ数文字削ることができると思いますが、このようにかなり満足しています(255はいい数字です)。

于 2009-09-26T01:55:03.880 に答える
16

これ 、Brian のソリューションを C#3 に直接移植したもので、コンソールとのやり取りはありませんこれは完全なプログラムではないため、この課題へのエントリではありません。私は、彼が使用した F# 構造のいくつかを C# でどのように表現できるか疑問に思っていました。

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

編集:いくつかの実験の後、次のやや冗長な検索コード:

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

よりコンパクトな LINQ to Objects コードに置き換えられました。

var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
         .First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));
于 2009-09-26T04:19:17.220 に答える
11

18203 文字の重み付けは、次のことができる Python ソリューションです。

  • 「部屋」の外の鏡に対処する
  • 2D の制限に基づいて「部屋」がない場合の軌跡を計算します (仕様では、「部屋」にある必要があるものについて多くのことが述べられていますが、部屋が存在する必要がある場合はそうではありません)
  • エラーを報告する

それはまだいくらか整理する必要があり、ビームがそれ自体を横切ることができないと 2D 物理学が指示するかどうかはわかりません...

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

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

The board is made out of 4 types of tiles:

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

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

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



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

MIRRORS = (MIRROR_NE_SW, MIRROR_NW_SE)

LASERS = (LASER_DOWN, LASER_UP, LASER_RIGHT, LASER_LEFT)

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

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

ROW, COLUMN = range(2)

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

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

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



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

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

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

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

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

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

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

    #Keep on looping until an ultimate conclusion
    while True:

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

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

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

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

        #Perform wrapping
        except IndexError:

            #Obtain the row position
            row_pos = beam_pos[ROW]

            #Handle vertical wrapping
            if axis == ROW:

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

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

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

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

            #Handle horizontal wrapping
            elif axis == COLUMN:

                #Obtain the row
                row = tiles[row_pos]

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

                #Obtain the column position
                col_pos = beam_pos[COLUMN]

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

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

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

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

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

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

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

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

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

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

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

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

        #Obtain the current row
        row = tiles[row_pos]

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

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

            #Obtain the current column
            tile = row[col_pos]

            #Handle finding a laser
            if tile in LASERS:

                #Return the laser's position
                return row_pos, col_pos

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

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

    #Obtain the row position
    row_pos = pos[ROW]

    #Obtain the column position
    col_pos = pos[COLUMN]

    #Obtain the row
    row = tiles[row_pos]

    #Obtain the tile
    tile = row[col_pos]

    #Return the tile
    return tile

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

    number_of_rows = len(tiles)

    row_iter = range(number_of_rows)

    if reverse:
        row_iter = reversed(row_iter)

    for row_pos in row_iter:
        row = tiles[row_pos]

        number_of_cols = len(row)

        col_iter = range(number_of_cols)

        if reverse:
            col_iter = reversed(col_iter)

        for col_pos in col_iter:
            tile = row[col_pos]

            if tile == SOLID_WALL:
                pos = row_pos, col_pos

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

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

                    next_pos[axis] += offset

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

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

                return pos

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

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

    #Safely lookup the tile
    try:

        #Return known tiles
        return TILES[tile]

    #Handle unknown tiles
    except KeyError:

        #Return a default value
        return

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

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

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

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

    #Safely handles outside input
    try:

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

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

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

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

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

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

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

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

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

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

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

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

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

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

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

        lines[error.row_pos] = line

        board = "\n".join(lines)

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

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

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

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

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

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

        lines[error.row_pos] = line

        board = "\n".join(lines)

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

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

    #If a result was returned
    else:

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

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

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

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

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

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

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

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

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

    #Return the container
    return tiles

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

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

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

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

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

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

    tiles = parse_board(board)

    validate_board(tiles)

    return does_laser_hit_target(tiles)

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

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

    found_laser = False
    found_target = False

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

    number_of_rows = len(tiles)

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

        number_of_cols = len(row)

        for col_pos in range(number_of_cols):

            tile = row[col_pos]

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

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

    if not found_laser:
        raise NoLaserError(tiles)

    if not found_target:
        raise NoTargetError(tiles)



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

    pass

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

    symbols = "^v><"

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

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

    symbols = "x"

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

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

    symbols = "^v><"

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

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

    symbols = "x"

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

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

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

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

    __slots__ = ("__row_pos", "__col_pos")

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

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

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

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

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

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

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

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



if __name__ == "__main__":
    main()

色のエラー報告を表示する bash スクリプト:

#!/bin/bash

declare -a TESTS

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

開発で使用される単体テスト:

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

import unittest

from lasers import *

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

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

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

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

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

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

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

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

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

class TestReflection(unittest.TestCase):
    def setUp(self):
        self.DIRECTION = LEFT
        self.NOT_DIRECTIO
于 2009-09-27T20:10:16.400 に答える
11

ルビー、176文字

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

私は単純なステート マシン (ほとんどのポスターのように) を使用しましたが、派手なものは何もありません。考えられるあらゆるトリックを使って、それを削り続けました。方向を変更するために使用されるビットごとの XOR (変数 に整数として格納されるc) は、以前のバージョンで使用していた条件よりも大幅に改善されました。

コードがインクリメントされて短くなる可能性があるのではないかと疑っていxますy。インクリメントを行うコードのセクションは次のとおりです。

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

編集:上記を少し短くすることができました:

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

レーザーの現在の方向はc次のように保存されます。

0 => 上
1 => ダウン
2 => 左
3 => 右

コードは、この事実に基づいてインクリメントxy、正しい量 (0、1、または -1) でインクリメントします。どの数値が各方向にマップされるかを再配置して、値をインクリメントするためにビット単位の操作を実行できる配置を探しました。

于 2009-09-28T05:58:22.660 に答える
9

Golfscript(83文字)

こんにちは、グニブラー!

:\'><v^'.{\?}%{)}?:P@=?{:O[1-1\10?).~)]=P+
:P\=' \/x'?[O.2^.1^'true''false']=.4/!}do
于 2009-11-09T02:15:22.237 に答える
9

C + ASCII、197文字:

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

このCソリューションはASCII文字セットを想定しているため、XORミラートリックを使用できます。また、非常に壊れやすいです。たとえば、すべての入力行は同じ長さである必要があります。

それは200文字のマークの下で壊れます-しかしそれをやめました、それでもそれらのPerlソリューションを打ち負かしていません!

于 2009-09-29T09:48:38.210 に答える
9

パイソン - 152

「L」というファイルから入力を読み取ります

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

stdin から読み取るには、最初の行をこれに置き換えます

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

小文字の true/false が必要な場合は、最後の行を次のように変更します

print`D<5`.lower()
于 2009-11-09T02:30:29.360 に答える
9

C# 3.0

259文字

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

もう少し読みやすい:

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

文字の主な浪費は、マップの幅とレーザー光源の位置を見つけることにあるようです。これを短縮する方法はありますか?

于 2009-09-26T13:30:29.287 に答える
7

JavaScript - 265 文字

更新 IV - これが更新の最後のラウンドになる可能性が高く、do-while ループに切り替えて移動方程式を書き直すことで、さらに数人の文字を節約することができました。

更新 III - Math.abs() を削除し、変数をグローバル名前空間に配置することに関する strager の提案のおかげで、変数割り当ての再配置と相まって、コードが 282 文字になりました。

更新 II - != -1 の使用を削除するためのコードの更新と、より長い操作のための変数の使用の改善。

更新- indexOf 関数への参照を作成し (LiraNuna に感謝します!)、必要のない括弧を削除することで、いくつかの変更を行いました。

コードゴルフをするのはこれが初めてなので、これがどれほど改善されるかはわかりませんが、フィードバックをいただければ幸いです。

完全に最小化されたバージョン:

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

コメント付きの元のバージョン:

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

テストする Web ページ:

<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>
于 2009-09-28T19:50:16.640 に答える
6

c(K&R)stragerからの追加の提案の後、339の必要な文字。

私の物理学者は、伝播と反射の操作は時間反転不変であると指摘しました。そのため、このバージョンでは、ターゲットから光線を放ち、レーザーエミッターに到達するかどうかを確認します。

残りの実装は非常に単純で、以前の前向きな取り組みから多かれ少なかれ正確に取り入れられています。

圧縮:

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

非圧縮(ish):

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

入力検証はなく、不正な入力はそれを無限ループに送る可能性があります。99x99以下の入力で適切に動作します。ヘッダーを含めずに標準ライブラリをリンクするコンパイラが必要です。そして、私は終わったと思います、ストラガーは彼の助けを借りても、かなりのストレッチで私を打ち負かしました。

私はむしろ誰かがタスクを達成するためのより微妙な方法を示すことを望んでいます。これには何の問題もありませんが、それは深い魔法ではありません。

于 2009-09-26T01:53:48.203 に答える
6

ルビー - 146 文字

A=$<.read
W=A.index('
')+1
until
q=A.index(">^<v"[d=d ?d+1:0])
end
while d<4
d=[d,d^3,d^1,4,5][(' \/x'.index(A[q+=[1,-W,-1,W][d]])or 4)]
end
p 5>d
于 2009-11-09T05:02:56.230 に答える
6

鏡の家

チャレンジへの実際のエントリーではありませんが、私はこのコンセプトに基づいてゲームを書きました (少し前のことです)。

これは Scala で書かれており、オープンソースであり、ここから入手できます。

もう少し多くのことを行います。バージョン 0.00001 は、色とさまざまな種類のミラーとデバイスを扱いますが、バージョン 0.00001 はまさにこのチャレンジが求めていることを実行しました。私はそのバージョンを失いましたが、とにかく文字数が最適化されたことはありません.

于 2009-09-26T07:28:54.300 に答える
5

PostScript、359 バイト

初めての試みで、改善の余地がたくさんあります...

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

Haskell、395 391 383 361 339 文字 (最適化)

巧妙なものではなく、一般的なステートマシンを引き続き使用します。

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

読み取り可能なバージョン:

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

私はコードの再利用を信じています。あなたのコードの1つをAPIとして使用します:)。

  puts Board.new.validate(入力)

32 文字 \o/... wohoooo

于 2009-09-26T09:10:40.347 に答える
3

C++: 388文字

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

(ヘッダーなしの318 )


使い方:

まず、すべての行が読み込まれ、次にレーザーが検出されます。0以下は、レーザー矢印がまだ見つからない限り評価され、同時にx水平位置に割り当てられます。

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

次に、見つけた方向を見て、それを に保存しiます。の偶数の値iは上/左 (「減少」) で、奇数の値は下/右 (「増加」) です。その考え方に従って、d("方向") とr("方向") が設定されます。ポインター配列に向きを付けてインデックスzを付け、取得した整数に方向を追加します。スラッシュを打った場合のみ方向が変わり、バックスラッシュを打った場合は同じままです。もちろん、鏡にぶつかると必ず向きが変わります ( r = !r)。

于 2009-09-27T23:10:38.907 に答える
2

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
于 2009-09-27T00:29:31.623 に答える
2

C#

1020文字。
1088 文字 (コンソールからの追加入力)。
925 文字 (リファクタリングされた変数)。
875 文字 (冗長なディクショナリ初期化子を削除。バイナリ & 演算子に変更)

投稿する前に他の人のものを見ないでください。私はそれが少しLINQ化される可能性があると確信しています。そして、読み取り可能なバージョンの FindLaser メソッド全体は、私にはひどく怪しいようです。しかし、それは機能し、遅れています:)

読み取り可能なクラスには、レーザーが移動するときに現在の Arena を出力する追加のメソッドが含まれていることに注意してください。

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

読みやすいバージョン (ゴルフの最終バージョンではありませんが、前提は同じです):

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

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

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

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

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

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

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

    private bool FindTarget()
    {
        DrawArena();

        string chr = Arena[Position];

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

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

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

        switch( Arena[Position] )
        {
            case "^":
                OffSet( North );
                break;
            case "v":
                OffSet( South );
                break;
            case "<":
                OffSet( West );
                break;
            case ">":
                OffSet( East );
                break;
        }
    }
}
于 2009-09-26T07:48:27.380 に答える
0

Perl 219
私の perl バージョンは392 342 文字の長さです (ビームがレーザーに当たるケースを処理する必要がありました):
更新、 を思い出させてくれた Hobbs に感謝しますtr//。現在は 250 文字です:
更新m、 inを削除し、持ち込まれた 2 つのループm//を変更しますwhileいくつかの節約; 必要なスペースは 1 つだけです。
(L:it;goto Lは と同じ長さdo{it;redo}):

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

私はいくつか剃りましたが、遅いとはいえ、これらのいくつかとほとんど競合しません.
次のように少し良く見えます。

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

@bええと...正直なところ、これは各行の文字の配列配列であり、単純な正規表現とtrステートメントを読み取ることができることを理解していれば、自明のはずです。

于 2009-09-26T02:54:53.650 に答える
0

F# - 454 (またはそのあたり)

ゲームに少し遅れましたが、2 回目の試みを投稿せずにはいられません。

更新はわずかに変更されました。送信機がヒットした場合、正しく停止するようになりました。IndexOfAny に対する Brian のアイデアをつまんだ (その行が非常に冗長であることを残念に思います)。コンソールから ReadToEnd を返す方法を実際に理解できていないので、そのビットを信頼しています...

私はこの回答に満足しています.非常に短いですが、それでもかなり読みやすいです.

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