做一个蛇解析器!


14

蛇看起来像这样:

      >>>v
@     ^  v
^  >>>^  v
^        v
^<<<<<<<<<

在这种情况下,蛇可以越过自身:

 @
 ^
>^>v
 ^<<

为了使交叉有效,两侧的字符必须沿相同方向移动。的情况下

 @
>^v
 ^<

可以认为不清楚和无效。

输出是WASD代表从头到尾(@)的字符串。

给定一条不会回溯且不模糊的蛇,您是否可以编写一个程序来输出蛇执行的一系列动作?

这是代码高尔夫球,所以最短的答案会成功!

测试用例:

(注意:@可以用以外的任何字符替换v^<>

输入:

>>>>v
    v
  v<<  @
  v    ^
  >>>>>^

输出: ddddssaassdddddww


输入:

@>>v
^  v
^  v
^<<<

输出: dddsssaaawww


输入:

>>>v
   v       @
   v       ^
   >>>>v   ^
       >>>>^

输出: dddsssddddsddddwww


输入:

@<< v
  ^ v
v<^<<
v ^
>>^

输出: ssaaaassddwwwwaa


输入:

@v<v
^v^v
^v^<
^<

输出: ssawwasssawww


1
输入必须是单个String还是可以接受String []?输入的每一行填充的长度都一样吗?还是必须处理不规则的行长?
CAD97

2
这给了我可怕的回忆,回到了关于魔方问题的蚂蚁的路径。
马特

起始段将始终位于第0行,即char 0,还是我们必须找到它?
市长蒙蒂

1
@SpeedyNinja测试用例2和4都没有以(0,0)开始,而测试用例0(蛇形)并没有以(0,0)开始或结束。
CAD97

1
@ CAD97哦,这很值得;)
市长Monty

Answers:


7

Java中,626个 539 536 529字节

-87字节通过在很多地方保存一些字节。感谢公共先生指出一些建议。

-3个字节,因为我无法设法先删除所有空格(感谢mbomb007)

+8个字节可解决这种情况:

@v<v
^v^v
^v^<
^<

-15个字节(通过前加载变量声明)

s->{String o="",t;String[]p=s.split("\n");int h=p.length,w=p[0].length(),y=0,x,b=0,a,n,m;char[][]d=new char[h][w];for(;y<h;y++)for(x=0;x<w;x++){d[y][x]=p[y].charAt(x);if(d[y][x]=='@')d[y][x]=' ';}for(;b<h;b++)for(a=0;a<w;a++){t="";x=a;y=b;n=0;m=0;while(!(y<0|y>h|x<0|x>w||d[y][x]==' ')){if(y+m>=0&y+m<h&x+n>=0&x+n<w&&d[y+m][x+n]==d[y-m][x-n])d[y][x]=d[y-m][x-n];n=m=0;switch(d[y][x]){case'^':t+="W";m--;break;case'<':t+="A";n--;break;case'v':t+="S";m++;break;case'>':t+="D";n++;}x+=n;y+=m;}o=t.length()>o.length()?t:o;}return o;}

可读版本:

static Function<String,String> parser = snake -> {
    // declare all variables in one place to minimize declaration overhead
    String output = "", path;
    String[] split = snake.split("\n");
    int h=split.length, w=split[0].length(), y=0, x, startY=0, startX, dx, dy;
    char[][] board = new char[h][w];
    // setup char[][] board
    for (; y<h; y++)
        for (x=0; x<w; x++) {
            board[y][x]=split[y].charAt(x);
            if(board[y][x]=='@')board[y][x]=' ';
        }
    // find the longest possible path
    for (; startY<h; startY++)
        for (startX=0; startX<w; startX++) {
            path = "";
            x=startX; y=startY; dx=0; dy=0;
            while (!(y<0 | y>h | x<0 | x>w || board[y][x] == ' ')) {
                if (y + dy >= 0 & y + dy < h & x + dx >= 0 & x + dx < w
                        && board[y + dy][x + dx] == board[y - dy][x - dx]) {
                    board[y][x] = board[y - dy][x - dx];
                } dx = dy = 0;
                switch(board[y][x]) {
                    case '^':path+="W";dy--;break;
                    case '<':path+="A";dx--;break;
                    case 'v':path+="S";dy++;break;
                    case '>':path+="D";dx++;break;
                }
                x+=dx; y+=dy;
            }
            output = path.length()>output.length()?path:output;
        }
    return output;
};

接受一个类似的字符串v @\n>>>^。创建一个从每个坐标开始的路径,然后返回最长的路径。重叠路径所需的超前是最困难的部分。


2
我印象深刻。我没想到有人会尝试这样做。而你是第一个。+1。(2016字节是可以的,对于2016:D甚至更好)

删除所有空格,名称等,然后+1。在正确打高尔夫球之前,我不会投票。
mbomb007 '16

2
或者,有两个代码段,其中一个是完整版本,一个是可读的示例。
公众先生

@ mbomb007我完成了逻辑高尔夫,所以这里是正确的高尔夫版本!
CAD97

2
@ CAD97对于这个挑战,我想说这是Java的绝佳高尔夫。
公众先生

1

红宝石217

->a{r=''
z=a.index ?@
a.tr!('<^>v',b='awds').scan(/\w/){c=0
e,n=[a[z,c+=1][?\n]?p: c,d=c*a[/.*
/].size,a[z-c,c][?\n]?p: -c,-d].zip(b.chars).reject{|i,k|!i||a[v=i+z]!=k||0>v}.max_by{|q|q&[a[z]]}until n
z+=e
r=n*c+r}
r}

这是从开始@并向后走,寻找指向当前位置(z)的邻居。为了在4路交叉路口选择正确的路,它偏向于指向同一方向的邻居(max_by{...})。如果未找到直接邻居,则假定必须存在交叉并且一次到达一个级别,直到找到一个(until nc+=1)。对身体部分(不包括头部)(.scan(/\w/){...})重复此过程。

我添加到谜题中的测试用例不断使我绊倒,所以我从182个字符变成了218个字符。那些多余的字符都确保了我的水平移动不会进入下一行/上一行。我想知道我是否可以更好地解决这一问题。

取消高尔夫:

f=->a{
  result=''
  position=a.index ?@ # start at the @
  a.tr!('<^>v',b='awds') # translate arrows to letters
  a.scan(/\w/){           # for each letter found...
    search_distance=0
    until distance
      search_distance+=1
      neighbors = [
        a[position,search_distance][?\n]?p: search_distance,  # look right by search_distance unless there's a newline
        width=search_distance*a[/.*\n/].size,   # look down (+width)
        a[position-search_distance,search_distance][?\n]?p: -search_distance, # look left unless there's a newline
        -width                  # look up (-width)
      ]
      distance,letter = neighbors.zip(b.chars).reject{ |distance, letter_to_find|
        !distance || # eliminate nulls
         a[new_position=distance+position]!=letter_to_find || # only look for the letter that "points" at me
         0>new_position # and make sure we're not going into negative indices
       }.max_by{ |q| 
        # if there are two valid neighbors, we're at a 4-way intersection
        # this will make sure we prefer the neighbor who points in the same 
        # direction we're pointing in.  E.g., when position is in the middle of 
        # the below, the non-rejected array includes both the top and left.
        #   v
        #  >>>
        #   v
        # We want to prefer left.
        q & [a[position]] 
        # ['>',x] & ['>'] == ['>']
        # ['v',x] & ['>'] == []
        # ['>'] > [], so we select '>'.
       }
    end
    position+=distance
    result=(letter*search_distance)+result # prepend result
  }
  result # if anyone has a better way of returning result, I'm all ears
}

您应该能够在某种程度上简化逻辑,因为您添加的案例已超出预期范围。
CAD97
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.