Checkers Cina merupakan gerakan terpanjang

12

Dalam Chinese Checkers , sepotong dapat bergerak dengan melompati bagian lain, atau dengan membuat urutan hop tersebut. Tugas Anda adalah menemukan urutan hop yang terpanjang.

Memasukkan

Urutan 121 nol atau satu, masing-masing mewakili tempat di papan tulis. Nol berarti tempat itu kosong; satu berarti tempat itu ditempati. Posisi terdaftar dari kiri ke kanan; atas ke bawah. Misalnya, input dari pengaturan ini adalah

1011110011000001000000000000000000000000100000000001000000000000000000000000000001000000000000000000000001000001100111111

Penjelasan:

Tempat paling atas ditempati oleh potongan hijau, jadi digit pertama dalam input adalah 1. Baris kedua memiliki satu posisi kosong dan satu posisi terisi, jadi 01datang berikutnya. Baris ketiga sudah terisi, jadi 111. Baris keempat memiliki dua ruang kosong dan dua yang ditempati (dari kiri ke kanan), jadi 0011. Kemudian muncul lima 0, a 1, dan tujuh 0untuk baris berikutnya, dan seterusnya.

Seperti dalam pengaturan itu, ada sudut yang menunjuk lurus ke atas. Mungkin ada sejumlah potongan di papan tulis (dari 1 hingga 121). Perhatikan bahwa potongan warna yang berbeda tidak terwakili secara berbeda.

Keluaran

Panjang maksimum lompatan legal, menggunakan bagian apa pun di papan tulis. Anda tidak boleh mengunjungi tempat yang sama lebih dari satu kali (termasuk posisi awal dan akhir). Namun, Anda dapat melompati bagian yang sama lebih dari satu kali. Jika tidak ada hop hukum, output 0. Jangan mempertimbangkan apakah ada langkah hukum non-hop.

Misalnya, output ke pengaturan yang dijelaskan di atas adalah 3.

Input dan output dapat dilakukan melalui stdin dan stdout, melalui argumen baris perintah, melalui pemanggilan fungsi, atau metode serupa lainnya.

Uji Kasus

Memasukkan:

0100000010000000000000000100000000000000000000000000000001010010000000000000000000000101000000000000000000100000000100001

Output: 0(tidak ada dua bagian yang bersebelahan)


Memasukkan:

0000000000111100000000011100000000011000000000100000000000000000000000000000000000000000000000000000000000000000000000000

Output: 1(pengaturan awal untuk satu pemain di sudut kiri atas)

Ypnypn
sumber
Saya memainkan ini dengan bibi saya yang hebat; kami berdua cukup baik. Ini tantangan yang menarik.
cjfaure
1
Mungkin Anda harus menentukan lebih lanjut tentang bagaimana input disimpan / bit mana yang menuju ke mana.
TheDoctor
Potongan mana yang bisa Anda "lompati"? Cara ibu saya dan saya dulu bermain, Anda bisa melompati setiap bagian di salah satu dari 6 arah jarak jauh (ke tempat yang berlawanan dari bagian yang Anda lompati) selama tidak ada bagian di jalan jalan untuk hop itu. Yang lain bermain bahwa Anda hanya bisa melompati potongan yang berdekatan.
Joe Z.
1
@TheDoctor Saya menambahkan penjelasan yang lebih rinci.
Ypnypn
Bisakah Anda mengklarifikasi detail: apakah saya boleh menempati posisi yang sama dua kali? Saya berasumsi bahwa saya tidak dapat melakukan loop tanpa batas, tetapi jika saya dapat mengenai lokasi yang bergerak kiri-kanan dan kemudian tekan lagi bergerak ke atas-kiri ke bawah-kanan maka membuka kemungkinan.
Devon Parsons

Jawaban:

1

Perl, 345 322

Sunting: golf, sedikit.

Lebih banyak test case akan menyenangkan, tetapi untuk saat ini sepertinya berfungsi. Saya akan menambahkan komentar nanti jika perlu. Dengan baris baru dan lekukan agar mudah dibaca:

$_=<>;
$s=2x185;
substr$s,(4,22,unpack'C5(A3)*','(:H[n129148166184202220243262281300')[$i++],0,$_ 
    for unpack A.join A,1..4,13,12,11,10,9..13,4,3,2,1;
$_=$s;
sub f{
    my(@a,%h)=@_;
    $h{$_}++&&return for@a;
    $-+=$#a>$-;
    $s=~/^.{$a[0]}$_/&&f($+[1],@a)
        for map{("(?=.{$_}1.{$_}(0))","(?<=(0).{$_}1.{$_}.)")}0,17,18
}
f$+[0]while/1/g;
print$-
pengguna2846289
sumber
Saya menambahkan beberapa test case.
Ypnypn
Itu bekerja OK, tapi terlalu mudah :-).
user2846289
2

C, 262 260

Kode golf ( kode debug dan spasi kosong yang tidak perlu dihapus. Berubah dari input melalui stdin ke input melalui baris perintah, dan memanfaatkan peluang untuk mendeklarasikan variabel di sana. Edit terbaru: kode dipindahkan ke dalam kurung forloop untuk menyimpan dua titik koma.)

t[420],j,l,x,y;f(p,d){int z,q,k;for(k=6;k--;t[q]&!t[p+z]?t[q]=0,f(q,d+1),t[q]=1:0)z="AST?-,"[k]-64,q=p+z*2;l=d>l?d:l;}main(int i,char**s){for(i=840;i--;x>3&y>5&x+y<23|x<13&y<15&x+y>13?i>420?t[i-420]=49-s[1][j++]:t[i]||f(i,0):0)x=i%20,y=i/20%21;printf("%d",l);}

Penjelasan

Ini bergantung pada papan 20x21 yang terlihat seperti ini, awalnya diisi dengan nol ketika program dimulai (seni ASCII ini dihasilkan oleh versi program yang dimodifikasi, dan ketika iloop menghitung ke bawah, nol ada di sudut kanan bawah):

....................
....................
...............#....
..............##....
.............###....
............####....
.......#############
.......############.
.......###########..
.......##########...
.......#########....
......##########....
.....###########....
....############....
...#############....
.......####.........
.......###..........
.......##...........
.......#............
....................
....................

Loop idijalankan melalui papan ini dua kali, menggunakan x dan y untuk menghitung apakah kotak benar-benar milik kotak-kotak atau tidak (ini membutuhkan 6 ketidaksetaraan terpisah dalam x dan y.)

Jika ya, putaran pertama mengisi kotak, menempatkan 0(falsy) untuk 1(diduduki) dan 1(kebenaran) untuk 0(tidak dihuni). Pembalikan ini penting, karena semua kotak di luar batas sudah mengandung 0, yang berarti mereka menyerupai kotak yang diduduki dan jelas mereka tidak dapat dilompati, tanpa perlu pemeriksaan khusus.

Putaran waktu kedua, jika kuadrat ditempati (berisi 0) itu memanggil fungsi fyang mencari bergerak.

fmencari secara rekursif dalam 6 arah yang mungkin dikodekan oleh +/- 1 (horizontal), +/- 20 (vertikal) dan +/- 19 (diagonal) yang dikodekan dalam ekspresi "AST?-,"[k]-64. Ketika menemukan hit, itu mengatur sel itu ke 0 (ditempati) sebelum memanggil dirinya secara rekursif, lalu set kembali ke 1 (kosong) ketika fungsi dikembalikan. Nilai sel harus diubah sebelum panggilan rekursif untuk mencegah melompat ke sel itu lebih dari sekali.

Kode tidak dikunci

char s[999];                           //input string.
t[420],i,j,l,x,y;                      //t=board. i=board counter, j=input counter. l=length of longest hop found so far.

f(p,d){                                //p=position, d= recursion depth.
  //printf("%d,%d ",p,d);              //debug code: uncomment to show the nodes visited.
  int k,z,q;                           //k=counter,z=displacement,q=destination
  for(k=6;k--;)                        //for each direction
    z="AST?-,"[k]-64,                  //z=direction
    q=p+z*2,                           //q=destination cell
    t[q]&!t[p+z]?                      //if destination cell is empty (and not out of bounds) and intervening cell is full
      t[q]=0,f(q,d+1),t[q]=1           //mark destination cell as full, recurse, then mark it as empty again.
      :0;
  l=d>l?d:l;                           //if d exceeds the max recorded recursion depth, update l
}

main(){
  gets(s);                             //get input
  for(i=840;i--;)                      //cycle twice through t
    x=i%20,                            //get x
    y=i/20%21,                         //and y coordinates
    x>3&y>5&x+y<23|x<13&y<15&x+y>13?   //if they are in the bounds of the board
      i>420?
        t[i-420]=49-s[j++]             //first time through the array put 0 for a 1 and a 1 for a 0 ('1'=ASCII49)
        :t[i]||f(i,0)                  //second time, if t[i]=0,call f(). 
       //,puts("")                     //puts() formats debug output to 1 line per in-bounds cell of the board
      :0;
  printf("%d",l);                      //print output
}
Level River St
sumber