ボードの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
コードカウントには、入力/出力(完全なプログラム)が含まれます。
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文字を犠牲にして削除できますが、
最初の改行は削除できます。他の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文字です。
#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
)であるものと等しいかどうかをチェックします。それらが等しい場合、移動ベクトルをb
(m=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
)
);
}
私は人々がこれをLOOOOONGの時間待っていたに違いない。 (どういう意味ですか、挑戦は終わり、誰も気にしませんか?)
見よ...私はここで解決策を提示する
それは途方もない重量を量る 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コードにコピーされることです。実際のコードを少し下回ったところです。
その後、ビーム位置がカーソル位置にコピーされ、次の反復が実行されます。
十分な需要がある場合は、コードのどこでこれがすべて達成されているかを正確に指摘しようとします。
改行はラッピング用です
:|'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行目は、レーザーがミラーに当たるたびに方向転換します。
答えを得るためだけに。
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
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
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
を設定します。 d
はl
の文字の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を出力します。
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はニースの数字です)。
この は 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));
x=!0;y=0;e="^v<>#x";b=readlines;b.map{|l|(x||=l=~/[v^<>]/)||y+=1};c=e.index(b[y][x])
loop{c<2&&y+=c*2-1;c>1&&x+=2*c-5;e.index(n=b[y][x])&&(p n==?x;exit);c^=' \/'.index(n)||0}
(ほとんどのポスターと同様に)シンプルなステートマシンを使用しました。私は考え得るすべてのトリックを使ってそれを削り続けました。ビット単位のXOR方向を変更するために使用(変数c
に整数として格納)は、以前のバージョンの条件よりも大幅に改善されました。
x
とy
をインクリメントするコードが短くなる可能性があると思われます。増分を行うコードのセクションは次のとおりです。
c<2&&y+=c*2-1;c>1&&x+=(c-2)*2-1
編集:上記を少し短くすることができました:
c<2&&y+=c*2-1;c>1&&x+=2*c-5
レーザーの現在の方向c
は次のように保存されます。
0 =>上 1 =>下 2 =>左 3 =>右
コードはこの事実に基づいて、x
およびy
を正しい量(0、1、または-1)ずつインクリメントします。どの数値が各方向にマップされるかを並べ替えて、ビット単位の操作を行って値を増やすことができる配置を探しました。これは、算術バージョンよりも短いと感じているためです。
18203文字の計量はPythonソリューションであり、次のことが可能です。
それはまだいくらか整頓する必要があり、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
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ソリューションを打ち負かしていません!
こんにちは、ニブラー!
:\'><v^'.{\?}%{)}?:P@=?{:O[1-1\10?).~)]=P+
:P\=' \/x'?[O.2^.1^'true''false']=.4/!}do
「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()
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;
}
}
チャーの主な無駄は、マップの幅とレーザー源の位置を見つけることにあるようです。これを短縮する方法はありますか?
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>
私の物理学者は、伝播と反射の操作は時間反転不変であるため、このバージョンではターゲットから光線をスローし、レーザーエミッタに到達するかどうかを確認します。
実装の残りの部分は非常に単純であり、以前の先への取り組みから多少なりとも正確に取られています。
圧縮された:
#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以下の入力で正常に動作します。ヘッダーを含めずに標準ライブラリをリンクするコンパイラが必要です。そして、私は終わったと思います ストラージャーは私を打ち負かす 彼の助けを借りても、かなりのストレッチで。
誰かがタスクを達成するためのより微妙な方法を示すことを望んでいます。これには何の問題もありませんが、深い魔法ではありません。
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
ミラーの家
チャレンジへの実際のエントリーではありませんが、私はこのコンセプトに基づいてゲームを書きました(さかのぼって)。
これはScalaで書かれており、オープンソースで利用可能です here :
それはもう少しします。色やさまざまな種類のミラーやデバイスを扱っていますが、バージョン0.00001はこの課題にまさに応えるものでした。私はそのバージョンを失いましたが、とにかく文字数が最適化されていません。
最初の試み、多くの改善の余地...
/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 =
ハスケル、 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
コードの再利用を信じています。あなたのコードの1つをAPIとして使用します:)。
puts Board.new.validate(input)
32文字\ o/... wohoooo
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;
}
}
}
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
Perl 219
私のPerlバージョンは 392 342文字の長さ(ビームがレーザーに当たる場合を処理する必要がありました):
Update、Hobbsにtr//
を思い出させてくれてありがとう、現在は250文字です:
Update、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
ステートメントを読み取れることを理解している場合、これは自明です。
ゲームに少し遅れましたが、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))