Buat Parser Ular!

14

Ular terlihat seperti ini:

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

Ular dapat menyeberang dengan sendirinya seperti dalam kasus ini:

 @
 ^
>^>v
 ^<<

Agar crossover valid, karakter di kedua sisi harus bergerak ke arah yang sama. Kasus

 @
>^v
 ^<

dapat dianggap tidak jelas dan tidak valid.

Outputnya adalah string yang WASDmewakili pergi dari kepala ke ekor ( @).

Mengingat ular yang tidak mundur dan tidak ambigu, dapatkah Anda menulis sebuah program yang akan menghasilkan serangkaian gerakan yang dilakukan ular?

Ini kode-golf, jadi jawaban tersingkat menang!

Kasus uji:

(Catatan: @Dapat diganti dengan karakter apa pun yang tidak ada di dalam v^<>)

Memasukkan:

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

Keluaran: ddddssaassdddddww


Memasukkan:

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

Keluaran: dddsssaaawww


Memasukkan:

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

Keluaran: dddsssddddsddddwww


Memasukkan:

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

Keluaran: ssaaaassddwwwwaa


Memasukkan:

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

Keluaran: ssawwasssawww

CAD97
sumber
1
Apakah input harus berupa String tunggal atau dapatkah kita mengambil String []? Apakah setiap baris dari input yang diisi memiliki panjang yang sama atau kita harus berurusan dengan panjang jalur yang tidak teratur?
CAD97
2
Ini memberi saya kilas balik mengerikan ke jalan Semut pada pertanyaan kubus rubiks.
Matt
Akankah segmen awal selalu di baris 0, char 0, atau haruskah kita menemukannya?
MayorMonty
1
@SpeedyNinja test case 2 dan 4 keduanya dimulai tidak pada (0,0), dan test case 0 (seperti ular) tidak mulai ATAU berakhir pada (0,0).
CAD97
1
@ CAD97 Oh, itu bahasa Inggris;)
MayorMonty

Jawaban:

7

Java, 626 539 536 529 byte

-87 byte dengan menyimpan beberapa di banyak tempat. Terima kasih kepada Tuan Umum untuk menunjukkan beberapa.

-3 byte karena saya tidak dapat menghapus semua ruang terlebih dahulu coba (terima kasih mbomb007)

+8 byte untuk diperbaiki untuk kasus ini:

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

-15 byte oleh deklarasi variabel front-loading

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

Versi yang dapat dibaca:

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

Mengambil String seperti v @\n>>>^. Buat jalur mulai dari setiap koordinat, lalu kembalikan yang terpanjang. Kepala pencarian yang diperlukan untuk jalur yang tumpang tindih adalah bagian tersulit.

CAD97
sumber
2
Saya sangat terkesan. Saya tidak berharap ada orang yang mencoba ini. Dan kamu yang pertama. +1. (2016 byte tidak apa-apa, dan bahkan lebih baik untuk 2016: D)
Keluarkan semua spasi, nama, dll, maka saya akan memberi +1. Saya tidak memberikan suara sampai itu golf dengan benar.
mbomb007
2
Atau, miliki dua cuplikan kode, salah satu versi yang sepenuhnya golf, salah satu contoh yang bisa dibaca.
Tn. Public
@ mbomb007 Saya menyelesaikan golf logika jadi inilah versi golf yang benar!
CAD97
2
@ CAD97 Untuk tantangan ini, saya akan mengatakan ini adalah golf yang sangat baik di Jawa.
Tuan Umum
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}

Ini dimulai pada @dan berjalan mundur, mencari tetangga yang menunjuk ke posisi saat ini ( z). Untuk memilih jalan yang benar di persimpangan 4 arah, ada baiknya tetangganya menunjuk ke arah yang sama ( max_by{...}). Jika tidak ada tetangga terdekat yang ditemukan, itu mengasumsikan bahwa pasti ada persimpangan dan menjangkau satu tingkat pada satu waktu sampai menemukan satu ( until ndan c+=1). Proses ini berulang untuk jumlah segmen tubuh (tidak termasuk kepala) ( .scan(/\w/){...}).

Kasing uji coba yang saya tambahkan ke puzzle terus membuat saya tersandung, jadi saya beralih dari 182 char ke 218. Semua karakter tambahan itu memastikan pergerakan horizontal saya tidak masuk ke baris berikutnya. Saya ingin tahu apakah saya bisa mengatasinya dengan cara yang lebih baik.

Tidak Disatukan:

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
}
Bukan itu Charles
sumber
Anda harus dapat menyederhanakan logika Anda sedikit karena case tambahan Anda telah dianggap keluar dari ruang lingkup yang dimaksud.
CAD97