コードゴルフ:レーザー


152

挑戦

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

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

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

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

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

テストケース

入力:
    ##########
    #/ \#
    ##
    # \ バツ#
    #> /#
    ########## 
出力:
    本当

入力:
    ##########
    #vx#
    #/#
    #/#
    #\#
    ##########
出力:    
    偽

入力:
    #############
    ###
    #>##
    ###
    # # バツ #
    ###
    #############
出力:
    偽

入力:
    ##########
    #/ \ / \ / \#
    #\\ // \\\#
    #// \ / \ / \\#
    #\ / \ / \ / x ^#
    ##########
出力:
    本当

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


84
IMMA CHARGIN 'MAH LAZER!
オラフルWaage

37
これは素晴らしいです。
GManNickG


49
@GameFreak:それは本当に古くなっています。
Artelius 2009

24
それは、実際に「^」は頭に奇妙なレーザーが付いているサメですか?
Nathan Feger 09/09/26

回答:


78

Perl、166 160文字

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

このコンテストが終了したとき、ソリューションには166のストロークがありましたが、A。レックスはさらに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一致> ^ <または一致する文字を探しますvに同時に$dレーザービームの初期方向を示す0〜3の値に設定します。

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

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

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

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

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

/[\/\\ ]/ && redo

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

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


さて、323文字になりました。= D
ストレージャー

5
99を1E5に変更して、3文字を犠牲にして非常に堅牢にすることができます。
モブ

2
あなたの最善の解決策は、投稿の上部でより顕著になります。
ストレッジャー2009

13
しかし、ボードを回転させるために正規表現を使用していますか?それは病気でした。それは自動20ストロークボーナスのようなものです。
モブ

1
@mobrule:保存6打:最初の行のリオーダーとしてs!.!$t{$s++}=$&!ge,$s=$r+=99for<>;変化、%d=split//,.." to %のD = .. =〜/./ G , and change にはgrep {..}%のT 'grep..,%t
A.レックス

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副作用が少しあります。ゴルフされたコードでは、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){...}


4
ボードを回転させて...クレイジー。正規表現...クレイジー。O_O
strager

39
あなた...あなたはモンスター!
LiraNuna

4
リラヌナ:私はそれを褒め言葉としてとることにしました。
ホッブズ

21
ゴルフは終わりました。正規表現で2Dボードを回転させるにはどうすればよいですか?
Konrad Rudolph、

13
wtf?Perlプログラマーはウィザードです。
ヨハネスシャウブ-litb 2009

39

C89(209文字)

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

説明

Cを理解していない場合、この怪物をたどることはおそらく難しいでしょう。

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

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

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

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

main(m){

明白mainです。 m動きベクトルを格納する変数です。(これmainは最適化のためのパラメーターです。)

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

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

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

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

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

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

    for(;
        q+=m,

移動ベクトルによってライトを移動します。

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

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

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

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

    );
}

8
うわっ!私のアパートで火災警報が鳴ったとき、私はCソリューションに取り組んでいました。今私は打ち負かされました。素晴らしい解決策です。
rlbond 2009

スワップとスワップ/否定のステップに一時変数を使用する方法では、2、3文字節約できます。
Artelius 2009

@Artelius、ええ、私はそれに気づきました、そして他のいくつかのこと。ありがとう。
ストレッジャー2009

1
TCCは実際には型なしの宣言をg.c:3: declaration expected
嫌い

2
の削除putsは役立ちましたが、170未満にするのに十分ではありません。209はかなり良いので、そのままにしておくと思います。皆さん、助けてくれてありがとう。ほんとうにありがとう。=](これらのPerl魔女を
倒す

36

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

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

Befunge-93!

それはなんと973文字(または、空白文字を無視できるほど慈善的である場合は688です)。空白は、フォーマットにのみ使用され、実際のコードでは何もしません。

警告:私は少し前に自分のBefunge-93インタープリターをPerlで作成しましたが、残念ながら、これをテストするのに本当に時間がかかったのはこれだけです。一般的にその正確さにはある程度の自信がありますが、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」も出力して終了します。
  • 文字がスペースの場合、スタックを空にして続行します。
  • 文字がスラッシュの場合は、ビームの方向をスタックに取得し、それを各方向文字と順番に比較します。1つが見つかると、新しい方向がコードの同じ場所に格納され、ループが繰り返されます。
  • 文字がバックスラッシュの場合、基本的に上記と同じことを行います(バックスラッシュの適切なマッピングを除く)。
  • 文字が「x」の場合、目標を達成しています。「true \ n」を出力して終了します。
  • 文字がこれらのいずれでもない場合は、「エラー\ n」を出力して終了します。

十分な需要がある場合は、コードのどこでこれを実現するかを正確に指摘します。


14
+1-メモ帳で開かれたEXEと誤解される可能性があるためのみ。
Kyle Rosendo、2010

1
ええと...聖なる****。私はBefungeをいじりました、そしてこれは本当に、本当に印象的です。
アルモ2012

難読化された言語でゴルフをコード化...ピーナッツバターやカイエンのように!
wberry

29

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

さて、そこに答えを得るために:

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

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

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

while true do
    p <- next p    

サンプル:

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

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

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

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

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

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

54
私は実際にこれを読むことができます!奇跡的!
ジェフアトウッド

17
Java / C#コードゴルフは、文字ではなく行でカウントされます。それがハンディキャップです。
Nathan Feger 09/09/26

3
@stragerは、コードを保守するために雇われて、元の開発者が去ってから3年間、憂鬱にならない。
Nathan Feger

Visual Studio 2010でF#を使用すると、これは失敗します。Seq.to_listが存在せず(OK、toListに変更)、次に25行目の不完全なパターンマッチング。
ラッセル

2
はい、to_listをtoListに変更します。不完全な一致の警告は問題ありません。それはコードゴルフなので、次のようなコードは実行しませんでした。_-> failwith "impossible"
Brian

29

Golfscript-83文字(私のマッシュアップとStragerのマッシュアップ)

改行はラッピングのためにここにあります

:|'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行目は、レーザーがミラーに当たるたびに方向転換します。


18

Rubyの353文字:

314 277文字になりました!

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

247文字。止まらない。

223の 203 Rubyで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

しかし... または、他の1文字の文字に名前chを変更してC2文字を保存できます!
LiraNuna

わかりました。わかりました...実際に使用するのは一度だけなので、変数全体が不要であることに気付きました。これと他のいくつかの改善により、247文字にまで削減されました。
ジェレミー・ルテン

1
いいえi++(の代わりにi+=1)?
LiraNuna

6
いいえ。++ iを実行することはできますが、以前と同じように本当にポジティブになります。
DigitalRoss

圧縮バージョンが好きです:#; p
SeanJA

17

パイソン

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

(4行目と5行目の最初の文字はスペースではなくタブです)

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

Pythonはオプションのセミコロンすら忘れていました。

使い方

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

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

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

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

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);l文字列内の現在の方向文字のインデックス。zを使用して、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を出力します。


9
p+=1j**z: それは甘いです。
dmckee ---元モデレーターの子猫

16

これはされて いた C#3にブライアンのソリューションの直接ポート、マイナスコンソールの相互作用。これは完全なプログラムではないため、これはチャレンジのエントリーではありません。彼が使用したF#構成の一部がC#でどのように表現できるのかと思っていました。

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

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

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

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

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

8
ああ、神様。強力なlinqとc#がどのようになっているかを示す良い例です。1+はC#の大ファンです。x)
Emiswelt 2009

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行ずつ説明していきましょう。

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

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

次に、現在位置「c」と、上、左、右、下で0、1、2、3の方向「d」をとる「次の」関数「n」を定義します。

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

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

物事を開始するために、初期位置「c」と開始方向(これは0123への方向の初期エンコーディングを行います)で再帰関数「n」を呼び出します。

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


11

18203文字の計量は、次のことができるPythonソリューションです。

  • 「部屋」の外の鏡に対処する
  • 2D制限に基づいて「部屋」がない場合の軌道を計算します(仕様では、「部屋」に何がなければならないかについて多くが説明されていますが、部屋が存在する必要がある場合はそうではありません)。
  • エラーについて報告する

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

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

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

The board is made out of 4 types of tiles:

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

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

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



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

MIRRORS = (MIRROR_NE_SW, MIRROR_NW_SE)

LASERS = (LASER_DOWN, LASER_UP, LASER_RIGHT, LASER_LEFT)

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

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

ROW, COLUMN = range(2)

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

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

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



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

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

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

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

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

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

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

    #Keep on looping until an ultimate conclusion
    while True:

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

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

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

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

        #Perform wrapping
        except IndexError:

            #Obtain the row position
            row_pos = beam_pos[ROW]

            #Handle vertical wrapping
            if axis == ROW:

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

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

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

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

            #Handle horizontal wrapping
            elif axis == COLUMN:

                #Obtain the row
                row = tiles[row_pos]

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

                #Obtain the column position
                col_pos = beam_pos[COLUMN]

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

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

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

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

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

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

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

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

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

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

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

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

        #Obtain the current row
        row = tiles[row_pos]

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

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

            #Obtain the current column
            tile = row[col_pos]

            #Handle finding a laser
            if tile in LASERS:

                #Return the laser's position
                return row_pos, col_pos

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

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

    #Obtain the row position
    row_pos = pos[ROW]

    #Obtain the column position
    col_pos = pos[COLUMN]

    #Obtain the row
    row = tiles[row_pos]

    #Obtain the tile
    tile = row[col_pos]

    #Return the tile
    return tile

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

    number_of_rows = len(tiles)

    row_iter = range(number_of_rows)

    if reverse:
        row_iter = reversed(row_iter)

    for row_pos in row_iter:
        row = tiles[row_pos]

        number_of_cols = len(row)

        col_iter = range(number_of_cols)

        if reverse:
            col_iter = reversed(col_iter)

        for col_pos in col_iter:
            tile = row[col_pos]

            if tile == SOLID_WALL:
                pos = row_pos, col_pos

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

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

                    next_pos[axis] += offset

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

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

                return pos

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

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

    #Safely lookup the tile
    try:

        #Return known tiles
        return TILES[tile]

    #Handle unknown tiles
    except KeyError:

        #Return a default value
        return

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

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

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

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

    #Safely handles outside input
    try:

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

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

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

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

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

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

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

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

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

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

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

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

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

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

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

        lines[error.row_pos] = line

        board = "\n".join(lines)

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

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

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

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

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

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

        lines[error.row_pos] = line

        board = "\n".join(lines)

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

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

    #If a result was returned
    else:

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

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

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

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

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

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

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

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

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

    #Return the container
    return tiles

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

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

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

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

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

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

    tiles = parse_board(board)

    validate_board(tiles)

    return does_laser_hit_target(tiles)

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

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

    found_laser = False
    found_target = False

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

    number_of_rows = len(tiles)

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

        number_of_cols = len(row)

        for col_pos in range(number_of_cols):

            tile = row[col_pos]

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

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

    if not found_laser:
        raise NoLaserError(tiles)

    if not found_target:
        raise NoTargetError(tiles)



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

    pass

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

    symbols = "^v><"

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

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

    symbols = "x"

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

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

    symbols = "^v><"

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

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

    symbols = "x"

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

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

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

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

    __slots__ = ("__row_pos", "__col_pos")

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

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

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

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

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

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

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

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



if __name__ == "__main__":
    main()

カラーエラーレポートを表示するbashスクリプト:

#!/bin/bash

declare -a TESTS

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

開発で使用されるユニットテスト:

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

import unittest

from lasers import *

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

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

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

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

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

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

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

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

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

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

6
レーザー物理学は、ビームそれ自体横切ることができることを要求します。上記のコメントは重要な文化的参照です。
dmckee ---元モデレーターの子猫

5
亀と野ウサギがゴルフをコード化するアプローチ。明らかに文字数が多すぎる(現在の勝者より91倍多い)ものを提供しますが、仕様のすべての文字に注意してください。ゆっくりと着実に、一般的に私はより少ない契約作業を取得します。
Metalshark

ユニットテストの一部が欠けているようです。「self.NOT_DIRECTIO」で切り捨てられます
BioGeek 2010年

@BioGeek-投稿の長さの制限に達する;)。BASHスタイルのテストに加えて、色の強調表示が表示されます。
Metalshark、2011

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は、以前のバージョンの条件式よりも大幅に改善されました。

コードが増加しxy短くできるのではないかと疑っています。以下は、増分を行うコードのセクションです。

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)。どの方向に対応する数値を再配置して、値をインクリメントするためのビット単位の操作ができる配置を探しました。これは、算術バージョンよりも短いと思われがちだからです。


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

イワナの主な無駄は、地図の幅とレーザー光源の位置を見つけることにあるようです。これを短縮する方法はありますか?


これが短いかどうかはわかりませんが、レーザーを見つけて幅を見つける際の私のショットです。 (){"v"、 "<"、 ">"、 "^"}; P p = new P(); r.ForEach(a => {int c = 0; v.ForEach(s => {c ++ ; if(s.IndexOf(a)!=-1){pX = s.IndexOf(a); pY = c;}});}); int l = v [0] .Length; vはテーブルを含むList <string>であり、レーザーの位置を表すポイント+幅を表すint
RCIX

より良い:L = List <string>; L l = new L(4){"v"、 "<"、 ">"、 "^"}; var point = new {x = 0、y = 0}を使用; int c = 0; l.ForEach(a => {m.ForEach(s => {if(s.IndexOf(a)!=-1){point = new {x = s.IndexOf(a)、y = c};}}); c ++;}); int w = m [0] .Length;
RCIX 2009

4
問題は関数ではなく完全なプログラムを要求します。
ストレッジャー2009

いかがですか while(1)
SSpoke 2013

9

C + ASCII、197文字:

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

このCソリューションはASCII文字セットを想定しているため、XORミラートリックを使用できます。また、それは信じられないほど壊れやすいです-たとえば、すべての入力行は同じ長さでなければなりません。

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


= O!+1!私を殴ることについての謝罪。=]
ストレッジャー2009

2
ここで最も良い解決策は、「すべての線が同じ長さである」という仮定を立てることです。ゴルフと戦争のすべてが公正です。
ホッブ09/09/30

行の長さが同じではない場合は、テストケースを追加します。しかし、私はそれが意図的であると明確に述べた:)
リラナ


9

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

どのように多くの文字は変更にかかりTruetrueしてFalseまでfalse?;-)
mob

「print D<5」を「print D <5」に変更して1文字削除できませんか?または私が見逃しているものはありますか?
ポンカドゥードル2010

@wallacoloo、確かにできます。小文字のtrue / falseの場合にのみ必要です
John La Rooy、2010

7

JavaScript-265文字

更新IV-オッズはこれが更新の最後のラウンドであり、do-whileループに切り替えて移動方程式を書き直すことにより、さらに2、3キャラクターを節約することができました。

アップデート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>

どのように入力しますか?これをテストして確認したいと思います。また、a.indexOfへの参照を保存すると、多くの文字を保存できます
LiraNuna

交換index != -1してindex > 0ください!(うまくいけば、左上隅にレーザーを配置し0ないので返されません。=])varステートメントをチェーンするか、それらを完全に取り除くことができます(グローバル名前空間に変数を置く)。Math.abs(m)==1と交換できると思いますm==-1|m==1movement = ...; location += movementに最適化できますlocation += movement =か?
ストレッジャー、2009

@ strager-あなたのコメントを見たところ、私がコードを更新しているときにあなたがそれを300文字まで投稿したようです。Math.abs()を削除することで何ができるかを見ていきます。
rjzii

function(a){return g.indexOf(a)}function(a)g.indexOf(a)最近のJavaScriptバージョンで置き換えることができます。
user1686

6

鏡の家

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

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

それはもう少し多くを行います。色とさまざまなタイプのミラーとデバイスを扱いますが、バージョン0.00001はこの課題が要求することを正確に行いました。私はそのバージョンを失いました、そしてそれはとにかく文字カウントのために最適化されませんでした。


scalaをインストールせずに、Windowsで動作するコンパイル済みバージョンをアップロードすることは可能でしょうか?
ミラノ

Scalaライブラリを含むバージョンがあります。ダウンロードのリストを見てください。とにかく、もしあなたが今までにScalaをインストールしたなら、私はあなたにそれをやらせてくれてうれしいです:)
HRJ

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

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

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


=0デフォルトでは0に初期化されるため、グローバルは必要ありません。文字定数を同等の10進数に置き換えます。使用>0の代わりに、!=EOFEOF(およびに対してチェックします\0)。おそらく#definecase私がで行ったようなコードの一部を取り除くことができifます。余分の必要ないん\nputsなどputs、とにかく改行を印刷する必要があります。 for(;;)より短いですwhile(1)。お役に立てれば。=]
ストレージャー、2009

@strager:ありがとう。私はそのように考えていないので、私はいつもこれらに繰り返し来ます...
dmckee ---元モデレーター子猫

2
"There is no input validation"-あってはいけません。ゴルファーに簡単にするために、特に指定がない限り、入力は常に「クリーン」であると想定されています。
LiraNuna

@dmckee、心配しないでください、私たちコードゴルフのプロも同様に繰り返し作業します。ただし、通常は最初からいくつかのトリックを使用しますが(先ほど述べたものの半分など)、これには経験が伴います。=]
ストレージャー、2009

私が間違って数えているのでない限り、プログラムは380文字ではなく390文字
です。– strager

6

ルビー-146文字

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

5

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 =

4

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

それでも、賢いものではなく、一般的なステートマシンを使用します。

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

読みやすいバージョン:

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

3

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

  Board.new.validate(input)を配置します

32文字\ o / ... wohoooo


6
それはダブルボギーです!
Jeff Atwood

3
それに打ち勝つ:p Board.new.validate input 26 characters \ o /
Alessandra Pereyra

3

C ++:388文字

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

318ヘッダーなし)


使い方:

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

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

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


あなたは私に自分自身のC ++ソリューションを実行させています。=]
ストレージャー、

2
@strager、これは退屈になっています。コンパイル時に「true」または「false」を表示するソリューションを実行してみましょうxD
Johannes Schaub-litb

私はこれをこれで維持すると思うので説明を追加しました:)
Johannes Schaub-litb 09/09/28

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

2

C#

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

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

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

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

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

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

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

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

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

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

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

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

    private bool FindTarget()
    {
        DrawArena();

        string chr = Arena[Position];

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

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

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

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

2
プログラムは入力を受け取る必要があります。最も一般的にはstdinから。
LiraNuna

0

Perl 219
私のperlバージョンは392 342文字です(レーザーに当たるビームのケースを処理する必要がありました):
更新、ホッブズに思い出してくれてありがとうtr//、それは今250文字です:
更新、削除するmにはm//、2つの変更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ステートメントを読み取ることができることを理解している場合は、自明です。


ヒント:ミラーコードを短くすることができます。$_=$s;tr/^v<>/<>^v/$_=$s;tr/v^<>/<>^v/それぞれ。また、あなたは必要ありませんmでしm//
ホッブズ

申し訳ありません、2つ目を作成してください$_=$s;tr/v^></<>^v/;
ホッブズ

あなたはまだ2つのキャラクターを1つのポップに救うif m/.../ことができるいくつかを持っていif/.../ます。
ホッブ09/09/28

y///代わりにtr///を使用して、2つの文字を保存できます。
Platinum Azure

0

F#-454(またはその周辺)

ゲームに少し遅れますが、2Dの試みを投稿することに抵抗することはできません。

更新が少し変更されました。トランスミッターがヒットした場合、正しく停止するようになりました。IndexOfAnyに対するBrianの考えをつまみました(その行が非常に冗長であることを恥じます)。ReadToEndをコンソールから返す方法を実際にうまく管理できていないので、その点については信頼しています...

私はこの回答に満足しています。短いのですが、まだかなり読みやすいからです。

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

彼らは装飾です。私の他の課題を確認してください。それは単なるフォーマットの問題です。
LiraNuna 2010年

@LiraNuna、わかりました、結局のところ、この反復はとにかくそれらを食べます:)
Benjol

1次元の実装と比較するとよいでしょう。左右の場合は1を加算/減算し、上下の場合はwを加算/減算するだけです。かなりの数の文字を節約できると思います
John La Rooy、

@gnibbler、ブライアンはすでにそれをしました、私が彼を倒すことができるかどうかはわかりませんが、私はそれを試してみるかもしれません。
ベンジョル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.