Code Golf:激光

Lir*_*una 152 language-agnostic code-golf rosetta-stone

挑战

按字符计数的最短代码输入板的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)
Run Code Online (Sandbox Code Playgroud)

只有一个激光器,只有一个目标.墙必须形成任何大小的实心矩形,激光和目标放在里面."房间"内的墙壁是可能的.

激光射击并从其原点移动到它指向的方向.如果激光射到墙上,它就会停止.如果激光射到镜子上,它会反射到镜子指向的方向90度.镜子是双面的,这意味着两面都是"反光的"并且可以以两种方式反射光线.如果激光射击激光(^v><)本身,则将其视为墙壁(激光束会破坏投影仪,因此它永远不会击中目标).

测试用例

Input:
    ##########
    #   / \  #
    #        #
    #   \   x#
    # >   /  #
    ########## 
Output:
    true

Input:
    ##########
    #   v x  #
    # /      #
    #       /#
    #   \    #
    ##########
Output:    
    false

Input:
    #############
    #     #     #
    # >   #     #
    #     #     #
    #     #   x #
    #     #     #
    #############
Output:
    false

Input:
    ##########
    #/\/\/\  #
    #\\//\\\ #
    #//\/\/\\#
    #\/\/\/x^#
    ##########
Output:
    true

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

mob*_*mob 78

Perl,166 160个字符

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

当比赛结束时,解决方案有166招,但是A.雷克斯已经找到了几种方法来削减6个角色:

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

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

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

它搜索的元素%t为匹配的字符> ^ <v,并同时设置$d为0和3之间的值,指示激光束的初始方向.

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

$d^=3*/\\/+m</>
Run Code Online (Sandbox Code Playgroud)

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

$r+=(1,-99,-1,99)[$d] ; $_ = $t{$r}
Run Code Online (Sandbox Code Playgroud)

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

/[\/\\ ]/ && redo
Run Code Online (Sandbox Code Playgroud)

如果我们在空白区域或镜像角色,请继续.否则我们终止,true如果我们在目标($_ =~ /x/)和false否则.

限制:可能无法处理超过99列的问题.这个限制可以删除3个字符,

  • 但是使用正则表达式来旋转电路板?那病了.这就像是一个自动20击中奖金. (13认同)
  • 我可以改变99到1E5,使其非常强大,代价是3个字符. (5认同)
  • 在帖子的顶部,您的最佳解决方案会更加引人注目. (2认同)

hob*_*bbs 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}
Run Code Online (Sandbox Code Playgroud)

说明:

$/ = %d = (' ' => '>', '/' => '^', '\\' => 'v');
Run Code Online (Sandbox Code Playgroud)

如果右移光束进入{空间,上角镜,下角镜},它就会成为{右移光束,向上移动光束,向下移动光束}.$/沿途初始化- 幸运的是"6"不是有效的输入字符.

$_ = <>;
Run Code Online (Sandbox Code Playgroud)

把板读进去$_.

$s="#";
Run Code Online (Sandbox Code Playgroud)

$s是光束坐在上面的任何东西的象征.由于激光发射器应像墙壁一样对待,因此将其设置为墙壁.

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

如果激光束指向除右侧之外的任何方向,则旋转其符号,然后将整个板旋转到位(也旋转镜子的符号).这是一个90度的左旋转,通过在移动行和列的同时反转行来有效地实现,具有略微恶劣的s///e副作用.在高尔夫代码中,tr以y'''允许我跳过反斜杠的形式写入.

die "true\n" if />x/; die "false\n" if />#/;
Run Code Online (Sandbox Code Playgroud)

如果我们击中目标或墙壁,请使用正确的消息终止.

$s = $1 if s/>(.)/$s$d{$1}/;
Run Code Online (Sandbox Code Playgroud)

如果激光器前面有空的空间,请向前移动.如果激光器前面有一面镜子,则向前移动并旋转光束.在任何一种情况下,将"已保存的符号"放回旧光束位置,并将我们刚刚覆盖的东西放入已保存的符号中.

redo;
Run Code Online (Sandbox Code Playgroud)

重复直到终止.{...;redo}是两个字符小于for(;;){...}三个小于while(1){...}.

  • 你......你的怪物! (39认同)
  • 高尔夫球结束了.你怎么能用正则表达式来旋转2D板?! (21认同)
  • 跆拳道?perl程序员是向导. (13认同)
  • 旋转板......疯了.Regexp ...... Crazier.O_O (4认同)
  • LiraNuna:我选择将其视为恭维. (4认同)
  • 这个解决方案是否正确 我在第一个测试用例中输出了false. (3认同)
  • 对于它的价值,它不仅仅是一个正则表达式.替换在`while`循环中运行,`/ g`修饰符在字符串中的匹配上添加另一个循环,`/ e`修饰符允许为每个匹配运行代码.那是嵌套循环,就在那里.它只是隐含地发生了很多.这就是我最骄傲的一点,并且(如果你查看修订历史记录)最需要做的工作是正确的. (2认同)
  • 我想打败你,但我不知道怎么做.; d (2认同)

str*_*ger 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;);}
Run Code Online (Sandbox Code Playgroud)

说明

如果你不理解,这种怪异可能很难理解.只是预警.

#define M(a,b)*p==*#a?m=b,*p=1,q=p:
Run Code Online (Sandbox Code Playgroud)

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

*q,G[999],*p=G;
w;
Run Code Online (Sandbox Code Playgroud)

声明一些变量.*q是灯光的当前位置.*G是游戏板作为一维阵列.*p是填充时的当前读取位置G.*w是电路板的宽度.

main(m){
Run Code Online (Sandbox Code Playgroud)

很明显main. m是存储运动矢量的变量.(这是main作为优化的参数.)

    for(;(*++p=getchar())>0;)
Run Code Online (Sandbox Code Playgroud)

遍历所有字符,G使用填充p.跳过G[0]优化(不需要p在第三部分再次浪费字符写入for).

        M(<,-1)
        M(>,1)
        M(^,-w)
        M(v,w)
Run Code Online (Sandbox Code Playgroud)

如果可能,使用上述宏来定义激光器. -11对应于左,右,分别与-ww上下.

        !w&*p<11
            ?w=p-G
            :0;
Run Code Online (Sandbox Code Playgroud)

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

    for(;
        q+=m,
Run Code Online (Sandbox Code Playgroud)

通过运动矢量移动灯光.

        m=
        *q&4
            ?(*q&1?-1:1)*(
                m/w?m/w:m*w
            )
Run Code Online (Sandbox Code Playgroud)

反映运动矢量.

            :*q&9
                ?!puts(*q&1?"false":"true")
                :m
        ;
Run Code Online (Sandbox Code Playgroud)

如果这是一个墙,或者x使用适当的消息退出(m=0终止循环).否则,什么都不做(noop; m=m)

    );
}
Run Code Online (Sandbox Code Playgroud)

  • 啊! 当火警在我的公寓大楼响起时,我正在研究一种C解决方案.现在我被打败了.不错的解决方案. (8认同)
  • 删除`puts`的声明有帮助,但还不足以使它低于170. 209虽然是相当不错的,所以我想我会留下它.伙计们,感谢您的帮助.对此,我真的非常感激.=](任何可以取消那些Perl女巫的东西!) (2认同)

Pla*_*ure 36

我敢打赌,人们一直在等待这一次LOOOOONG时间.(你是什么意思,挑战结束了,没有人关心?)

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

Befunge-93!

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

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

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

说明

如果您不熟悉Befunge语法和操作,请在此处查看.

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

另一个地方靠近左上角:

######
    a#
######
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我上面突出显示的区域是我存储几个坐标的位置.中间行的第一列是我存储当前"光标位置"的x坐标的地方; 第二列是我存储y坐标的地方; 接下来的两列用于存储激光束源的x坐标和y坐标; 最后一列(其中带有'a'字符)最终被覆盖以包含当前的光束方向,当光束的路径被跟踪时,该方向明显改变.

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

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

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

  • 检查当前光束方向并适当增加或减少光标坐标.(我这样做是为了避免在第一步中正确处理激光束的角落情况.)
  • 阅读该位置的角色.
  • 如果字符是"#",则将换行符和"false"放在堆栈上,打印并结束.
  • 将它与所有光束字符[<> ^ v]进行比较; 如果有匹配,也打印"false \n"并结束.
  • 如果角色是空格,则清空堆栈并继续.
  • 如果该字符是正斜杠,则将光束方向放入堆栈并依次将其与每个方向字符进行比较.找到一个时,新方向存储在代码中的相同位置,循环重复.
  • 如果字符是反斜杠,则基本上与上面的相同(除了正确的反斜杠映射).
  • 如果角色是'x',我们就会击中目标.打印"true \n"并退出.
  • 如果字符不是这些,请打印"error \n"并退出.

如果对它有足够的需求,我会试着指出代码中的所有这些都完成了.

  • +1 - 只是因为它可能被误解为在记事本中打开的EXE. (14认同)

Bri*_*ian 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    
Run Code Online (Sandbox Code Playgroud)

样品:

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

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

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

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

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

##########
#  /    \#
# / \    #
#/    \ x#
#\^/\ /  #
##########
false
Run Code Online (Sandbox Code Playgroud)

  • 我实际上可以阅读这一个!神奇! (54认同)
  • 我怜悯付钱的傻瓜维持代码高尔夫球条目. (20认同)
  • Java/C#代码高尔夫是由行而不是字符计算的.这是障碍. (17认同)
  • @strager在你被雇用来维护代码并且原来的开发人员早已离开的3年内并没有让人沮丧. (3认同)
  • 是的,现在将to_list更改为toList.不完整的匹配警告很好; 这是代码高尔夫,所以我没有做代码:| _ - > failwith"不可能" (2认同)

Joh*_*ooy 29

Golfscript - 83个字符(我的混搭和strager's)

换行就在这里用于包装

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

Golfscript - 107个字符

新线就是为了清晰起见

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

这个怎么运作.

第一行计算出初始位置和方向.
当激光击中镜子时,第二行逐步转动.


Jer*_*ten 18

Ruby中的353个字符:

现在有314 277个字符!

好的,Ruby中有256个字符,现在我已经完成了.好的圆号停在.:)

247个字符.我无法阻止.

223 203 201 Ruby中的字符

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)}
Run Code Online (Sandbox Code Playgroud)

有空格:

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)
}
Run Code Online (Sandbox Code Playgroud)

稍微重构:

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
Run Code Online (Sandbox Code Playgroud)

  • 不.你可以做++ i,但它只是让它真的像过去那样积极. (6认同)

The*_*ran 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
Run Code Online (Sandbox Code Playgroud)

我忘了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和方向d.d是其中一个角色l

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

while' '<d: space的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]在转换表中查找光束的新方向.如果表中不存在当前char,则设置d为space.

print'#'<c 如果我们停在目标以外的任何地方,则打印false.

  • `p + = 1j**z`:那很好. (9认同)

Bri*_*ian 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])
Run Code Online (Sandbox Code Playgroud)

让我们逐行说说吧.

首先,将所有输入粘贴到一个大的一维数组中(2D数组对于代码高尔夫来说可能不好;只需使用一维数组并将一行的宽度加/减到索引以向上/向下移动一行).

接下来,我们通过索引到我们的数组来计算'w',输入行的宽度和'c',即起始位置.

现在让我们定义'next'函数'n',它取当前位置'c'和方向'd',即向上,向左,向右,向下为0,1,2,3.

索引 - epsilon'e'和what-new-direction-if-we-hit-a-slash'是由表计算的.例如,如果当前方向'd'为0(向上),则表的第一个元素显示"-w,2",这意味着我们将索引减去w,如果我们按下斜线,则新方向为2 (对).

现在我们用(1)下一个索引("c + e" - 当前加上epsilon)和(2)新方向递归到下一个函数'n',我们通过向前看来计算数组中的内容.下一个细胞.如果前瞻字符是斜线,则新方向为's'.如果它是反斜杠,则新方向为3-s(我们选择编码0123使其工作).如果它是一个空间,我们只是朝'd'方向前进.如果它是任何其他角色'c',则游戏结束,如果char为'x'则打印'true',否则打印为false.

为了解决问题,我们使用初始位置"c"和起始方向(将方向的初始编码转换为0123)调用递归函数"n".

我想我可能仍然可以剃掉一些更多的角色,但我对它很满意(而且这是一个很好的数字).


Nat*_*lch 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};
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:经过一些实验,以下相当详细的搜索代码:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我的天啊.这是一个很好的例子,展示了强大的linq和c#如何成为.1+因为我是一个巨大的c#粉丝.X) (8认同)

Met*_*ark 11

称重为18203个字符的Python解决方案可以:

  • 应对"房间"外面的镜子
  • 根据2D限制计算没有"房间"的轨迹(规范说明了"房间"中的内容,但如果房间必须存在则不会
  • 报告错误

它仍然需要整理一下,我不知道2D物理是否要求光束不能自行穿过......

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

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

The board is made out of 4 types of tiles:

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

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

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



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

MIRRORS = (MIRROR_NE_SW, MIRROR_NW_SE)

LASERS = (LASER_DOWN, LASER_UP, LASER_RIGHT, LASER_LEFT)

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

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

ROW, COLUMN = range(2)

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

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

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



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

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

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

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

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

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

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

    #Keep on looping until an ultimate conclusion
    while True:

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

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

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

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

        #Perform wrapping
        except IndexError:

            #Obtain the row position
            row_pos = beam_pos[ROW]

            #Handle vertical wrapping
            if axis == ROW:

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

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

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

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

            #Handle horizontal wrapping
            elif axis == COLUMN:

                #Obtain the row
                row = tiles[row_pos]

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

                #Obtain the column position
                col_pos = beam_pos[COLUMN]

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

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

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

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

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

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

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

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

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

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

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

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

        #Obtain the current row
        row = tiles[row_pos]

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

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

            #Obtain the current column
            tile = row[col_pos]

            #Handle finding a laser
            if tile in LASERS:

                #Return the laser's position
                return row_pos, col_pos

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

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

    #Obtain the row position
    row_pos = pos[ROW]

    #Obtain the column position
    col_pos = pos[COLUMN]

    #Obtain the row
    row = tiles[row_pos]

    #Obtain the tile
    tile = row[col_pos]

    #Return the tile
    return tile

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

    number_of_rows = len(tiles)

    row_iter = range(number_of_rows)

    if reverse:
        row_iter = reversed(row_iter)

    for row_pos in row_iter:
        row = tiles[row_pos]

        number_of_cols = len(row)

        col_iter = range(number_of_cols)

        if reverse:
            col_iter = reversed(col_iter)

        for col_pos in col_iter:
            tile = row[col_pos]

            if tile == SOLID_WALL:
                pos = row_pos, col_pos

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

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

                    next_pos[axis] += offset

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

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

                return pos

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

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

    #Safely lookup the tile
    try:

        #Return known tiles
        return TILES[tile]

    #Handle unknown tiles
    except KeyError:

        #Return a default value
        return

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

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

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

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

    #Safely handles outside input
    try:

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

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

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

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

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

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

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

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

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

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

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

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

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

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

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

        lines[error.row_pos] = line

        board = "\n".join(lines)

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

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

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

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

        lines = board.split("\n")

        line = lines[error.row_pos]

        before = line[:error.col_pos]

        after = line[error.col_pos + 1:]

        symbol = line[error.col_pos]

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

        lines[error.row_pos] = line

        board = "\n".join(lines)

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

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

    #If a result was returned
    else:

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

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

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

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

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

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

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

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

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

    #Return the container
    return tiles

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

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

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

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

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

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

    tiles = parse_board(board)

    validate_board(tiles)

    return does_laser_hit_target(tiles)

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

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

    found_laser = False
    found_target = False

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

    number_of_rows = len(tiles)

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

        number_of_cols = len(row)

        for col_pos in range(number_of_cols):

            tile = row[col_pos]

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

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

    if not found_laser:
        raise NoLaserError(tiles)

    if not found_target:
        raise NoTargetError(tiles)



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

    pass

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

    symbols = "^v><"

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

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

    symbols = "x"

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

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

    symbols = "^v><"

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

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

    symbols = "x"

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

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

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

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

    __slots__ = ("__row_pos", "__col_pos")

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

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

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

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

    def __get_row_pos(self):
        return self.__row_pos

    def __get_col_pos(self):
        return self.__col_pos

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

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

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

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

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

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

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



if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

用于显示颜色错误报告的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#
#\\^/\\ /  #
##########"
Run Code Online (Sandbox Code Playgroud)

开发中使用的单元测试:

#!/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
Run Code Online (Sandbox Code Playgroud)

  • 激光物理学要求光束*可以自我交叉.以上评论是一个重要的文化参考. (6认同)
  • 乌龟和野兔编码高尔夫的方法.提供明显太多字符的东西(比当前赢家多91倍),但要注意规范的每个字母.虽然缓慢而稳定但通常会让我减少合同工作. (5认同)

Mik*_*oss 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}
Run Code Online (Sandbox Code Playgroud)

我使用了一个简单的状态机(像大多数海报一样),没什么特别的.我只是用我能想到的每一个技巧来缩减它.用于改变方向的按位XOR(在变量中存储为整数c)比我在早期版本中的条件有了很大的改进.

我怀疑代码增加x并且y可以缩短.以下是执行递增的代码部分:

c<2&&y+=c*2-1;c>1&&x+=(c-2)*2-1
Run Code Online (Sandbox Code Playgroud)

编辑:我能够略微缩短上述内容:

c<2&&y+=c*2-1;c>1&&x+=2*c-5
Run Code Online (Sandbox Code Playgroud)

激光器的当前方向c存储如下:

0 => up
1 => down
2 => left
3 => right

代码依赖于这个事实来递增xy正确的量(0,1或-1).我尝试重新排列哪些数字映射到每个方向,寻找一种安排,让我做一些按位操作来增加值,因为我有一种唠叨的感觉,它会比算术版本短.


Nol*_*rin 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;}}
Run Code Online (Sandbox Code Playgroud)

稍微更具可读性:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

字符的主要浪费似乎在于找到地图的宽度和激光源的位置.任何想法如何缩短这个?

  • 问题要求完整的程序,而不是功能. (4认同)

caf*_*caf 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");}
Run Code Online (Sandbox Code Playgroud)

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

它打破了200个字符标记 - 但它还没有打败那些Perl解决方案!

  • 这里最好的解决方案是"所有线都是相同长度"的假设.在高尔夫和战争中都很公平. (2认同)

str*_*ger 9

Golfscript(83个字符)

你好,gnibbler!

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

  • golfscript:perl~ = 1:1.7 (3认同)

Joh*_*ooy 9

Python - 152

从名为"L"的文件中读取输入

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

要从stdin读取,请用此替换第一行

import os;A=os.read(0,1e9)
Run Code Online (Sandbox Code Playgroud)

如果您需要小写的真/假,请将最后一行更改为

print`D<5`.lower()
Run Code Online (Sandbox Code Playgroud)


rjz*_*zii 7

JavaScript - 265个字符

更新IV - 赔率是这将是最后一轮更新,通过切换到do-while循环并重写运动方程,设法保存了几个字符.

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

更新II - 对代码的一些更新,以删除!= -1的使用以及更长时间操作的一些更好的变量使用.

更新 - 通过创建对indexOf函数的引用(感谢LiraNuna!)并删除不需要的括号时,通过并进行一些更改.

这是我第一次打码高尔夫,所以我不确定这可能会有多好,任何反馈都是值得赞赏的.

完全最小化版本:

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

带评论的原始版本:

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;
    }
Run Code Online (Sandbox Code Playgroud)

要测试的网页:

<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>
Run Code Online (Sandbox Code Playgroud)


dmc*_*kee 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");}
Run Code Online (Sandbox Code Playgroud)

未压缩(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");
}
Run Code Online (Sandbox Code Playgroud)

没有输入验证,错误的输入可以将其发送到无限循环.使用不大于99到99的输入正常工作.需要一个能够链接标准库而不包含任何标题的编译器.而且我想我已经完成了,即使在他的帮助下,斯特雷格还是让我在相当长的时间内击败了他.

我更希望有人能够展示一种更微妙的方式来完成任务.这没有什么不对,但它并不是很神奇.

  • `"没有输入验证"` - 应该没有.为了方便高尔夫球手,除非另有说明,否则输入被假定为"干净". (2认同)

HRJ*_*HRJ 6

镜子之家

不是真正的挑战,但我写了一个基于这个概念的游戏(不会太久).

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

它做得多一点; 处理颜色和各种类型的镜子和设备,但0.00001版本正是这个挑战所要求的.我失去了那个版本,但它从来没有针对字符数进行优化.


Joh*_*ooy 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
Run Code Online (Sandbox Code Playgroud)


Kir*_*now 5

PostScript,359个字节

第一次尝试,还有很大的改进空间......

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