激光镜门户派对


27

2D板包含以下对象:

  • ^>v,或<:一个激光发射器朝上,右,下,或左分别。可能不止一个。激光将在空的空间中以直线行进(空的空间由点表示.)。激光不会穿过发射器。
  • *: 目标。激光穿过目标。可能不止一个。

该板还可能包含以下对象:

  • @:坚固的墙。激光不会穿过这里。
  • \向左倾斜的反射器。根据下表更改激光的方向:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Left
    Right                             Down
    Down                              Right
    Left                              Up
    

    反射器的工作原理应该非常直观。只需将它们想象为实际的两面镜子,并且方向应该清晰。

  • /右倾反射镜。根据下表更改激光的方向:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 123... 9:一个门户。该数字表示门户的通道-同一通道中将恰好有两个门户(例如,不会有三个1)。门户改变位置激光器到同一信道的其他入口的位置。例如:

    >     1     @     1     *
    

    激光会击中目标,因为当激光击中第一个目标时1,它将被传送到1另一侧的第二个目标。激光保持与以前相同的方向。

    传送门不会将激光传送到其他频道的传送门(即1不会将激光传送到)9

您的程序将接收木板的2D表示作为输入。该板将始终为矩形。输出应该是True所有目标都有激光穿过它们,False否则为其他。

以下是一些测试案例:

  1. 输入项

    >....\
    ..*...
    >./../
    ..*...
    

    输出量

    True
    
  2. 输入项

    >..........\
    1........../
    2..........1
    3..........2
    4..........3
    5..........4
    6..........5
    7..........6
    8..........7
    9..........8
    *..........9
    

    输出量

    True
    
  3. 输入项

    >.@............*
    >..@...........*
    >...@..........*
    >....@.........*
    >.....@........*
    >...*..@........
    >.......@......*
    

    输出量

    False
    
  4. 输入项

    ../\.
    >./**
    

    输出量

    False
    
  5. 输入项

    /.......*.......\/3.....
    @..............//\.\....
    *.............2\.1\/\...
    \..............///.....<
    .........*...//\\/.....\
    >.............\.1.///.4.
    4.......*/...\2\/3/\/..^
    

    输出量

    True
    
  6. 输入项

    vvvvvvvvvvvvvvvvv
    \\\\\\\\\\\\\\\\\
    /////////////////
    \\\\\\\\\\\\\\\\\
    /////////////////
    \\\\\\\\\\\\\\\\\
    /////////////////
    *****************
    

    输出(注意最右边的目标)

    False
    

如果右倾斜的反射器(/)将激光束的方向从左(←)向下(↓)改变会更有意义吗?
吱吱作响的ossifrage

@squeamish ossifrage很抱歉,我不明白您的问题。其反射规则在倾颓的反射器表,你认为是不正确的?
苦艾酒

我认为您左右混为一谈
令人讨厌的ossifrage

1
如果激光到达栅格边界会怎样?
DavidG 2014年

2
@DavidG没什么,否则它会反弹回来。(在这种情况下,这些是等效的)。它并不“环绕”如可从实施例6中可以看出
丹尼斯Jaheruddin

Answers:


8

蟒蛇, 310 302 287 278 277 260

我认为,这与现有的Python帖子没有太大的不同,但是有一个或两个值得注意的技巧。 它还处理“非终止”输入,例如1>1 编辑:糟糕!发射器阻挡激光。

def t(b):
 w=len(b[0])+1;B=list('@'*w+'@'.join(b));i=l=len(B);C="<>^v@"
 while i:
    j=l-i;i-=1;d=C.find(B[j]);c='.'
    while c not in C:
     if'+'>c:B[j]='.'
     if'0'<c<C:j=(B*2).index(c,j+1)%l
     elif'.'<c:d^=2+(c<C)
     j-=[1,-1,w,-w,j][d];c=B[j%l]
 return'*'not in B

t 接受字符串列表(输入行)并返回布尔结果。

这是一段很好的代码代码:

在此处输入图片说明

编辑:可怕的gif礼貌的意志。谢谢威尔!


该规范指定“激光不能穿过发射器”。因此1>1将终止。我没有找到不会终止的东西,尽管我没有付出太多努力,并且几乎假设它在我的实现中不会发生。我当然会重新考虑是否有人可以提出。
VisualMelon 2014年

4
@VisualMelon:规则是时间对称的,除了在激光诞生或死亡的地方,这意味着一切都必须终止(因为您始终可以唯一地追溯到其诞生的地点,并且发射器本身也不能参与其中循环)。
米卡2014年

@Micah hehe,感谢您的正确解释,就像我说的那样,我凭直觉去了,也不用担心,谢谢您在盒子里放了另一种工具。
VisualMelon 2014年

是的,我读错了。
2014年

向厄尔致敬!做得非常好。我认为您可以使用.find(d)返回-1(如果未找到)的事实来减少一些字节。如果删除该if-1<d:语句,而是j+=[-1,1,w,-w,-i][d]在while循环的顶部进行操作,则找不到的-1会变成将该数组中的最后一个元素添加到中j,这将使j0 变为已知的@...?
威尔

7

Perl,647岁

这是我第一次尝试代码高尔夫球,但有些尴尬的是我什至没有超过C#分数,但是我认为将整个过程作为一个整体来做会很有趣(或者很有趣,或者只是自虐)。一系列正则表达式替换。(我还认为重新熟悉我的Perl会很有趣,但是最后,我深为后悔没有在Ruby或Python中实现它。)

我没有做很多测试,但是我认为它应该处理所有情况。

网格是通过STDIN输入的。输入中必须至少有一个换行符(即,没有换行符的单行将不起作用)。

%s=(d,'[|+#$vk%ZX]',u,'[|+#$^W%KX]',r,'[-G+#>k%KX]',l,'[-G+#<W%ZX]');%o=(d,'[-.*G/k\\\\Z',u,'[-.*G/W\\\\K',r,'[|.*$\\\\/kK',l,'[|.*$\\\\/ZW');for$d(d,u,r,l){$o{$d}.='123456789qwertyuio]'}%u=(d,'.|-+*$G#/Wk%\KZX',u,'.|-+*$G#/kW%\ZKX',r,'.-|+*G$#/Wk%\ZKX',l,'.-|+*G$#/kW%\KZX');@q=split//,"qwertyuio";local$/;$_=<STDIN>;for$i(1..9){$m{$i}=$q[$i-1];$m{$m{$i}}=$i;s/$i/$m{$i}/e}/.*?\n/;$l='.'x((length$&)-1);do{$c=0;for$d(d,u,r,l){%p=(d,"(?<=$s{d}$l)$o{d}",u,"$o{u}(?=$l$s{u})",r,"(?<=$s{r})$o{r}",l,"$o{l}(?=$s{l})");%h=split//,$u{$d};$c+=s!$p{$d}!$h{$&}||($v=$&,($o{$d}=~s/$v// && $s{$d}=~s/]/$m{$v}]/),$v)!es}}while($c);print/\*/?"False\n":"True\n"

说明:该代码会在激光穿过栅格字符串时迭代更新栅格字符串。-表示水平激光器,|垂直激光,+划线激光器,K一个\用激光反弹的顶部,反射镜k/用激光反弹底部,镜子Z一个\用激光反弹底部反射镜,和W一个/反射镜与激光反弹顶端。%/两面X都是\激光的镜子,而两面都是激光的镜子。(这是区分大小写我想摘字母看起来有点适当的-例如,kK是一些显而易见的选择-但不幸的是效果并没有那么大的帮助。我确实应该将此信息放入表格中,但现在我已经筋疲力尽了。)

以相同的方式处理门户(即,根据可能的输入/输出激光位置为每个数字分配一组额外的字符)将需要144个字符(包括原始的9个),因此,当激光打到“输入”门户时,我将“输出”门户网站字符添加到向正确方向发射激光的字符集中。(这确实需要区分输入和输出门户;qwertyuio为此,我使用了字母。)

有点不符合实际的情况,带有打印语句,因此您可以看到正在发生的替换(每个替换代表激光进行的一个“回合”),并且将g标志添加到了主行中s///,因此不需要太多迭代:

# Throughout, d,u,r,l represents lasers going down, up, left, or right
# `sources` are the character classes representing laser "sources" (i.e. any
# character that can, on the next round, cause a laser to enter the space
# immediately adjacent to it in the proper direction)
%sources=(d,'[|+#$vk%ZX]',u,'[|+#$^W%KX]',r,'[-G+#>k%KX]',l,'[-G+#<W%ZX]');
# `open` characters will not block a laser
%open=(d,'[-.*G/k\\\\Z',u,'[-.*G/W\\\\K',r,'[|.*$\\\\/kK',l,'[|.*$\\\\/ZW');
# One of each portal is changed into the corresponding letter in `qwertyuio`.
# At the start, each portal is 'open' and none of them is a source.
for$d(d,u,r,l){$open{$d}.='123456789qwertyuio]'}
# A mapping of 'open' characters to the characters they become when a laser
# goes through them. (This is used like a hash of hashes; see the assignment
# of `%h` below.)
%update=(d,'.|-+*$G#/Wk%\KZX',
    u,'.|-+*$G#/kW%\ZKX',
    r,'.-|+*G$#/Wk%\ZKX',
    l,'.-|+*G$#/kW%\KZX');
@q=split//,"qwertyuio";
local$/;$_=<STDIN>;
for$i(1..9){
    $m{$i}=$q[$i-1];
    $m{$m{$i}}=$i;
    s/$i/$m{$i}/e}
print "After substituting portals:\n";
print;
print "\n";
# Find the number of characters in each line and create a string of `.`'s,
# which will be used to correlate characters above/below one another in the
# grid with each other.
/.*?\n/;
$l='.'x((length$&)-1);
do{
    $changes=0;
    for$d(d,u,r,l){
        # `patterns` is a mapping from each direction to the regex representing
        # an update that must occur (i.e. a place where a laser must progress).
        # Each pattern is either a lookahead or lookbehind plus the necessary
        # "open" character class.
        %patterns=(d,"(?<=$sources{d}$l)$open{d}",
            u,"$open{u}(?=$l$sources{u})",
            r,"(?<=$sources{r})$open{r}",
            l,"$open{l}(?=$sources{l})");
        %h=split//,$update{$d};
        # Match against the pattern for each direction. Note whether any
        # matches were found.
        $changes+=s!$patterns{$d}!
            # If the "open" character for a map is in the `update` map, return
            # the corresponding value. Otherwise, the "open" character is a
            # portal.
            $h{$&} || ($v=$&,
                        # For portals, remove the input portal from the
                        # proper "open" list and add the output portal to
                        # the proper "source" list.
                       ($open{$d}=~s/$v// && $sources{$d}=~s/]/$m{$v}]/),
                       $v)
                    # This whole substitution should allow `.` to match
                    # newlines (see the definition of `$l` above), and the
                    # replacement must be an expression rather than a string
                    # to facilitate the portal logic. The `g` allows multiple
                    # updates per "frame"; it is left out of the golfed code.
                    !egs
    }
    # Print the next "frame".
    print;
    print "\n";
# Continue updating until no "open" spaces are found.
}while($changes);
# Print whether `*` is still present in the input.
print/\*/?"False\n":"True\n"

我在Python中尝试了这种方法(使用布尔数组而不是正则表达式),但无法达到如此小的效果。我认为这是一种非常发人深省的方法!我的尝试受到catpad.net/michael/apl的错误引导,并带有精美的youtube.com/watch?v=a9xAKttWgP4petercollingridge.co.uk/blog/python-game-of-life-in-one-line

1
@会谢谢!我清楚地意识到,在我研究出进入门户的激光的每种可能组合中使用不同的字符时,我的努力与GoL有多么相似。我想我也许可以剃掉更多的角色,但是……这显然不是最佳方法!
凯尔·斯特兰德

另外,如果有人知道在头几行中的字符类中处理三重转义的“”的更好方法,那将是非常可爱的……
Kyle Strand

6

Python 338351

def t(b):
 L=len;w=L(b[0])+3;b=list("@"*w+"@@".join(b)+"@"*w);w-=1;I=b.index
 for i in range(L(b)):
  c=b[i];d={"^":-w,"<":-1,">":1,"v":w}.get(c)
  if d:
   while c!='@':
    i+=d;c=b[i]
    if c=='*':b[i]='.'
    elif c in '/\\':d={-w:-1,w:1,1:w,-1:-w}[d]*(-1 if c=='/' else 1)
    elif c>'0':i+=I(c)-i or I(c,i+1)-i
 return "*" not in b

我的未缩小版本实际上在板上绘制了激光路径,这很漂亮:

>-+--\
..X..|
>-/--/
..X...

>----------\
1----------/
2----------1
3----------2
4----------3
5----------4
6----------5
7----------6
8----------7
9----------8
X----------9

>-@............*
>--@...........*
>---@..........*
>----@.........*
>-----@........*
>---X--@........
>-------@......*

/-------X+------\/3.....
@........|.....//\+\....
X........|....2\+1\/\...
\--------+----+///+++--<
.........X...//\\/+++--\
>--------+---+\+1+///-4|
4-------X/...\2\/3/\/..^

vvvvvvvvvvvvvvvvv
\\\\\\\\\\\\\\\\\
/////////////////
\\\\\\\\\\\\\\\\\
/////////////////
\\\\\\\\\\\\\\\\\
/////////////////
XXXXXXXXXXXXXXXX*

def debug(board,x,y):
    emit_dir = {
        "^":    ( 0, -1),
        "<":    (-1,  0),
        ">":    ( 1,  0),
        "v":    ( 0,  1),
    }
    class PortalException(Exception): pass
    xdir, ydir = emit_dir[board[y][x]]
    while True:
        # print "step (%d, %d) (%d, %d)" % (x, y, xdir, ydir)
        x += xdir
        y += ydir
        if y < 0 or y >= len(board) or x < 0 or x >= len(board[y]):
            return
        ch = board[y][x]
        if ch == '/':
            xdir, ydir = -ydir, -xdir
        elif ch == '\\':
            xdir, ydir = ydir, xdir
        elif ch in '@^><v':
            return
        elif ch == '*':
            board[y] = board[y][:x] + 'X' + board[y][x+1:]
        elif ch in '.-|':
            ch = ('-' if xdir else '|') if ch == '.' else '+'
            board[y] = board[y][:x] + ch + board[y][x+1:]
        elif ch in '123456789':
            try:
                for r in range(len(board)):
                    for c in range(len(board[r])):
                        if board[r][c] == ch and (r != y or c != x):
                            x, y = c, r
                            raise PortalException()
                raise Exception("could not find portal %s (%d,%d)" % (ch, x, y))
            except PortalException:
                pass

5

C# - 515个 414 400字节

完整的C#程序,没有像Will那样好的输出。通过跟踪每个单独发射的激光路径并保持我们访问过的哪些细胞的阵列来工作,以便我们可以检查是否最后访问了所有恒星。编辑:通过使所有内容变为1D并使用char而不是int来存储当前char来划分大量字节

w0lf提醒我,我的代码中间有一个未充分利用的for循环,所以我认为我最好还是花点力气并付诸实践,现在我可以减少卷曲的绝对最小数量大括号。我不会假装喜欢第二个for循环的崩溃,现在的代码非常混乱,但是节省了一些字节。在此过程中,我重新编写了门户网站处理。我还发现了一种使用嵌套而不是聚合条件操作执行“移动”的较短方法。

高尔夫代码:

using C=System.Console;class P{static void Main(){var S=C.In.ReadToEnd().Replace("\r","");int W=S.IndexOf('\n')+1,l=S.Length,i=l,d,m,n;var M=new int[l];for(char c;i-->0;)for(d="^<v>".IndexOf(c=S[m=i]);c>14&d>-1;d=(m+=d==2?W:d>0?d-2:-W)>=0&m<l&&"@^<v>".IndexOf(c=S[m])<0?d:-1)for(d=c==47?3-d:c==92?d^1:d,M[n=m]=1;c%49<9&&(m=S.IndexOf(c,m+1))==n|m<0;);for(;l-->0;)W*=S[l]==42?M[l]:1;C.WriteLine(W>0);}}

减少打高尔夫球的代码:

using C=System.Console;

class P
{
    static void Main()
    {
        var S=C.In.ReadToEnd().Replace("\r",""); // read the grid, remove pesky carriage returns
        int W=S.IndexOf('\n')+1,l=S.Length,i=l,d,m,n; // find "width"
        var M=new int[l]; // defaults to 0s

        for(char c;i-->0;) // for each cell

            for(d="^<v>".IndexOf(c=S[m=i]); // find initial direction, if any
                c>14&d>-1; // loop only if we have direction
                d=(m+=d==2?W:d>0?d-2:-W) // move (after iteration)
                >=0&m<l&&"@^<v>".IndexOf(c=S[m])<0?d:-1) // terminate if we hit something or go off edge

                for(d=c==47?3-d:c==92?d^1:d, // mirrors
                    M[n=m]=1; // we have seen this spot
                    c%49<9&&(m=S.IndexOf(c,m+1))==n|m<0;); // portals

        for(;l-->0;) // for each cell
            W*=S[l]==42?M[l]:1; // if *, then mul by whether seen

        C.WriteLine(W>0);
    }
}

新的门户网站处理代码利用了String.IndexOf函数愉快地返回-1(即未找到字符)的事实,如果您要求它开始查找字符串后的1个字符(如果您要求它开始任何超出该范围的字符,则会引发异常)。这对我来说是个新闻,但是在这种情况下非常方便。


+1很棒的高尔夫!我只是想到了一个窍门:您可以m+=(d>0?d-2:0)+(d<3?d-1:0)*W;将推入for,然后像这样:for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W)。这样,您将保存一个字符,因为您将丢失分号。
Cristian Lupascu 2014年

@ w0lf做了最后的努力,并设法完全折叠了for循环,这是感谢的推动;)
VisualMelon 2014年
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.