Làm một Parser rắn!


14

Rắn trông như thế này:

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

Con rắn có thể vượt qua chính nó như trong trường hợp này:

 @
 ^
>^>v
 ^<<

Để một giao thoa có hiệu lực, các ký tự ở hai bên phải di chuyển cùng hướng. Trường hợp của

 @
>^v
 ^<

có thể được coi là không rõ ràng và không hợp lệ.

Đầu ra là một chuỗi WASDbiểu diễn đi từ đầu đến đuôi ( @).

Đưa ra một con rắn không quay lại và không mơ hồ, bạn có thể viết một chương trình sẽ tạo ra chuỗi di chuyển mà con rắn thực hiện không?

Đây là môn đánh gôn, vì vậy câu trả lời ngắn nhất sẽ thắng!

Các trường hợp thử nghiệm:

(Lưu ý: Có @thể thay thế bằng bất kỳ ký tự nào không có trong v^<>)

Đầu vào:

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

Đầu ra: ddddssaassdddddww


Đầu vào:

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

Đầu ra: dddsssaaawww


Đầu vào:

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

Đầu ra: dddsssddddsddddwww


Đầu vào:

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

Đầu ra: ssaaaassddwwwwaa


Đầu vào:

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

Đầu ra: ssawwasssawww


1
Đầu vào phải là một Chuỗi hay chúng ta có thể lấy Chuỗi [] không? Là mỗi dòng của phần đệm đầu vào có cùng độ dài hay chúng ta phải xử lý độ dài dòng không đều?
CAD97

2
Điều này mang lại cho tôi ánh sáng kinh khủng quay trở lại con đường của một con Kiến trong câu hỏi khối rubiks.
Matt

Đoạn đầu sẽ luôn nằm trên dòng 0, char 0, hay chúng ta sẽ phải tìm nó?
MayorMonty 18/03/2016

1
Cả hai trường hợp kiểm tra @SpeedyNinja đều bắt đầu không ở (0,0) và trường hợp kiểm tra 0 (giống như rắn) không bắt đầu HOẶC kết thúc tại (0,0).
CAD97

1
@ CAD97 Ồ, đó là devlish;)
MayorMonty 18/03/2016

Câu trả lời:


7

Java, 626 539 536 529 byte

-87 byte bằng cách lưu một vài ở rất nhiều nơi. Cảm ơn ông Mr đã chỉ ra một số.

-3 byte vì tôi không thể quản lý để xóa tất cả các khoảng trắng trước tiên (cảm ơn mbomb007)

+8 byte để sửa cho trường hợp này:

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

-15 byte bằng cách khai báo biến trước tải

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;}

Phiên bản dễ đọc:

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;
};

Có một chuỗi như v @\n>>>^. Tạo một đường dẫn bắt đầu tại mỗi tọa độ, sau đó trả về đường dẫn dài nhất. Cái nhìn cần thiết cho các đường dẫn chồng chéo là phần khó nhất.


2
Tôi rất ấn tượng. Tôi đã không mong đợi bất cứ ai thậm chí sẽ cố gắng này. Và bạn là người đầu tiên. +1. (2016 byte là ổn, và thậm chí tốt hơn cho năm 2016: D)

Tách tất cả các khoảng trắng, tên, vv sau đó tôi sẽ +1. Tôi không bỏ phiếu cho đến khi nó chơi golf đúng cách.
mbomb007

2
Hoặc, có hai đoạn mã, một trong những phiên bản được đánh gôn hoàn toàn, một trong những ví dụ có thể đọc được.
Ông công

@ mbomb007 Tôi đã hoàn thành việc chơi golf logic nên đây là phiên bản chơi golf đúng cách!
CAD97

2
@ CAD97 Đối với thử thách này, tôi muốn nói rằng đây là một môn golf xuất sắc trong Java.
Mr Public

1

Ruby, 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}

Điều này bắt đầu tại @và đi về phía sau, tìm kiếm hàng xóm chỉ đến vị trí hiện tại ( z). Để chọn đúng đường tại ngã tư 4 chiều, nó ưu tiên hàng xóm chỉ theo cùng một hướng ( max_by{...}). Nếu không có hàng xóm ngay lập tức được tìm thấy, nó giả định rằng phải có sự giao thoa và đạt đến một cấp độ tại một thời điểm cho đến khi tìm thấy một ( until nc+=1). Quá trình này lặp lại cho số lượng các phân đoạn cơ thể (không bao gồm đầu) ( .scan(/\w/){...}).

Trường hợp thử nghiệm mà tôi đã thêm vào câu đố khiến tôi vấp ngã, vì vậy tôi đã chuyển từ 182 char sang 218. Những nhân vật phụ đó đều đảm bảo rằng các bước di chuyển ngang của tôi không đi vào các dòng tiếp theo / trước. Tôi tự hỏi nếu tôi có thể đối phó với điều đó một cách tốt hơn.

Ung dung:

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
}

Bạn sẽ có thể đơn giản hóa phần nào logic của mình vì trường hợp đã thêm của bạn đã được coi là nằm ngoài phạm vi dự định.
CAD97
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.