Verifikasi solusi Tower of Hanoi

29

Jika Anda tidak tahu apa itu Menara Hanoi , saya akan jelaskan secara singkat: Ada tiga batang dan beberapa cakram yang masing-masing memiliki ukuran berbeda. Pada awalnya semua disc ada di menara pertama, dalam urutan: Urut terbesar ada di bawah, yang terkecil di atas. Tujuannya adalah untuk membawa semua cakram ke batang ketiga. Kedengarannya mudah? Inilah masalahnya: Anda tidak dapat menempatkan disk di atas disk yang lebih kecil dari disk lain; Anda hanya dapat memegang satu disk di tangan Anda pada satu waktu untuk memindahkannya ke batang lain dan Anda hanya dapat menempatkan disk pada batang, bukan di atas meja, Anda bajingan licik.

solusi contoh ascii:

  A      B      C
  |      |      |      
 _|_     |      |      
__|__    |      |


  A      B      C
  |      |      |      
  |      |      |      
__|__   _|_     |


  A      B      C
  |      |      |      
  |      |      |      
  |     _|_   __|__


  A      B      C
  |      |      |      
  |      |     _|_     
  |      |    __|__      

Tantangan

Ada tiga batang yang disebut A, B dan C. (Anda juga dapat memanggilnya 1,2 dan 3 dengan hormat jika itu membantu) Pada awalnya semua cakram ada pada batang A (1).

Tantangan Anda adalah memverifikasi solusi untuk menara hanoi. Anda harus memastikan bahwa:

  1. Pada akhirnya semua n disc berada di rod C (3).
  2. Untuk setiap disk yang diberikan pada kondisi tertentu tidak ada disk yang lebih kecil di bawahnya.
  3. Tidak ada kesalahan yang jelas seperti mencoba mengambil disk dari batang kosong atau memindahkan disk ke batang yang tidak ada.

(solusinya tidak harus optimal.)

Memasukkan

Program Anda akan menerima dua input:

  1. Jumlah cakram n (bilangan bulat)
  2. Bergerak yang diambil, yang akan terdiri dari satu set tupel dari: (menara untuk mengambil disk paling atas dari saat ini), (menara untuk membawa disk ini ke) di mana masing-masing tupel mengacu pada suatu gerakan. Anda dapat memilih bagaimana mereka diwakili. Misalnya sesuatu seperti cara berikut untuk mewakili solusi untuk n = 2 yang telah saya gambar di ascii di atas. (Saya akan menggunakan yang pertama dalam test case, karena mudah di mata):

    "A-> B; A-> C; B-> C"

    [("A", "B"), ("A", "C"), ("B", "C")]

    [(1,2), (1,3), (2,3)]

    "ABACBC"

    [1,2,1,3,2,3]

Keluaran

  • Sebenarnya, jika kondisi itu dapat ditemukan di bawah "tantangan" terus.

  • Falsy, jika tidak.

Kasus uji:

Benar:

n=1, "A->C"

n=1, "A->B ; B->C"

n=2, "A->B ; A->C ; B->C"

n=2, "A->C ; C->B ; A->C ; B->C"

n=2, "A->C ; A->B ; C->B ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C ; B->C"

Salah:

Yang ketiga disarankan oleh @MartinEnder, 7th oleh @Joffan

n=1, "A->B"

n=1, "C->A"

n=2, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=2, "A->B ; A->C ; C->B"

n=2, "A->C ; A->B ; C->B ; B->A"

n=2, "A->C ; A->C"

n=3, "A->B ; A->D; A->C ; D->C ; A->C"

n=3, "A->C ; A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->B ; B->C ; B->A ; B->C ; A->C"

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; C->B"

n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C"

n=4, "A->B ; A->B ; A->B ; A->C ; B->C ; B->C ; B->C"

Ini adalah kode-golf , solusi terpendek yang menang. Aturan dan celah standar berlaku. Tidak termasuk baterai.

KarlKastor
sumber
Apakah juga oke jika 2 input dapat direpresentasikan dengan menggunakan metode Anda, tetapi menggunakan angka bukan huruf (yaitu A=1, B=2, C=3, dll)?
R. Kap
1
Bolehkah saya nol indeks input?
Rohan Jhunjhunwala
1
Apakah boleh jika kesalahan dilemparkan ketika disk diambil dari batang kosong atau tidak ada?
R. Kap
1
Bisakah kita berasumsi bahwa tidak akan ada gerakan seperti itu A->A?
Martin Ender
2
@ Kobi Anda harus memeriksa moving discs to nonexistant rods.jadi tentu saja ya, iniD
edc65

Jawaban:

7

Retina , 84 80 Bytes

-5 byte berkat Martin Ender

~
 ~$'
$
ABC
{`^(.)(.*)( ~+)\1
$3$2$1
}`^(\W+)(\w)(.*)(?<=\1~+|\w)\2
$3$1$2
^AB 

Cobalah online! (ditambah 5 byte untuk tes baris demi baris)

Kode mensimulasikan permainan penuh.

  • Input diberikan sebagai ACABCBACBABCAC~~~.
    ~~~berarti tiga cakram.
  • Pertama empat baris mengkonversi input ke format permainan: ACABCBACBABCAC ~~~ ~~ ~ABC.
    Pada awalnya batang A memiliki semua 3 cakram, dan batang B dan C kosong.
  • Selanjutnya kita memiliki lingkaran dua langkah:
    • Ambil huruf pertama di baris, yang menunjukkan batang sumber berikutnya. Temukan batang ini, dan ambil cakram terakhir masuk. Keluarkan surat itu dan pindahkan cakram ke stark (ambil).
      Di luar contoh, setelah langkah pertama, teks akan terlihat seperti: ~CABCBACBABCAC ~~~ ~~ABC.
    • Pada tahap kedua kita menemukan batang target, dan memindahkan disk ke sana. Kami memvalidasi batang kosong, atau memiliki disk yang lebih besar di bagian atas: ABCBACBABCAC ~~~ ~~AB ~C.
  • Akhirnya kami mengkonfirmasi batang A dan B kosong - ini berarti semua disk ada di C (ada ruang tambahan di baris terakhir).
Kobi
sumber
Wow, itu mengesankan
Rohan Jhunjhunwala
17

Retina , 167 165 157 150 123 byte

Ini benar-benar tampak seperti tantangan yang harus diselesaikan dengan satu regex ... (meskipun tajuknya berbunyi "Retina", ini hanyalah vanilla .NET regex, yang cocok dengan input yang valid).

^(?=\D*((?=(?<3>1+))1)+)((?=A(?<1-3>.+)|B(?<1-4>.+)|C(?<1-5>.+)).(?=A.*(?!\3)(\1)|B.*(?!\4)(\1)|C.*(?!\5)(\1)).)+(?!\3|\4)1

Format input adalah daftar instruksi formulir AB, diikuti oleh nunary menggunakan digit 1. Tidak ada pemisah. Output 1untuk valid dan 0tidak valid.

Cobalah online! (Dua karakter pertama memungkinkan suite tes yang dipisahkan dengan linefeed.)

Solusi alternatif, jumlah byte yang sama:

^(?=\D*((?=(?<3>1+))1)+)((?=A(?<1-3>.+)|B(?<1-4>.+)|C(?<1-5>.+)).(?=A.*(?!\3)(\1)|B.*(?!\4)(\1)|C.*(?!\5)(\1)).)+(?<-5>1)+$

Ini mungkin dapat dipersingkat dengan menggunakan 1, 11dan 111bukannya A, Bdan Ctapi saya harus memeriksanya nanti. Mungkin juga lebih pendek untuk membagi program menjadi beberapa tahap, tetapi di mana tantangannya? ;)

Penjelasan

Solusi ini banyak menggunakan kelompok penyeimbang .NET. Untuk penjelasan lengkap, lihat posting saya di Stack Overflow , tetapi intinya adalah bahwa menangkap grup di .NET adalah tumpukan, di mana setiap tangkapan baru mendorong substring lain dan di mana juga dimungkinkan untuk muncul dari tumpukan seperti itu lagi. Ini memungkinkan Anda menghitung berbagai jumlah dalam sebuah string. Dalam hal ini memungkinkan kita mengimplementasikan tiga batang secara langsung sebagai tiga kelompok pengambilan yang berbeda di mana setiap disk diwakili oleh suatu tangkapan.

Untuk memindahkan disk di sela-sela batang, kami menggunakan quirk (?<A-B>...)sintaksis yang aneh . Biasanya, ini muncul menangkap dari tumpukan Bdan mendorong ke tumpukan Atali antara penangkapan muncul dan awal kelompok ini. Jadi (?<A>a).(?<B-A>c)dicocokkan abcakan dibiarkan Akosong dan Bdengan b(sebagai lawan dari c). Namun, karena .NET variabel-panjang lookbehinds mungkin untuk menangkap (?<A>...)dan (?<B-A>...)tumpang tindih. Untuk alasan apa pun, jika itu masalahnya, persimpangan dari dua kelompok didorong ke B. Saya telah merinci perilaku ini di "bagian lanjutan" tentang menyeimbangkan grup dalam jawaban ini .

Aktif ke regex. Batang A, Bdan Csesuai dengan kelompok 3, 4dan 5di regex. Mari kita mulai dengan menginisialisasi batang A:

^                 # Ensure that we start at the beginning of the input.
(?=               # Lookahead so that we don't actually move the cursor.
  \D*             # Skip all the instructions by matching non-digit characters.
  (               # For each 1 at the end of the input...
    (?=(?<3>1+))  # ...push the remainder of the string (including that 1)
                  # onto stack 3.
  1)+
)

Jadi mis. Jika input berakhir dengan 111, maka grup 3 / batang Asekarang akan memegang daftar tangkapan [111, 11, 1](yang atas berada di sebelah kanan).

Bit kode selanjutnya memiliki struktur sebagai berikut:

(
  (?=A...|B...|C...).
  (?=A...|B...|C...).
)+

Setiap iterasi dari loop ini memproses satu instruksi. Pergantian pertama menarik cakram dari batang yang diberikan (ke grup sementara), pergantian kedua menempatkan cakram itu ke batang yang diberikan lainnya. Kami akan segera melihat bagaimana ini bekerja dan bagaimana kami memastikan bahwa langkah tersebut valid.

Pertama, mengambil disk dari batang sumber:

(?=
  A(?<1-3>.+)
|
  B(?<1-4>.+)
|
  C(?<1-5>.+)
)

Ini menggunakan perilaku persimpangan-kelompok yang aneh yang telah saya jelaskan di atas. Perhatikan grup itu 3, 4dan 5akan selalu menahan substring 1s pada akhir string yang panjangnya sesuai dengan ukuran disk. Kami sekarang menggunakan (?<1-N>.+)pop disc atas dari stack Ndan mendorong persimpangan substring ini dengan pertandingan .+ke stack 1. Karena .+selalu harus mencakup seluruh tangkapan yang muncul N, kita tahu bahwa ini hanya memindahkan tangkapan.

Selanjutnya, kami menempatkan disk ini dari tumpukan 1ke tumpukan yang sesuai dengan batang kedua:

(?=
  A.*(?!\3)(\1)
|
  B.*(?!\4)(\1)
|
  C.*(?!\5)(\1)
)

Perhatikan bahwa kita tidak perlu membersihkan tumpukan 1, kita bisa meninggalkan disk di sana, karena kita akan meletakkan yang baru di atas sebelum menggunakan tumpukan lagi. Itu berarti kita dapat menghindari (?<A-B>...)sintaks dan cukup menyalin string (\1). Untuk memastikan bahwa langkah tersebut valid, kami menggunakan lookahead negatif (?!\N). Ini memastikan bahwa, dari posisi di mana kami ingin mencocokkan disk saat ini, tidak mungkin untuk mencocokkan disk yang sudah ada di tumpukan N. Ini hanya dapat terjadi jika a) \Ntidak akan pernah cocok karena tumpukan benar-benar kosong atau b) the disc on top of stackN is larger than the one we're trying to match with\ 1`.

Akhirnya, yang tersisa adalah memastikan bahwa a) kami telah mencocokkan semua instruksi dan b) batang Adan Bkosong, sehingga semua disc telah dipindahkan C.

(?!\3|\4)1

Kami cukup memeriksa tidak ada yang cocok \3atau tidak \4(yang hanya merupakan kasus jika keduanya kosong, karena setiap disc yang sebenarnya akan cocok) dan bahwa kami kemudian dapat mencocokkan 1sehingga kami belum menghilangkan instruksi apa pun.

Martin Ender
sumber
14

Java "hanya" 311 272 263 261 260 259 256 byte

Menyimpan 39 byte yang tak terhitung jumlahnya karena @Frozn memperhatikan fitur debug yang lebih lama serta beberapa trik golf yang pintar.

Versi golf

int i(int n,int[]m){int j=0,k=0,i=n;Stack<Integer>t,s[]=new Stack[3];for(;j<3;)s[j++]=new Stack();for(;i-->0;)s[0].push(i);for(;k<m.length;k+=2)if((t=s[m[k+1]]).size()>0&&s[m[k]].peek()>t.peek())return 0;else t.push(s[m[k]].pop());return s[2].size()<n?0:1;}

ungolfed dengan penjelasan dan tumpukan cetak cantik di setiap langkah

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package codegolf;

/**
 *
 * @author rohan
 */
import java.util.Arrays;
import java.util.Stack;
public class CodeGolf {
    //golfed version
    int i(int n,int[]m){int j=0,k=0,i=n;Stack<Integer>[] s=new Stack[3];for(;j<3;j++)s[j]=new Stack();for(;i-->0;)s[0].push(i);for(;k<m.length;System.out.println(Arrays.toString(s)),k+=2)if(!s[m[k+1]].isEmpty()&&s[m[k]].peek()>s[m[k+1]].peek())return 0;else s[m[k+1]].push(s[m[k]].pop());return s[2].size()==n?1:0;}
    /** Ungolfed
        * 0 as falsy 1 as truthy
        * @param n the number of disks
        * @param m represents the zero indexed stacks in the form of [from,to,from,to]
        * @return 0 or 1 if the puzzle got solved, bad moves result in an exception
        */
    int h(int n, int[] m) {
        //declarations
        int j = 0, k = 0, i = n;
        //create the poles
        Stack<Integer>[] s = new Stack[3];
        for (; j < 3; j++) {
            s[j] = new Stack();
        }
        //set up the first tower using the "downto operator
        for (; i-- > 0;) {
            s[0].push(i);
        }
    //go through and perform all the moves
        for (; k < m.length; System.out.println(Arrays.toString(s)), k += 2) {
            if (!s[m[k + 1]].isEmpty() && s[m[k]].peek() > s[m[k + 1]].peek()) {
                return 0;//bad move
            } else {
                s[m[k + 1]].push(s[m[k]].pop());
            }
        }
        return s[2].size() == n ? 1 : 0;// check if all the disks are done
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
    //test case
        System.out.println( new CodeGolf().h(3,new int[]{0,2,0,1,2,1,0,2,1,0,1,2,0,2})==1?"Good!":"Bad!");
    }

}

Versi ungolfed memiliki fitur di mana ia akan mencetak seperti apa tumpukan di setiap langkah seperti ...

[[2, 1], [], [0]]
[[2], [1], [0]]
[[2], [1, 0], []]
[[], [1, 0], [2]]
[[0], [1], [2]]
[[0], [], [2, 1]]
[[], [], [2, 1, 0]]
Good!
Rohan Jhunjhunwala
sumber
Apa yang System.out.println(Arrays.toString(s))harus dilakukan
Frozn
Ini akan cukup mencetak tumpukan. Seperti itu [[2,1,0], [] []]
Rohan Jhunjhunwala
Whoops @Frozn yang merupakan fitur debug menghapus sekarang
Rohan Jhunjhunwala
Aku tahu, hanya bertanya-tanya mengapa itu ada :) Anda juga dapat mengganti &&dengan &.
Frozn
@ Frozn Saya tidak bisa mengganti itu dengan sedih karena saya mengandalkan perilaku hubung singkat untuk menghindari mencoba mengintip tumpukan kosong. Terima kasih atas pengurangan 39 byte
Rohan Jhunjhunwala
9

Python 2, 186 167 158 135 127 115 110 102 byte

n,m=input()
x=[range(n),[],[]]
for a,b in m:p=x[a].pop();e=x[b];e and 1/(p>e[-1]);e+=p,
if x[0]+x[1]:_

Mengambil input pada STDIN dalam format berikut:

(1,[(0,1),(1,2)])

Artinya, sebuah tuple Python dari jumlah cakram dan daftar tupel Python (from_rod,to_rod). Seperti dalam Python, tanda kurung di sekitarnya adalah opsional. Batang nol diindeks.

Sebagai contoh, test case ini:

n=2; "A->B ; A->C ; B->C"

akan diberikan sebagai:

(2,[(0,1),(0,2),(1,2)])

Jika solusinya valid, tidak menghasilkan apa-apa dan keluar dengan kode keluar 0. Jika tidak valid, melempar pengecualian dan keluar dengan kode keluar dari 1. Melemparkan sebuah IndexError jika pindah ke batang yang tidak ada atau mencoba melepaskan disk dari batang yang tidak memiliki cakram di atasnya, ZeroDivisionErrorjika cakram ditempatkan di atas cakram yang lebih kecil, atau NameErrorjika ada cakram yang tersisa di batang pertama atau kedua di ujungnya.

Disimpan 13 byte berkat @KarlKastor!

Disimpan 8 byte berkat @xnor!

Tembaga
sumber
1
Periksa bahwa setiap tumpukan diurutkan tampaknya terlalu rumit. Tidak bisakah Anda memeriksa bahwa disk yang dipindahkan lebih besar dari disk teratas dari tumpukan yang dipindahkan?
xnor
@ xnor Terima kasih, itu seharusnya berhasil. Menambahkannya sekarang.
Tembaga
5

Python 2.7, 173 158 138 130 127 123 byte:

r=range;a,b=input();U=[r(a,0,-1),[],[]]
for K,J in b:U[J]+=[U[K].pop()]if U[J]<[1]or U[K]<U[J]else Y
print U[-1]==r(a,0,-1)

Mengambil input melalui stdin dalam format di (<Number of Discs>,<Moves>)mana <Moves>diberikan sebagai larik berisi tupel yang sesuai dengan setiap gerakan, yang masing-masing berisi sepasang bilangan bulat yang dipisahkan koma. Misalnya, test case:

n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C" 

diberikan dalam pos akan diberikan sebagai:

(3,[(0,2),(0,1),(2,1),(0,2),(1,0),(1,2),(0,2)]) 

ke program saya. Outputs IndexErrorjika kondisi ke-3 tidak terpenuhi, NameErrorkondisi ke-2 tidak terpenuhi, dan Falsejika kondisi ke-1 tidak terpenuhi. Jika tidak, output True.

R. Kap
sumber
dua hal: variabel Ytidak pernah didefinisikan dalam kode Anda (saya pikir itu harus J) dan U[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]lebih pendek oleh 3 karakter yangstmt1 if cond else stmt2
jermenkoo
@ jermenkoo Yah, saya menggunakan Yvariabel seperti itu adalah untuk menaikkan NameErrorsetiap kali kondisi ke-2 tidak terpenuhi. Jika saya harus mengubah Yke J, maka NameErrortidak akan dibangkitkan. Untuk alasan ini, saya juga tidak dapat melakukannya U[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]karena ini akan meningkatkan NameError waktu , bukan hanya ketika kondisi ke-2 tidak terpenuhi.
R. Kap
baiklah, terima kasih atas penjelasannya!
jermenkoo
5

VBA, 234 217 213 196 byte

Function H(N,S)
ReDim A(N)
While P<Len(S)
P=P+2:F=1*Mid(S,P-1,1):T=1*Mid(S,P,1)
E=E+(T>2):L=L+T-F
For i=1 To N
If A(i)=F Then A(i)=T:Exit For
E=E+(A(i)=T)+(i=N)
Next
Wend
H=L+9*E=2*N
End Function

Format input untuk bergerak adalah string dengan angka genap (012). Doa ada dalam spreadsheet, = H ([jumlah disk], [pindahkan string])

Array A memegang posisi batang berbagai disk. Sebuah langkah hanya memperbarui kemunculan pertama dari nomor batang "Dari" ke nomor batang "Ke". Jika Anda menjumpai "ke" disk batang pertama, atau tidak ada "dari" disk batang, itu adalah langkah yang tidak valid. "Nilai batang" total A disimpan dalam L, yang harus berakhir pada 2N. Kesalahan diakumulasikan sebagai penghitungan negatif di E.

Secara umum dengan solusi lain, "memindahkan" disk dari menara ke menara yang sama tidak dilarang. Saya bisa melarangnya selama 6 byte lagi.

Hasil

Hasil fungsi di kolom pertama (n = 3 kasus terakhir adalah tambahan saya menggunakan batang tambahan).

TRUE    1   02
TRUE    1   0112
TRUE    2   010212
TRUE    2   02210212
TRUE    2   020121101202
TRUE    3   02012102101202
TRUE    4   010212012021010212102012010212

FALSE   1   01
FALSE   1   20
FALSE   2   02012102101202
FALSE   2   010221
FALSE   2   02012110
FALSE   2   0202
FALSE   3   0202012102101202
FALSE   3   0201210112101202
FALSE   3   02012102101221
FALSE   3   0103023212
FALSE   4   0102120120210102121020120102
FALSE   4   01010102121212
Joffan
sumber
2

php, 141 byte

<?php $a=$argv;for($t=[$f=range($a[++$i],1),[],[]];($r=array_pop($t[$a[++$i]]))&&$r<(end($t[$a[++$i]])?:$r+1);)$t[$a[$i]][]=$r;echo$t[2]==$f;

Script baris perintah, mengambil input sebagai tinggi kemudian serangkaian indeks array (0 diindeks) misalnya 1 0 2 atau 2 0 1 0 2 1 2 untuk 1 atau 2 kasus uji terpendek ketinggian.
Gema 1 pada kasus yang benar dan tidak ada yang salah.
Memberi 2 pemberitahuan dan 1 peringatan sehingga perlu dijalankan di lingkungan yang membungkamnya.

pengguna55641
sumber
1

JavaScript (ES6), 108

n=>s=>!s.some(([x,y])=>s[y][s[y].push(v=s[x].pop())-2]<v|!v,s=[[...Array(s=n)].map(_=>s--),[],[]])&s[2][n-1]

Format input: berfungsi dengan 2 argumen

  • arg 1, numerik, jumlah dering
  • arg 2, array string, masing-masing string 2 karakter '0', '1', '2'

Output: mengembalikan 1 jika ok, 0 jika tidak valid, kecuali jika tidak ada batang

Kurang bermain golf dan menjelaskan

n=>a=>(
  // rods status, rod 0 full with an array n..1, rod 1 & 2 empty arrays
  s = [ [...Array(t=n)].map(_=>t--), [], [] ],
  // for each step in solution, evaluate function and stop if returns true
  err = a.some( ([x,y]) => {
    v = s[x].pop(); // pull disc from source rod
    // exception is s[x] is not defined
    if (!v) return 1; // error source rod is empty
    l = s[y].push(v); // push disc on dest rod, get number of discs in l
    // exception is s[y] is not defined
    if(s[y][l-2] < v) return 1; // error if undelying disc is smaller
  }),
  err ? 0 // return 0 if invalid move
  : s[2][n-1]; // il all moves valid, ok if the rod 2 has all the discs
)

Catatan Tes : baris pertama dari fungsi Tes diperlukan untuk mengonversi format input yang diberikan dalam pertanyaan menjadi input yang diharapkan oleh fungsi saya

F=
n=>s=>!s.some(([x,y])=>s[y][s[y].push(v=s[x].pop())-2]<v|!v,s=[[...Array(s=n)].map(_=>s--),[],[]])&s[2][n-1]

Out=x=>O.textContent+=x+'\n'

Test=s=>s.split`\n`.map(r=>[+(r=r.match(/\d+|.->./g)).shift(),r.map(x=>(parseInt(x[0],36)-10)+''+(parseInt(x[3],36)-10))])
.forEach(([n,s],i)=>{
  var r
  try {
    r = F(+n)(s);
  } 
  catch (e) {
    r = 'Error invalid rod';
  }
  Out(++i+' n:'+n+' '+s+' -> '+r)
})

Out('OK')
Test(`n=1, "A->C"
n=1, "A->B ; B->C"
n=2, "A->B ; A->C ; B->C"
n=2, "A->C ; C->B ; A->C ; B->C"
n=2, "A->C ; A->B ; C->B ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C ; B->C"`)

Out('\nFail')
Test( `n=1, "A->B"
n=1, "C->A"
n=2, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=2, "A->B ; A->C ; C->B"
n=2, "A->C ; A->B ; C->B ; B->A"
n=2, "A->C ; A->C"
n=3, "A->B ; A->D; A->C ; D->C ; A->C"
n=3, "A->C ; A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->B ; B->C ; B->A ; B->C ; A->C"
n=3, "A->C ; A->B ; C->B ; A->C ; B->A ; B->C ; C->B"
n=4, "A->B ; A->C ; B->C ; A->B ; C->A ; C->B ; A->B ; A->C ; B->C ; B->A ; C->A ; B->C ; A->B ; A->C"
n=4, "A->B ; A->B ; A->B ; A->C ; B->C ; B->C ; B->C"`)
<pre id=O></pre>

edc65
sumber