Bir Hanoi Kulesi çözümünü doğrulayın


29

Hanoi Kulesi'nin ne olduğunu bilmiyorsanız , kısaca açıklayacağım: Her biri farklı boyutta olan üç çubuk ve bazı diskler var. Başlangıçta, tüm diskler ilk sırada, sıralı sıradadır: En büyüğü en alttaki, en küçüğü en üsttedir. Amaç tüm diskleri üçüncü çubuğa getirmektir. Kolay mı geliyor? İşte catch: Diski diğer diskten daha küçük olan bir diskin üzerine yerleştiremezsiniz; Bir seferde sadece bir diski elinizde tutabilirsiniz, başka bir çubuğa hareket ettirin ve diski yalnızca çubukların üzerine yerleştirebilirsiniz, masaya değil sinsi piç.

ascii örnek çözümü:

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


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


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


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

Meydan okuma

A, B ve C diye adlandırılan üç çubuk var. (Eğer yardımcı olursa buna sırasıyla sırasıyla 1,2 ve 3 de diyebilirsiniz) Başlangıçta tüm n diskler A çubuğundadır (1).

Buradaki zorluk, hanoi kulesi için bir çözüm bulmak. Şunlardan emin olmanız gerekir:

  1. Sonunda, tüm n diskler C çubuğundadır (3).
  2. Belirli bir durumda verilen herhangi bir disk için, altında daha küçük bir disk yoktur.
  3. Diskleri boş bir çubuktan almaya çalışmak veya diskleri dayanılmaz çubuklara taşımak gibi açık bir hata yoktur.

(çözümün optimal olması gerekmez.)

Giriş

Programınız iki girdi alacak:

  1. Disk sayısı n (bir tam sayı)
  2. Alınan hareketler, aşağıdakilerden oluşan bir dizi tuptan oluşacaktır: (şu anda en üstteki diski alma kulesi), (bu diski alma kulesi), burada her bir kaymanın bir hareketi ifade ettiği. Onların nasıl temsil edileceğini seçebilirsiniz. Örneğin, yukarıda ascii'de çizdiğim n = 2 için çözümü temsil eden aşağıdaki yollar gibi bir şey. (Test senaryosunda birincisini kullanacağım, çünkü gözlerde kolay):

    "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]

Çıktı

  • Truthy, “meydan okuma” altında bulunabilecek koşullar geçerliyse.

  • Sahte, eğer değilse.

Test durumları:

Doğru:

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"

Yanlış:

@MartinEnder tarafından 7, @Joffan tarafından 7

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"

Bu kod golf , en kısa çözüm kazanır. Standart kurallar ve boşluklar geçerlidir. Pil yok.


2 giriş yönteminizi kullanılarak temsil, ancak bunun yerine harfler (yani sayıları kullanarak edilebilirse o da iyi mi A=1, B=2, C=3vs.)?
R. Kap

1
Girdileri sıfırlayabilir miyim?
Rohan Jhunjhunwala

1
Boş veya olmayan bir çubuktan bir disk alındığında bir hata atılması sorun olur mu?
R. Kap,

1
Gibi hareketsiz olmayacağını varsayabilir miyiz A->A?
Martin Ender

2
@Kobi mutlaka kontrol etmelisiniz moving discs to nonexistant rods.tabii ki evet, bu birD
edc65

Yanıtlar:


7

Retina , 84 80 Bayt

Martin Ender sayesinde -5 bayt

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

Çevrimiçi deneyin! (artı satır satır testler için 5 bayt)

Kod dolu bir oyun simüle eder.

  • Giriş olarak verilir ACABCBACBABCAC~~~.
    ~~~üç disk demektir.
  • İlk dört satır oyunu biçimine giriş dönüştürmek: ACABCBACBABCAC ~~~ ~~ ~ABC.
    Başlangıçta A çubuğunun 3 diski de vardır ve B ve C çubukları boştur.
  • Sonra iki aşamalı bir döngü var:
    • Satırdaki ilk harfi alın, sonraki kaynak çubuğunu gösterir. Bu çubuğu bulun ve son diski içeri alın. Mektubu çıkarın ve diski sıkıca hareket ettirin (çıkarın).
      Örnekte, ilk adımdan sonra, metin şöyle görünecektir: ~CABCBACBABCAC ~~~ ~~ABC .
    • İkinci aşamada hedef çubuğu buluyoruz ve diski oraya yerleştiriyoruz. Biz çubuk boş veya üstteki daha büyük bir disk bulunur doğrulamak: ABCBACBABCAC ~~~ ~~AB ~C.
  • Sonunda, A ve B çubuklarının boş olduğunu onaylıyoruz - bu, tüm disklerin C konumunda olduğu anlamına gelir (son satırda fazladan boşluk var).

Vay canına, bu etkileyici
Rohan Jhunjhunwala

17

Retina , 167 165 157 150 123 bayt

Bu tamamen tek bir regex ile çözülmesi gereken bir meydan okumaya benziyor ... ("Retina" yazan başlığa rağmen, bu geçerli bir girdiyle eşleşen bir vanilya .NET regex'idir).

^(?=\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

Giriş formatı, formdaki komutların listesidir AB, ardından nrakamı kullanarak unary kullanılır 1. Ayırıcı yok. Çıktı 1geçerli ve 0geçersiz.

Çevrimiçi deneyin! (İlk iki karakter satır besleme ayrılmış bir test takımını etkinleştirir.)

Alternatif çözüm, aynı bayt sayısı:

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

Bu durum muhtemelen kullanılarak kısaltılabilir 1, 11ve 111yerine A, BveC fakat bunu daha sonra içine bakmak gerekecek. Programı birkaç aşamaya ayırmak da daha kısa olabilir, fakat bunun neresinde zorluk var? ;)

açıklama

Bu çözüm, .NET'in dengeleme gruplarını yoğun şekilde kullanıyor. Tam bir açıklama için Yığın Taşması hakkındaki yazıma bakın , ancak esas amaç, .NET'te yakalama gruplarının yığınlar olduğu, her yeni yakalamanın başka bir alt dizgiyi ittiği ve yeniden böyle bir yığından çıkarmanın mümkün olduğu yerdir. Bu, bir dizgede çeşitli miktarları saymanıza izin verir. Bu durumda, üç çubuğu doğrudan her diskin bir yakalama ile temsil edildiği üç farklı yakalama grubu olarak uygulamamızı sağlar.

Diskleri çubuklar arasında hareket ettirmek için, (?<A-B>...)sözdiziminin tuhaf bir tutamını kullanırız . Normalde, bu yığıntan bir yakalama çıkar Bve Abu yakalanan yakalama ile bu grubun başlangıcı arasındaki dizeyi yığına iter . Yani (?<A>a).(?<B-A>c)eşleşti karşı abcbırakacaktı Aboş ve Bile b(aksine c). Bununla birlikte, .NET değişken uzunluktaki görünümler sayesinde, yakalama (?<A>...)ve (?<B-A>...)üst üste binme için mümkündür . Sebep ne olursa olsun, eğer öyleyse, iki grubun kesişimi üzerine itilir B. Bu davranışı , bu cevaptaki dengeleme gruplarındaki "ileri bölüm" bölümünde ayrıntılı olarak anlattım. .

Regex'e. Çubuklar A, Bve Cgruplara karşılık gelir 3, 4ve 5regex. Çubuk başlatarak başlayalım 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)+
)

Örneğin giriş sona ererse 111, grup 3 / çubuk Aşimdi yakalama listesini tutacaktır[111, 11, 1] (üstte sağda).

Kodun bir sonraki biti aşağıdaki yapıya sahiptir:

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

Bu döngünün her yinelemesi bir talimatı işler. İlk alternatif bir diski verilen çubuktan (geçici bir gruba) çeker, ikinci alternatif bu diski verilen diğer çubuğun üzerine koyar. Bir an sonra bunun nasıl çalıştığını ve hareketin geçerli olmasını nasıl sağladığımızı göreceğiz.

İlk olarak, kaynak çubuğundan bir disk alarak:

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

Bu, yukarıda tanımladığım tuhaf grup kesişme davranışını kullanır. Bu grubu Not 3, 4ve 5her zaman substrings yapacak 1uzunluğu diskin boyutuna karşılık gelir dize sonundaki s. Şimdi (?<1-N>.+)üst diski yığından çıkarmak Nve bu alt halkanın kesişimini kibritle .+yığının üzerine itmek için kullanıyoruz 1. Yana .+her zaman mutlaka kapakları tüm yakalama kapalı attıN , bu basitçe yakalama hareket olduğunu biliyoruz.

Sonra, bu diski yığından 1ikinci çubuğa karşılık gelen yığının üzerine koyduk :

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

Yığını temizlememiz gerekmediğini 1, yığını kullanmadan önce üstüne yeni bir tane koyacağımız için diski orada bırakabileceğimizi unutmayın. Bu, (?<A-B>...)sözdiziminden kaçınabileceğimiz ve basitçe dizeyi kopyalayabileceğimiz anlamına gelir (\1). Hareketin geçerli olmasını sağlamak için negatif görünüşü kullanıyoruz (?!\N). Bu, mevcut diski eşleştirmek istediğimiz konumdan diski zaten istifte eşleştirmek imkansız olmasını sağlar N. Bu yalnızca, a) \Nhiç bir zaman eşleşmeyecek, çünkü yığın tamamen boş veya b) the disc on top of stackN is larger than the one we're trying to match with\ 1` olabilir.

Son olarak, geriye Bunlar bütün talimatları ve b) çubuklar eşleştirdiğimizde) bir sağlanmasıdır Ave Bboş, bu nedenle tüm diskler üzerine taşındığını C.

(?!\3|\4)1

Biz sadece ne olduğunu kontrol \3ne de \4(herhangi bir fiili disk, çünkü her ikisi de boşsa sadece vaka olduğu eşleşebilir olur eşleşecek) ve biz de buna eşleştirebilmemiz 1yüzden hiçbir talimat ihmal değil ki.


14

Java "yalnızca" 311 272 263 261 260 259 256 bayt

39 kayıtlı@Frozn'ın eski bir hata ayıklama özelliğini ve bazı akıllı golf oyunlarını fark etmesi nedeniyle sayısız bayt .

Golf versiyonu

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

Her adımda açıklama ve oldukça basılmış yığınları ile ungolfed

/*
 * 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!");
    }

}

Ungolfed versiyonu, her adımda yığınların nasıl göründüğünü yazdırabilecek bir özelliğe sahip ...

[[2, 1], [], [0]]
[[2], [1], [0]]
[[2], [1, 0], []]
[[], [1, 0], [2]]
[[0], [1], [2]]
[[0], [], [2, 1]]
[[], [], [2, 1, 0]]
Good!

Ne yapar System.out.println(Arrays.toString(s))?
Frozn,

Yığınları çok güzel basacaktır. Şöyle ki [[2,1,0], [] []]
Rohan Jhunjhunwala 23

Whoops @Frozn şimdi kaldırılması bir hata ayıklama özelliği oldu
Rohan Jhunjhunwala

Biliyorum, neden orada olduğunu merak ediyorum :) Siz de &&onunla değiştirebilirsiniz &.
Frozn

@ Frozn Boş bir yığına bakmak istememek için kısa devre davranışına güvendiğim için bunu ne yazık ki değiştiremiyorum. 39 byte azaltma için teşekkürler
Rohan Jhunjhunwala

9

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

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]:_

STDIN'de girişi aşağıdaki biçimde alır:

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

Yani, disk sayısının Python demetini ve disklerin Python listesini (from_rod,to_rod) . Python'da olduğu gibi, çevre parantezler isteğe bağlıdır. Çubuklar sıfır dizinlidir.

Örneğin, bu test durumu:

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

olarak verilecekti:

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

Solüsyon geçerliyse geçersiz ise, 0 bir çıkış kodu ile çıkışlar hiçbir şey ve çıkışlar, 1. bir çıkış kodu ile bir istisna ve çıkışlar bir Atar atar IndexErrornonexistant çubuk geçmesini veya a kapalı bir disk almaya çalışıyor ise Üzerinde disk bulunmayan çubuk ZeroDivisionError, a daha küçük bir diskin üzerine bir disk yerleştirilmişse NameErrorveya sonunda birinci veya ikinci çubuklarda kalan diskler varsa.

@KarlKastor sayesinde 13 bayt kaydedildi!

@Xnor sayesinde 8 bayt kaydedildi!


1
Her yığının sıralandığının kontrolü çok karmaşık görünüyor. Taşınan diskin, taşındığı yığının üst diskinden daha büyük olup olmadığını kontrol edemez misiniz?
xnor

@ xnor Teşekkürler, bu çalışması gerekir. Şimdi ekliyorum.
Copper,

5

Python 2.7, 173 158 138 130 127 123 bayt:

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)

Biçiminde stdin yoluyla girişi Alır (<Number of Discs>,<Moves>)nerede<Moves> her virgülden bir çift içeren her hareket tekabül dizilerini ihtiva eden bir dizi tamsayı ayrılmış olarak verilir. Örneğin, test durumu:

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

yazı içinde verilen:

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

programıma Çıkışlar bir IndexError3 koşul yerine getirilmediği takdirde, bir NameError2 koşul yerine getirilmediği takdirde, ve False1 koşul yerine getirilmediği takdirde. Aksi takdirde çıktılar True.


iki şey: değişken Ykodunuzda asla tanımlanmaz (b J olması gerektiğini düşünüyorum) ve U[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]3 karakterden kısa olanstmt1 if cond else stmt2
jermenkoo

@jermenkoo Peki, bu koşulu, 2. koşul karşılanmadığında Yyükseltmek için kullanıyorum NameError. Değişmek olsaydı Yetmek J, sonra NameErrorkaldırdı olmaz. Bu nedenle, ben de yapamam U[J]+=[Y,[U[K].pop()]][U[J]<[1]or U[K]<U[J]]bu getireceğini çünkü NameError her zaman değil, sadece 2 koşul karşılanmadığında.
R. Kap,

tamam, açıklama için teşekkürler!
jermenkoo

5

VBA, 234 217 213 196 bayt

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

Hareketler için giriş biçimi, çift sayılar içeren bir dizedir (012). Başvuru elektronik tabloda, = H ([disk sayısı], [hareket dizesi])

A dizisi çeşitli disklerin çubuk pozisyonunu tutar. Bir hamle, basitçe "Kimden" çubuk numarasının ilk oluşumunu "Kime" çubuk numarasına güncellemektedir. Önce "Kime" bir çubuk diskiyle karşılaşırsanız veya "Kimden" çubuk diski yoksa, bu geçersiz bir harekettir. A'nın toplam "çubuk değeri", 2N'de bitmesi gereken L'de tutulur. Hatalar E'de negatif sayım olarak biriktirilir.

Diğer çözümlerde olduğu gibi, bir diski kuleden aynı kuleye “taşımak” yasaktır. Başka bir 6 bayt için onu yasaklayabilirdim.

Sonuçlar

İşlev, ilk sütunda sonuçlanır (son n = 3 durum, fazladan bir çubuk kullanarak benim eklememdir).

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

2

php, 141 bayt

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

Komut satırı betiği, yükseklik olarak girdi alır, sonra 1 veya 2 boy kısa test durumları için bir dizi dizin indeksi (0 indeksli) örneğin 1 0 2 veya 2 0 1 0 2 1 2 alır.
Gerçek vakalarda Echos 1, yanlış davalarda hiçbir şey yok.
2 uyarı verir ve 1 uyarı verir, bu yüzden bunları susturan bir ortamda çalıştırılmalıdır.


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]

Giriş formatı: 2 bağımsız değişken içeren fonksiyon

  • arg 1, sayısal, çalma sayısı
  • arg 2, dizge dizisi, her karakter dizisi 2 karakter '0', '1', '2'

Çıktı: 1 ise tamam, 0 ise geçersiz, istisnasız çubuk

Daha az golf oynadı ve açıkladı

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
)

Test Notu: Test fonksiyonunun ilk satırı, soruda verilen giriş formatını fonksiyonumdan beklenen girişe dönüştürmek için gereklidir.

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>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.