web-dev-qa-db-ja.com

コードゴルフ:レーザー

チャレンジ

ボードの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つのレーザー1つのターゲットのみがあります。壁は、レーザーとターゲットが内部に配置される任意のサイズの固体の長方形を形成する必要があります。 「部屋」内の壁は可能です。

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

テストケース

入力:
 ########## 
#/ \#
##
#\ x#
#> /#
 ########## 
出力:
 true 
 
入力:
 ########## 
#vx#
#/#
#/#
#\#
 ### ####### 
出力:
 false 
 
入力:
 ############# 
###
#>##
###
##x#
###
 ### ########## 
出力:
 false 
 
入力:
 ########## 
#/ \/\/\#
#\\ // \\\#
#// \/\/\\#
#\/\/\/x ^#
 ########## 
 Output:
 true 

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

152
LiraNuna

Perl、 166 160文字

Perl、 251248246222214208203201193190180176173170 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,$/

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

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

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

メインループの各反復の開始時に、ビームが現在ミラー上にある場合、$dを更新します。 3によるXOR'ingは\ミラーの正しい動作を提供し、1によるXOR'ingは/ミラーの正しい動作を提供します。

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

次に、現在の位置に応じて現在の位置$rが更新されます。

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

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

/[\/\\ ]/ && redo

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

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

78
mob

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}_は、for(;;){...}未満の2文字とwhile(1){...}未満の3文字です。

75
hobbs

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

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

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

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

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

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

        !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

    );
}
39
strager

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

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

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の構文と操作に慣れていない場合は、 here を確認してください。

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」を出力して終了します。

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

36
Platinum Azure

Golfscript-83文字(私のマッシュアップとストレガーの)

改行はラッピング用です

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

ゴルフスクリプト-107文字

改行はclarityのためにあります

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

使い方。

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

29
John La Rooy

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

Rubyで353文字:

314277文字になりました!

OK、256文字でRubyで、これで完了です。素敵なラウンド番号で止まります。:)

247文字。やめられない.

223203 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
18
Jeremy Ruten

Python

294277253240 改行を含む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を設定します。 dlの文字の1つです

ボードをbにロードした後、現在の位置pと方向dはレーザー光源の位置に設定されています。

_while' '<d:_スペースには、方向記号よりも低いASCII値があるため、停止フラグとして使用します。

l文字列内の現在の方向文字のz=l.find(d);インデックス。 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を出力します。

17
Theran

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

OK、一晩休んだ後、これを大幅に改善しました:

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次元配列に丸Sみします(2D配列はコードゴルフには不適切です。1D配列を使用し、1行の幅をインデックスに加算/減算して行を上下に移動します)。

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

ここで、「次」関数「n」を定義しましょう。これは、現在の位置「c」と上、左、右、下の方向「0」、「1」、「2」、「3」を取ります。

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

次に、(1)次のインデックス(「c + e」-現在のプラスイプシロン)、および(2)新しい方向を次の関数 'n'に再帰します。その次のセル。先読み文字がスラッシュの場合、新しい方向は「s」です。バックスラッシュの場合、新しい方向は3秒です(エンコーディング0123の選択により、これが機能します)。スペースの場合は、同じ方向「d」に進みます。そして、それが他のキャラクター「c」の場合、ゲームは終了し、charが「x」の場合は「true」、それ以外の場合はfalseを出力します。

物事を開始するために、初期位置「c」と開始方向(方向を0123に初期エンコードする)で再帰関数「n」を呼び出します。

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

16
Brian

この  was 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));
16
Nathan Baulch

ルビー、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 =>右

コードはこの事実に基づいて、xおよびyを正しい量(0、1、または-1)ずつインクリメントします。どの数値が各方向にマップされるかを並べ替えて、ビット単位の操作を行って値を増やすことができる配置を探しました。これは、算術バージョンよりも短いと感じているためです。

11
Mike Spross

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

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ソリューションを打ち負かしていません!

9
caf

Golfscript(83文字)

こんにちは、ニブラー!

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

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()
9
John La Rooy

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

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

9
Noldorin

JavaScript-265文字

pdate IV-オッズは、これが更新の最後のラウンドであり、do-whileループに切り替えて運動方程式を書き換えることにより、さらに数文字を保存することができます。

pdate III-Math.abs()を削除し、変数をグローバルネームスペースに配置することに関して、stragerの提案に感謝します。文字。

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

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以下の入力で正常に動作します。ヘッダーを含めずに標準ライブラリをリンクするコンパイラが必要です。そして、私は終わったと思います ストラージャーは私を打ち負かす 彼の助けを借りても、かなりのストレッチで。

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

ルビー-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
6
John La Rooy

ミラーの家

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

これはScalaで書かれており、オープンソースで利用可能です here

それはもう少しします。色やさまざまな種類のミラーやデバイスを扱っていますが、バージョン0.00001はこの課題にまさに応えるものでした。私はそのバージョンを失いましたが、とにかく文字数が最適化されていません。

6
HRJ

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 =
5
KirarinSnow

ハスケル、 395391383361 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
4
comingstorm

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

 puts Board.new.validate(input)

32文字\ o/... wohoooo

3
Rishav Rastogi

C++:88文字

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

18ヘッダーなし)


使い方:

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

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

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

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

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

Perl 219
私のPerlバージョンは 392 342文字の長さ(ビームがレーザーに当たる場合を処理する必要がありました):
Update、Hobbsにtr//を思い出させてくれてありがとう、現在は250文字です:
Updatem//mを削除、2つのwhileループを変更いくつかの節約をもたらしました。必要なスペースは1つだけになりました。
L:it;goto Ldo{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ステートメントを読み取れることを理解している場合、これは自明です。

0
dlamblin

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

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

更新わずかに変更。送信機がヒットした場合に正しく停止するようになりました。 IndexOfAnyに対するブライアンのアイデアをつままれました(その行が非常に冗長なのは残念です)。私は実際にコンソールから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))
0
Benjol