高尔夫代码:激光


152

挑战

按字符计数的最短代码,用于输入板的2D表示,并根据输入输出“ true”或“ false”

木板由4种类型的瓷砖制成:

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

只有一台激光,只有一个目标。墙壁必须形成一个任何大小的实心矩形,并将激光和目标放置在内部。“房间”内的墙壁是可能的。

激光射线从其原点射向其指向的方向。如果激光束撞击墙壁,它将停止。如果激光束击中镜子,它会向镜子指向的方向反弹90度。镜子是两面的,这意味着两面都是“反射性的”,并且可能以两种方式反射光线。如果有激光束撞击激光(^v><)本身,则将其视为一堵墙(激光束会破坏光束投射器,因此它将永远不会撞击目标)。

测试用例

输入:
    ##########
    #/ \#
    ##
    # \ X#
    #> /#
    ########## 
输出:
    真正

输入:
    ##########
    #vx#
    #/#
    #/#
    #\#
    ##########
输出:    
    假

输入:
    #############
    ###
    #>##
    ###
    # # X #
    ###
    #############
输出:
    假

输入:
    ##########
    #/ \ / \ / \#
    #\\ // \\\#
    #// \ / \ / \\#
    #\ / \ / \ / x ^#
    ##########
输出:
    真正

代码计数包括输入/​​输出(即完整程序)。


84
IMMA CHARGIN'MAH LAZER!
奥拉维尔Waage

37
这是真棒
GManNickG

33
不要
越过障碍

49
@GameFreak:真是老了。
Artelius

24
那头鲨鱼实际上是“ ^”鲨鱼,脑袋上有一个疯子吗?
内森·费格09年

Answers:


78

Perl,166160个字符

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

比赛结束时,Solution达到了166招,但是A. Rex找到了几种方法来减少6个字符:

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

第一行将输入加载到%t板子的表中,该表$t{99*i+j}在第ij列保存字符。然后,

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

它会搜索的元素以查找%t> ^ <或匹配的字符,v同时将其设置$d为介于0和3之间的值,该值指示激光束的初始方向。

在主循环的每次迭代开始时,我们都会更新$d光束是否在镜子上。XOR'ing 3给出\镜像的正确行为,XOR'ing 1给出/镜像的正确行为。

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

接下来,根据$r当前方向更新当前位置。

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

我们在当前位置分配字符,$_以方便使用匹配运算符。

/[\/\\ ]/ && redo

如果我们在空格或镜像字符上,请继续。否则,true如果我们位于目标($_ =~ /x/)上,false则终止,否则终止。

限制:可能无法解决超过99列的问题。可以删除此限制,但要多花3个字符,


好的,最多可以输入323个字符。= D
斯特拉格

5
我可以将99更改为1E5,使其非常健壮,但要牺牲3个字符。
暴徒

2
您最好的解决方案将在帖子顶部更加引人注目。
斯特拉格

13
但是使用正则表达式旋转电路板吗?真恶心 这就像自动20笔奖金。
暴徒

1
@mobrule:保存六招:重排序的第一行作为s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;,变化%d=split//,.." to %d = .. =〜/./克, and change 的grep {..}%t`至grep..,%t
A.雷克斯

75

Perl,177个字符

可以删除第一个换行符;其他两个是强制性的。

$/=%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'''允许我跳过一个反斜杠的形式编写。

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

如果我们击中目标或墙,则以正确的消息终止。

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

如果激光器前面有一个空白空间,请向前移动。如果激光器前面有镜子,请向前移动并旋转光束。无论哪种情况,都将“保存的符号”放回旧的梁位置,然后将我们刚刚改写的东西放到保存的符号中。

redo;

重复直到终止。{...;redo}for(;;){...}少两个字符,比少三个字符while(1){...}


4
旋转板...疯狂。正则表达式... Crazier。O_o
斯特拉格

39
你...你是怪物!
LiraNuna

4
LiraNuna:我选择将其作为一种赞美。
hobbs 09/09/26

21
高尔夫结束了。您怎么能击败用正则表达式旋转2D电路板?
Konrad Rudolph

13
wtf?perl程序员是向导。
Johannes Schaub-litb

39

C89(209个字符)

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

说明

如果您不了解C,可能很难理解这种怪异。只是预警。

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

这个小宏检查当前字符(*p)是否等于a字符形式(*#a)中的任何字符。如果它们相等,则将运动矢量设置为bm=b),将此字符标记为墙(*p=1),并将起点设置为当前位置(q=p)。该宏包括“其他”部分。

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

声明一些变量。* q是灯光的当前位置。* G是游戏板上的一维数组。* p是填充时的当前读取位置G。* w是木板的宽度。

main(m){

明显mainm是存储运动矢量的变量。(这main是优化的参数。)

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

循环浏览所有字符,并G使用填充p。跳过G[0]作为优化(无需p在的第三部分中浪费字符再次书写for)。

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

如果可能的话,使用上述宏来定义缓存器。 -1和分别1对应于左和右,-w以及w上和下。

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

如果当前字符是行尾标记(ASCII 10),请设置宽度(如果尚未设置)。跳过G[0]允许我们写w=p-G而不是w=p-G+1。同样,这也?:从结束了链M

    for(;
        q+=m,

通过运动矢量移动灯光。

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

反映运动矢量。

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

如果这是墙或x,请退出并显示相应的消息(m=0终止循环)。否则,不执行任何操作(noop; m=m

    );
}

8
啊! 当我的公寓大楼响起火警时,我正在研究C解决方案。现在我被打败了。不错的解决方案。
rlbond

使用临时变量进行交换和交换/取反步骤的方法将为您节省几个字符。
Artelius

@Artelius,是的,我意识到了这一点,还有其他一些事情。谢谢。
斯特拉格09/09/26

1
TCC实际上不喜欢无类型的声明和错误:g.c:3: declaration expected
Mark Rushakoff 09年

2
删除puts的声明有帮助,但不足以使它低于170。但是209相当不错,所以我想保留它。伙计们,谢谢您的帮助。我真的很感激。=](任何要废除那些Perl女巫的东西!)
斯特拉格

36

我敢打赌,人们一直在等待这个时间太久了。(您是什么意思,挑战已经结束,没人在乎了吗?)

看...我在这里提出一个解决方案

Befunge-93!

它的权重高达973个字符(如果您足够慈善,可以忽略空格,则为688个字符,它仅用于格式化,在实际代码中不执行任何操作)。

警告:不久前,我在Perl中编写了自己的Befunge-93解释器,不幸的是,这是我真正有时间对其进行测试的全部内容。我总体上对它的正确性很有信心,但是它对EOF可能有一个奇怪的限制:由于Perl的<>运算符在文件末尾返回undef,因此在数字上下文中将其处理为0。对于EOF具有不同值(例如-1)的基于C的实现,此代码可能不起作用。

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

说明

如果您不熟悉Befunge的语法和操作,请在此处检查。

Befunge是一种基于堆栈的语言,但是有些命令允许人们将字符写入Befunge代码。我在两个地方利用了这一点。首先,我将整个输入复制到Befunge板上,但位于实际编写的代码下方几行。(当然,这在代码运行时实际上是不可见的。)

另一个地方在左上角附近:

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

在这种情况下,我上面突出显示的区域就是我存储几个坐标的地方。中间行的第一列是我存储当前“光标位置”的x坐标的位置;第二列是我存储y坐标的位置;接下来的两列用于存储找到的激光束源的x和y坐标;最后一列(其中带有“ a”字符)最终将被覆盖以包含当前的光束方向,该方向显然会随着追踪光束的路径而变化。

程序通过将(0,27)作为初始光标位置开始。然后一次读取一个字符并将其放置在光标位置。换行符仅导致y坐标增加而x坐标返回0,就像实际回车一样。最终,undef被解释器读取,并且0字符值用于表示输入结束并继续进行激光迭代步骤。读取激光字符[<> ^ v]时,该字符也被复制到内存存储库中(在'a'字符上方),其坐标也被复制到左侧的列中。

所有这些的最终结果是,整个文件基本上都被复制到Befunge代码中,比所遍历的实际代码要低一些。

然后,将光束位置复制回光标位置,并执行以下迭代:

  • 检查当前光束方向,并适当增加或减少光标坐标。(我首先这样做是为了避免在刚开始时就必须处理激光束的角部情况。)
  • 在该位置读取字符。
  • 如果字符为“#”,则将换行符和“ false”放在堆栈上,然后打印并结束。
  • 将其与所有波束字符[<> ^ v]进行比较;如果有匹配项,还显示“ false \ n”并结束。
  • 如果字符是空格,则清空堆栈并继续。
  • 如果字符是正斜杠,则将光束方向移到堆栈上,然后依次将其与每个方向字符进行比较。找到一个方向后,新方向将存储在代码中的同一位置,然后重复循环。
  • 如果字符是反斜杠,请执行与上述基本相同的操作(除了正确的反斜杠映射之外)。
  • 如果字符是“ x”,我们已经击中目标。打印“ true \ n”并退出。
  • 如果这些字符都不是,请打印“ error \ n”并退出。

如果有足够的需求,我将尝试指出代码在哪里完成了所有这些工作。


14
+1-仅因为它可能被误解为在记事本中打开的EXE。
凯尔·罗森多

1
嗯...圣****。我搞砸了Befunge,这确实非常令人印象深刻。
Almo '04 -4-26

用混淆的语言编码高尔夫……例如花生酱和卡宴!
wberry 2012年

29

F#,36行,可读性强

好的,只是为了得到答案:

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

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

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

while true do
    p <- next p    

样品:

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

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

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

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

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

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

54
我实际上可以读这一个!神奇!
杰夫·阿特伍德

17
Java / C#代码高尔夫球是用行而不是字符来计数的。那是障碍。
内森·费格

3
@strager在雇用您来维护代码的3年时间里并不沮丧,原始开发者已经离开了很长时间。
内森·费格

这在Visual Studio 2010中使用F#失败。Seq.to_list不存在(确定,将其更改为toList),然后是第25行,不完整的模式匹配。
罗素

2
是的,现在将to_list更改为toList。比赛不完整警告是可以的;它是代码高尔夫球,所以我没有做类似以下的代码:_-> failwith“不可能”
Brian

29

Golfscript-83个字符(我和斯特拉格的混搭)

换行符只用于包装

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

Golfscript-107个字符

换行符只是为了清晰

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

这个怎么运作。

第一行计算出初始位置和方向。
每当激光打到镜子上时,第二行都会逐步转向。


18

Ruby中的353个字符:

314 现在277个字符!

好的,在Ruby中为256个字符,现在我完成了。要停的不错的回合数。:)

247个字符。我停不下来

223个 203 201字符在红宝石

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

带空格:

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

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

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

稍微重构:

board = readlines

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

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

  ch = board[y][x].chr
  case ch
  when "/"
    direction = [1, 0, 3, 2][direction]
  when "\\"
    direction = 3 - direction
  when "x"
    puts "true"
    exit
  when "#"
    puts "false"
    exit
  end
end

但是...您可以重命名chC或任何其他1个字符以保存2个字符!
LiraNuna

好的,好的...我实际上意识到整个变量是不必要的,因为我只使用了一次。此功能和其他一些改进使它减少到247个字符。
杰里米·鲁滕

1
i++(代替i+=1)?
LiraNuna

6
不。您可以做++ i,但这确实使它确实像以前一样积极。
DigitalRoss

我喜欢压缩版本:#;​​ p
SeanJA

17

蟒蛇

294个 277 253个 240个 232字符,包括换行:

(第4行和第5行中的第一个字符是制表符,而不是空格)

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

我忘记了Python甚至还有可选的分号。

这个怎么运作

该代码背后的关键思想是使用复数表示位置和方向。行是虚轴,向下增加。列是实轴,向右增加。

l='>v<^';激光符号列表。选择顺序以使激光方向字符的索引对应于sqrt(-1)的幂

x={'/':'^<v>','\\':'v>^<',' ':l};转换表,用于确定光束离开不同图块时方向如何变化。磁贴是关键,新的方向是值。

b=[1];持有董事会。第一个元素为1(评估为true),以便while循环至少运行一次。

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和方向dd是其中的字符之一l

将板装入后b,当前位置p和方向d已设置为激光源的位置和方向。

while' '<d: 空格的ASCII值低于任何方向符号,因此我们将其用作停止标志。

z=l.find(d);l字符串中当前方向char的索引。z稍后将用于使用x表格确定新的光束方向并增加位置。

p+=1j**z;使用i的幂增加位置。例如,l.find('<')==2 -> i ^ 2 = -1,它将移到左侧的一列。

c=b[int(p.imag)][int(p.real)]; 读取当前位置的字符

d=x.get(c,' '*4)[z]在转换表中查找光束的新方向。如果表中不存在当前字符,则设置d为空格。

print'#'<c 如果我们停止目标以外的任何操作,则打印false。


9
p+=1j**z: 太贴心了。
dmckee ---前主持人小猫

16

就是 布赖恩的解决方案,以C#3的直接端口,减去控制台交互。这不是挑战,因为它不是一个完整的程序,我只是想知道他使用的某些F#构造如何用C#表示。

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

编辑:经过一些试验,以下相当冗长的搜索代码:

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

已被一些更紧凑的LINQ to Objects代码取代:

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

8
我的天啊。这是一个很好的示例,演示了如何强大的linq和c#变得如此。1+,因为我是C#的忠实粉丝。x)
Emiswelt

16

F#,255个字符(仍然相当可读!):

好了,经过一夜的休息,我做了很多改进:

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

让我们逐行讨论。

首先,将所有输入都包含在一个大的一维数组中(二维数组可能不利于代码合成;只需使用1D数组并将一行的宽度加/减到索引上即可上下移动一行)。

接下来,我们通过索引数组来计算输入线的宽度“ w”和起始位置“ c”。

现在,让我们定义“下一个”函数“ n”,该函数将当前位置“ c”和方向“ d”分别设为向上,向左,向右,向下的0、1、2、3。

索引ε“ e”和如果被击中的新方向“ s”由表计算。例如,如果当前方向“ d”为0(向上),则表的第一个元素为“ -w,2”,这意味着我们将索引减w,如果我们打斜杠,则新方向为2 (对)。

现在我们递归到下一个函数'n',其中(1)下一个索引(“ c + e”-当前加epsilon),以及(2)新方向,我们通过向前看以了解数组中的内容来计算下一个单元格。如果前瞻字符为斜杠,则新方向为“ s”。如果是反斜杠,则新方向为3-s(我们选择的编码0123可以实现此目的)。如果是空间,我们将一直朝着“ d”方向前进。如果是其他字符“ c”,则游戏结束,如果char为“ x”,则打印“ true”,否则为false。

首先,我们用初始位置“ c”和起始方向(将方向初始编码为0123)调用递归函数“ n”。

我想我可能仍然可以再剃掉几个字符,但是我对此非常满意(255是一个不错的数字)。


11

Python解决方案的权重为18203个字符,它可以:

  • 应对“房间”外的镜子
  • 在没有“房间”的情况下基于2D限制计算轨迹(规格说明了“房间”中必须包含的内容,但如果房间必须存在则没有)
  • 报告错误

它仍然需要进行一些整理,而且我不知道2D物理学是否规定光束不能自身交叉...

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

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

The board is made out of 4 types of tiles:

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

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

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



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

MIRRORS = (MIRROR_NE_SW, MIRROR_NW_SE)

LASERS = (LASER_DOWN, LASER_UP, LASER_RIGHT, LASER_LEFT)

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

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

ROW, COLUMN = range(2)

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

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

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



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

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

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

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

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

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

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

    #Keep on looping until an ultimate conclusion
    while True:

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

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

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

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

        #Perform wrapping
        except IndexError:

            #Obtain the row position
            row_pos = beam_pos[ROW]

            #Handle vertical wrapping
            if axis == ROW:

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

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

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

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

            #Handle horizontal wrapping
            elif axis == COLUMN:

                #Obtain the row
                row = tiles[row_pos]

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

                #Obtain the column position
                col_pos = beam_pos[COLUMN]

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

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

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

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

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

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

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

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

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

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

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

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

        #Obtain the current row
        row = tiles[row_pos]

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

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

            #Obtain the current column
            tile = row[col_pos]

            #Handle finding a laser
            if tile in LASERS:

                #Return the laser's position
                return row_pos, col_pos

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

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

    #Obtain the row position
    row_pos = pos[ROW]

    #Obtain the column position
    col_pos = pos[COLUMN]

    #Obtain the row
    row = tiles[row_pos]

    #Obtain the tile
    tile = row[col_pos]

    #Return the tile
    return tile

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

    number_of_rows = len(tiles)

    row_iter = range(number_of_rows)

    if reverse:
        row_iter = reversed(row_iter)

    for row_pos in row_iter:
        row = tiles[row_pos]

        number_of_cols = len(row)

        col_iter = range(number_of_cols)

        if reverse:
            col_iter = reversed(col_iter)

        for col_pos in col_iter:
            tile = row[col_pos]

            if tile == SOLID_WALL:
                pos = row_pos, col_pos

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

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

                    next_pos[axis] += offset

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

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

                return pos

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

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

    #Safely lookup the tile
    try:

        #Return known tiles
        return TILES[tile]

    #Handle unknown tiles
    except KeyError:

        #Return a default value
        return

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

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

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

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

    #Safely handles outside input
    try:

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

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

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

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

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

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

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

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

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

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

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

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

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

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

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

        lines[error.row_pos] = line

        board = "\n".join(lines)

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

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

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

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

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

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

        lines[error.row_pos] = line

        board = "\n".join(lines)

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

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

    #If a result was returned
    else:

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

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

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

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

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

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

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

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

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

    #Return the container
    return tiles

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

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

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

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

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

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

    tiles = parse_board(board)

    validate_board(tiles)

    return does_laser_hit_target(tiles)

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

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

    found_laser = False
    found_target = False

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

    number_of_rows = len(tiles)

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

        number_of_cols = len(row)

        for col_pos in range(number_of_cols):

            tile = row[col_pos]

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

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

    if not found_laser:
        raise NoLaserError(tiles)

    if not found_target:
        raise NoTargetError(tiles)



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

    pass

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

    symbols = "^v><"

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

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

    symbols = "x"

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

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

    symbols = "^v><"

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

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

    symbols = "x"

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

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

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

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

    __slots__ = ("__row_pos", "__col_pos")

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

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

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

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

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

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

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

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



if __name__ == "__main__":
    main()

一个bash脚本来展示颜色错误报告:

#!/bin/bash

declare -a TESTS

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

开发中使用的单元测试:

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

import unittest

from lasers import *

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

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

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

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

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

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

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

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

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

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

6
激光物理学表明光束可以自身交叉。以上评论是重要的文化参考。
dmckee ---前主持人小猫

5
乌龟和野兔编码高尔夫球的方法。交付的东西显然字符太多(比当前获胜者多91倍),但请注意规范中的每个字母。缓慢而稳定通常会使我的合同工作减少。
Metalshark

您的单元测试似乎缺少了一部分。它在“ self.NOT_DIRECTIO”处关闭
BioGeek 2010年

@BioGeek-达到帖子长度的限制;)。除了BASH样式测试,还可以突出显示颜色。
Metalshark,2011年

11

Ruby,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)。我尝试重新排列映射到每个方向的数字,寻找一种可以让我进行按位操作以增加值的排列,因为我a不安地认为它会比算术版本短。


9

C#3.0

259个字符

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

更具可读性:

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

焦炭的主要浪费似乎是在寻找地图的宽度和激光源的位置。任何想法如何缩短?


我不确定是否更短,但是这是我寻找激光并找到宽度的镜头:使用L = List <string>;使用P = System.Drawing.Point;使用L = List <string>; L r = new L (){“ v”,“ <”,“>”,“ ^”}; P p = new P(); r.ForEach(a => {int c = 0; v.ForEach(s => {c ++ ; if(s.IndexOf(a)!=-1){pX = s.IndexOf(a); pY = c;}});}); int l = v [0] .Length; v是包含表的List <string>,它输出代表激光位置的Point +代表宽度的int
RCIX

更好:使用L = List <string>; L l = new L(4){“ v”,“ <”,“>”,“ ^”}; var point = new {x = 0,y = 0}; int c = 0; l.ForEach(a => {m.ForEach(s => {if(s.IndexOf(a)!=-1){point = new {x = s.IndexOf(a),y = c};}}); c ++;}); int w = m [0] .Length;
RCIX

4
问题要求完整的程序,而不是功能。
斯特拉格

怎么样 while(1)
SSpoke

9

C + ASCII,197个字符:

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

这个C解决方案假设一个ASCII字符集,允许我们使用XOR镜像技巧。它也非常脆弱-例如,所有输入线的长度必须相同。

它的字符数低于200个字符-但这还算不错,但还没有击败过那些Perl解决方案!


= O!+1!恨我殴打。=]
斯特拉格

2
此处大多数最佳解决方案均假设“所有行的长度相同”。在高尔夫和战争中一切都公平。
hobbs

如果要求行的长度不同,我将为其添加一个测试用例。但我明确表示这是故意的:)
LiraNuna

9

Golfscript(83个字符)

你好,狼人!

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

3
golfscript:perl〜= 1:1.7
John La Rooy

9

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

要从标准输入中读取,请用以下内容替换第一行

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

如果需要小写的true / false,请将最后一行更改为

print`D<5`.lower()

更改TruetrueFalse需花费多少个字符false?;-)
暴民

您不能通过将“ print D<5” 更改为“ print D <5”来删除1个字符吗?还是我想念的东西?
Ponkadoodle

@wallacoloo,肯定可以。仅适用于小写的true / false
John La Rooy

7

JavaScript-265个字符

更新四很有可能这将是最后一轮更新,通过切换到do-while循环并重写运动方程式,设法节省了几个字符。

更新三感谢strager关于删除Math.abs()并将变量放在全局名称空间中的建议,再加上对变量分配的一些重新安排,使代码减少到282个字符。

更新二对代码进行了更多更新,以删除!= -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;
    }

要测试的网页:

<html>
  <head>
    <title>Code Golf - Lasers</title>
    <script type="text/javascript">
    a;b;c;d;e;function f(g){a=function(a){return g.indexOf(a)};b=a("\n")+1;a=g[c=e=a("v")>0?e:e=a("^")>0?e:e=a("<")>0?e:a(">")];d=a=="<"?-1:a==">"?1:a=="^"?-b:b;do{e=d==-1|d==1;a=g[c+=d=a=="\\"?e?b*d:d>0?1:-1:a=="/"?e?-b*d:d>0?1:-1:d];e=a=="x"}while(a!="#"^e);return e}
    </script>
  </head>
  <body>
    <textarea id="maze" rows="10" cols="10"></textarea>
    <button id="checkMaze" onclick="alert(f(document.getElementById('maze').value))">Maze</button>
  </body>
</html>

如何接受输入?我想测试并验证。此外,如果将引用保存到a.indexOf
LiraNuna

请替换index != -1index > 0!(希望没有人将lazer放在左上角,因此0不会被返回。=])您可以链接var语句或完全删除语句(将变量放在全局名称空间中)。我认为Math.abs(m)==1可以用代替m==-1|m==1。可以movement = ...; location += movement优化为location += movement =
斯特拉格

@ strager-刚刚看到您的评论,就像您在我更新代码时将其张贴到300个字符一样。我将看到消除Math.abs()可以做什么。
rjzii

function(a){return g.indexOf(a)}可以function(a)g.indexOf(a)在最新的JavaScript版本中替换。
user1686 2010年

6

镜屋

这不是挑战的实际入口,但我基于此概念编写了一款游戏(回溯时间不长)。

它是用Scala编写的,开源的,可以在这里找到

它做得更多。处理颜色和各种类型的反射镜和设备,但是0.00001版确实满足了此挑战的要求。我已经失去了那个版本,而且它从来没有针对字符计数进行过优化。


您是否可以上传可在Windows下运行的编译版本而无需安装scala?
米兰

有一个包含Scala库的版本。查看下载列表。但是无论如何,如果您现在已经安装了Scala,我很高兴得到您的支持:)
HRJ

6

c(K&R)339个必要字符,之后来自strager提出了更多建议。

我内的物理学家指出,传播和反射操作是时间反转不变的,因此,此版本会从目标投射光线并检查是否到达激光发射器。

其余的实现非常简单,是从我较早前的工作中或多或少地完全采用的。

压缩后:

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

未压缩(ish):

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

没有输入验证,错误的输入会将其发送到无限循环中。可以在输入不大于99 x 99的情况下正常工作。需要一个编译器,该编译器将链接标准库而不包含任何头文件。我想我完成了,斯特拉格击败了我了,即使在他的帮助下。

我希望有人会演示一种更微妙的方式来完成任务。这没有错,但这不是深奥的魔术。


不需要=0全局变量,因为它们默认情况下初始化为0。将字符常量替换为其等效的十进制数。使用>0代替!=EOF来检查EOF(和\0)。您可能会像使用s 一样#define删除一些代码。无论如何都不需要额外的内容,因为无论如何都必须打印换行符。 比短。希望这可以帮助。=]caseif\nputsputsfor(;;)while(1)
斯特拉格

@strager:谢谢。我总是以迭代的方式来介绍这些内容,因为我不这么认为……
dmckee ---前主持人小猫

2
"There is no input validation"-不应该有。为了使高尔夫球手轻松,除非另有说明,否则假定输入始终为“干净”。
LiraNuna

@dmckee,请放心,我们Code Golf的专业人士也会反复工作。但是,我们通常从一开始就使用一些技巧(例如我提到的一半),但这是有经验的。=]
斯特拉格

除非我算错了,否则程序是390个字符,而不是380个字符
。– strager

6

红宝石-146个字符

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

5

后记,359个字节

第一次尝试,还有很多改进的余地...

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

4

Haskell中,395个 391 383 361 339字符(优化)

仍然使用通用状态机,而不是任何聪明的东西:

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

可读版本:

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


3

C ++:388个字符

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

318不带标题)


这个怎么运作:

首先,读取所有行,然后找到激光。0只要未找到激光箭头,以下内容就会评估,并且同时将其分配给x水平位置。

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

然后,我们查看找到的方向并将其存储在中i。偶数的值i是上/左(“减少”),奇数的值是下/右(“增加”)。根据该概念,设置d(“方向”)和r(“方向”)。我们z用方向索引指针数组,并将方向添加到所获得的整数中。仅当我们打斜杠时方向才会改变,而当我们打反斜杠时方向保持不变。当然,当我们碰到镜子时,我们总是会改变方向(r = !r)。


您正在让我做自己的C ++解决方案。=]
斯特拉格

2
@strager,虽然这很无聊。让我们做一个在编译时xD时显示“ true”或“ false”的解决方案
Johannes Schaub-litb

添加了解释,因为我认为我会坚持下去:)
Johannes Schaub-litb

2

Groovy @ 279个字符

m=/[<>^v]/
i={'><v^'.indexOf(it)}
n=['<':{y--},'>':{y++},'^':{x--},'v':{x++}]
a=['x':{1},'\\':{'v^><'[i(d)]},'/':{'^v<>'[i(d)]},'#':{},' ':{d}]
b=[]
System.in.eachLine {b<<it.inject([]) {r,c->if(c==~m){x=b.size;y=r.size;d=c};r<<c}}
while(d==~m){n[d]();d=a[b[x][y]]()}
println !!d

2

C#

1020个字符。
1088个字符(从控制台添加的输入)。
925个字符(重构变量)。
875个字符(已删除冗余的字典初始化程序;已更改为二进制和运算符)

提出要不要在发帖之前先看别人的。我敢肯定这可能是LINQ了。在我看来,可读版本中的整个FindLaser方法似乎非常糟糕。但是,它有效并且很晚:)

请注意,可读类包括一个附加方法,该方法会在激光移动时打印出当前的Arena。

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

可读版本(不是最终的高尔夫版本,但前提相同):

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

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

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

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

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

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

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

    private bool FindTarget()
    {
        DrawArena();

        string chr = Arena[Position];

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

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

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

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

2
该程序应接受输入。最常见的是来自stdin。
LiraNuna

0

Perl的219
我的perl的版本是392 342个字符(我不得不处理束击中激光的情况下):
更新,感谢霍布斯提醒我tr//,它现在是250个字符:
更新,移除mm//,改变两个while带环节省一些;现在只需要一个空间。
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是每行中的字符数组,并且可以读取简单的regexp和tr语句,这应该是不言而喻的。


提示:您可以缩短镜像代码的长度。$_=$s;tr/^v<>/<>^v/$_=$s;tr/v^<>/<>^v/分别。另外,您不需要min m//
hobbs 09/09/26

抱歉,让第二个$_=$s;tr/v^></<>^v/;
霍布斯09/09/26

您仍然有几个if m/.../可能会if/.../在弹出窗口中保存两个字符。
hobbs

您可以使用y///代替tr///来保存两个字符。
白金天蓝色

0

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

他们是装饰。检查我的其他挑战,这只是格式化。
LiraNuna 2010年

@LiraNuna,好吧,事实证明,这个迭代还是会吃掉它们:)
Benjol 2010年

与一维实现进行比较会很好。只需为左和右加/减1,并为上下加/减w。我期望你会相当多的字符保存
约翰·拉ROOY

@ gnibbler,Brian已经做到了,我不确定是否可以击败他,但我可以尝试一下。
Benjol
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.