Risolutore della torre di hanoi


10

Per riferimento a ciò che è la torre di Hanoi, Google o guarda sulla pagina di Wikipedia .

Il tuo codice dovrebbe essere in grado di fare 2 cose e sono le seguenti:

  • Accetta l'input dell'utente che specifica il numero di dischi nel punto iniziale della torre di Hanoi
  • Crea un output come preferisci (purché sia ​​in qualche modo logico) per mostrare la soluzione al puzzle della torre.

Un esempio di output logico sarebbe il seguente (utilizzando un avvio a 4 dischi):

L1L2C1L1R-2R-1L1L2C1C-1R-2C1L1L2C1

Lrappresenta il piolo sinistro, Crappresenta il piolo centrale e Rrappresenta il piolo destro e i numeri indicano la distanza di spostamento del disco su quel piolo e in quale direzione. I numeri positivi rappresentano il numero di pioli che si spostano verso il piolo più a destra (poiché i dischi iniziano sul piolo più a sinistra).

Le regole per la torre di Hanoi sono semplici:

  • È possibile spostare un solo disco alla volta.
  • Ogni mossa consiste nel prendere il disco superiore da uno dei pioli e farlo scorrere su un altro piolo, sopra gli altri dischi che potrebbero già essere presenti su quel piolo.
  • Nessun disco può essere posizionato sopra un disco più piccolo.

I dischi iniziano dal piolo più a sinistra, più grande nella parte inferiore, più piccolo nella parte superiore, naturalmente.


Dobbiamo risolvere torri arbitrariamente grandi o c'è qualche limite che possiamo assumere, come i dischi 10, 100, 1k, 1M?
utente sconosciuto

@userunk Se fossi in te, non mi preoccuperei troppo di numeri straordinariamente grandi, ma dirò che il numero più alto di dischi che il tuo programma può gestire dovrebbe essere limitato solo dalla capacità di memoria del computer o dal suo limite di stack di chiamate ( tipo della stessa cosa immagino, dal momento che la memoria è un termine piuttosto generale). Non lasciare che numeri arbitrariamente alti ti spaventino quando invii il tuo codice; se la tua soluzione è creativa ma può gestire solo così tanti dischi, io per primo ti darei comunque credito.
Carter Pape,

Bene, la mia idea era un algoritmo di risoluzione piuttosto inefficiente e, se il limite è, se il programma fosse in grado di gestire, andrebbe bene. Ma finora ho visto le soluzioni e ho capito che avrei giocato in un campionato completamente diverso.
utente sconosciuto

Risposte:


2

Buccia , 5 byte

↑≠⁰İr

Provalo online!
Ciascuno nnell'output rappresenta lo spostamento del disco nal successivo pegging disponibile (avvolgendo ciclicamente).

Spiegazione

   İr   The ruler sequence [0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, ...]
↑       Take while...
 ≠⁰     ... not equal to the input.

7

Python, 76 caratteri

def S(n,a,b):
 if n:S(n-1,a,6-a-b);print n,a,b;S(n-1,6-a-b,b)
S(input(),1,3)

Ad esempio, per N = 3 restituisce:

1 1 3  (move disk 1 from peg 1 to peg 3)
2 1 2  (move disk 2 from peg 1 to peg 2)
1 3 2  (move disk 1 from peg 3 to peg 2)
3 1 3  ...
1 2 1
2 2 3
1 1 3

So di essere un po 'in ritardo al gioco, ma questo fa radere 13 caratteri: tio.run/##K6gsycjPM/r/…
JayCe

6

Perl - 54 caratteri

for(2..1<<<>){$_--;$x=$_&-$_;say(($_-$x)%3,($_+$x)%3)}

Esegui con perl -M5.010e inserisci il numero di dischi su stdin.

Formato di output:

Una riga per mossa, la prima cifra è dal piolo, la seconda cifra è dal piolo (a partire da 0)

Esempio:

02 -- move from peg 0 to peg 2
01
21
02
10
12
02

Salva 5 caratteri rimuovendo le parentesi graffe. $x=--$_&-$_,say(($_-$x)%3,($_+$x)%3)for 2..1<<<>
marinus,

5

GolfScript ( 31 25 24 caratteri)

])~{{~3%}%.{)3%}%2,@++}*

Grazie a Ilmari Karonen per aver sottolineato che le mie originali trpermutazioni potrebbero essere abbreviate di 6 caratteri. Decomponendoli come prodotto di due permutazioni sono riuscito a salvarne uno in più.

Si noti che il factoring 3%aumenta la lunghezza di un carattere:

])~{{~}%.{)}%2,@++}*{3%}%

Alcune persone hanno formati di output davvero complicati. In questo modo il piolo si sposta da (numerato 0, 1, 2) e il piolo si sposta su. La specifica non dice a quale piolo spostare, quindi passa al piolo 1.

Per esempio

$ golfscript hanoi.gs <<<"3"
01021201202101

Senza dubbio la stessa logica in sed è ancora più breve, ma le mie capacità sed non sono all'altezza.
Peter Taylor,

1
Puoi farlo in 25 caratteri:])~{.{3^3%}%2,@{2\-}%++}*
Ilmari Karonen,

3

Perl, 75 79 caratteri

Rubare totalmente il formato di output di Keith Randall:

sub h{my($n,$p,$q)=@_;h($n,$p^$q^h($n,$p,$p^$q),$q*say"@_")if$n--}h pop,1,3

Invocare con -M5.010per il say.

(Penso che questo possa essere migliorato se riesci a trovare un modo per utilizzare il valore restituito della funzione invece di sopprimerlo.)


[ sayraccomandazione " usa solo "]
JB

Va bene - ma non dovrei includere il costo dell'abilitazione delle funzionalità 5.10 rispetto al mio conteggio dei caratteri?
breadbox

1
Vorresti ... ma è gratis. Basta prendere nota di come invocare il programma in modo che le persone non fluenti nelle specifiche di invocazione perl possano comunque provarlo.
JB,

Grazie per il link; Prima cercavo quel genere di cose.
breadbox,

3

SML, 63

fun f(0,_,_)=[]|f(n,s,t)=f(n-1,s,6-s-t)@[n,s,t]@f(n-1,6-s-t,t);

funzione di chiamata f(n,s,t)con:

  • n numero di dischi
  • s punto di partenza
  • punto obiettivo

2

Bash (64 caratteri)

t(){ tr 2$1 $12 <<<$s;};for((i=$1;i--;))do s=`t 1`01`t 0`;done;t

Pubblicare questo nonostante sia più del doppio della lunghezza di quello GolfScript perché mi piace il riutilizzo di tservire come echo $s.


2

Scala, 92 88 87 caratteri

def?(n:Int,a:Int,b:Int){if(n>0){?(n-1,a,a^b)
print(n,a,b);?(n-1,a^b,b)}};?(readInt,1,3)

Formato di output

Pronuncia il numero di disco = 3 quindi,

(1,1,3)(2,1,2)(1,3,2)(3,1,3)(1,2,1)(2,2,3)(1,1,3) (disk number,from peg, to peg)
                                                   \---------------------------/       
                                                            Move 1              ... Move n

Bel uso di xor.
Peter Taylor,

2

C, 98 92 87 caratteri

Implementa l'algoritmo più banale.
L'output è nella forma in ab ab abcui ogni coppia significa "sposta il disco superiore dal pegging al pegg b".
EDIT : le mosse sono ora codificate in esadecimale - 0x12 significa spostarsi dal piolo 1 al piolo 2. Salvati alcuni caratteri.
EDIT : legge il numero dallo stdin, piuttosto che dal parametro. Più corto.
Esempio:
% echo 3 | ./hanoi
13 12 32 13 21 23 13

n;
h(d){n--&&h(d^d%16*16,printf("%02x ",d,h(d^d/16))),n++;}
main(){scanf("%d",&n);h(19);}

Qualcuno può spiegare la sintassi del corpo della funzione h () - in particolare i due argomenti apparenti nella sua chiamata ricorsiva (d ^ d% 16 * 16 e printf (...)) e l'ultima operazione apparentemente sospesa alla fine. Sulla base delle mie conoscenze, quella funzione ha due errori di sintassi, ma so già che si costruisce (dopo aver incluso stdio) ed esegue correttamente.
Griffin,

1
È possibile passare più parametri di quelli desiderati dalla funzione. I loro valori non vanno da nessuna parte. h(x,printf(...))è semplicemente un modo per chiamare printfprima che hvenga chiamato. L'ultimo n++è fatto dopo i hritorni interiori . Viene utilizzato per annullare l'iniziale n--.
ugoren,

Grazie, ha un senso (lo scopo di n ++ era evidente). Perché non c'è un punto e virgola che precede n ++ invece di una virgola o fa la differenza?
Griffin,

@Griffin, In realtà ;sarebbe lo stesso qui. ,è spesso utile (ad esempio if(x)a,b;sostituisce if(x){a;b;}), ma qui non ha alcun vantaggio.
ugoren,

2

Gelatina , 5 byte

2*Ṗọ2

Provalo online!

0sposta il disco più piccolo di uno spazio a destra (ritornando all'inizio se necessario)
1sposta il secondo disco più piccolo nell'unica altra colonna legale
2sposta il terzo disco più piccolo nell'unica altra colonna legale
ecc.

Algoritmo

Possiamo vedere ricorsivamente la soluzione del problema delle Torri di Hanoi; per spostare una pila di dimensioni n da A a B , spostare una pila di dimensioni n -1 da A a C , allora il disco di dimensione n da A a B , quindi spostare una pila di dimensione n -1 da B a C . Questo produce un modello nel seguente formato (nel formato di output utilizzato da questo programma):

0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2 …

Possiamo osservare che questa sequenza è A007814 sull'OEIS . Un'altra possibile definizione della sequenza è "l' elemento k th (basato su 1) della sequenza è il numero di zero alla fine del numero k quando è scritto in binario". Ed è quello che sta calcolando il programma qui.

Spiegazione

Innanzitutto, calcoliamo il numero di mosse nella soluzione, 2 n -1. Risulta essere il più breve per calcolare effettivamente una mossa extra e scartarla in un secondo momento, quindi questo è 2*, cioè 2 per la potenza di qualcosa. (L'unico input che abbiamo preso finora è l'argomento della riga di comando, quindi viene utilizzato di default.)

Quindi, usiamo l'integrato di Jelly per calcolare il numero di zero alla fine di un numero nella base b ; quello è . Come stiamo calcolando in binario, lo è . Tutto quello che dobbiamo fare è applicare questo builtin ai numeri da 1 a 2 n -1 inclusi.bọ2

Esistono due semplici modi per scorrere su un intervallo di numeri in Jelly e R, e i miei precedenti tentativi di risolvere questo problema, hanno utilizzato uno di questi. Tuttavia, in questo caso, è possibile andare leggermente più corto:, quando viene dato un numero come input, ti permetterà di eseguire un'iterazione che interrompe un elemento in breve (in generale, è un builtin usato per elaborare tutti gli elementi tranne uno). Questo è esattamente ciò che vogliamo in questo caso (perché2* genera troppi elementi), quindi usarlo per collegare 2*e ọ2in 2*Ṗọ2ci dà una soluzione a 5 byte al problema.


1

Awk, 72 caratteri

function t(n,a,b){if(n){t(n-1,a,a^b);print n,a,b;t(n-1,a^b,b)}}t($0,1,3)

Il formato di output è uguale a quello di Keith Randall .

awk -f tower.awk <<< "3"    
1 1 1
2 1 1
1 1 1
3 1 3
1 1 1
2 1 3
1 1 3

1

Script Bash, 100 96 caratteri

t(){ [[ $1<1 ]] && return
t $(($1-1)) $2 $(($2^$3))
echo $@
t $(($1-1)) $(($2^$3)) $3
}
t $1 1 3

Il formato di output è uguale a quello di Keith Randall .

1 1 3
2 1 2
1 3 2
3 1 3
1 2 1
2 2 3
1 1 3

Modifica : salvato 4 caratteri con il commento di Peter .


1
Puoi aggiungere gli spazi e salvare alcuni caratteri facendo eco$@
Peter Taylor,

@PeterTaylor: buon punto. lasciami aggiornare.
Prince John Wesley,

1

J, 23 byte

soluzione di numeri binari

2&(+/@:~:/\)@#:@i.@^~&2

Questa soluzione utilizza il metodo di conteggio binario descritto in questo video .

Vale a dire, genera le cifre binarie 1fino a 2^n, quindi prendo gli infissi di lunghezza 2 e confronto ogni bit con il bit corrispondente del numero precedente e controllo se sono disuguali. Il numero di bit disuguali è l'output per quella mossa.

Uscita, ad esempio, per 3 dischi, in cui il disco più piccolo è etichettato 1:

1 2 1 3 1 2 1

1 significa "sposta il disco più piccolo di un piolo a destra, eseguendo il ciclo indietro al primo piolo se necessario"

n, per tutti gli altri n, significa "sposta il disco nin un piolo legale" (ce ne sarà sempre esattamente uno)

Provalo online!

soluzione ricorsiva

((],[,])$:@<:)`]@.(1=])

Stesso risultato della soluzione precedente, ma la logica qui rende più chiara la natura ricorsiva del problema.

Visualizzarlo come un albero sottolinea anche questo punto:

              4
             / \
            /   \
           /     \
          /       \
         /         \
        /           \
       /             \
      3               3      
     / \             / \    
    /   \           /   \
   /     \         /     \ 
  2       2       2       2  
 / \     / \     / \     / \
1   1   1   1   1   1   1   1

Provalo online!


1
la coincidenza della presentazione della tua risposta oltre 5 anni dopo che la domanda originale è stata posta entro la stessa ora in cui sono tornato per rivedere le risposte a questa domanda che ho presentato più di 5 anni fa ... wow. +1
Carter Pape,



0

R , 73 byte

Mettendo R sulla mappa. Ispirato da [Keith Randall's answer] [1] con input semplificato, stampa solo end e start peg per salvare 2 byte. Pioli anche con indice 0.

f=function(n,s=0,e=2){if(n){f(n-1,s,3-s-e)
print(c(s,e))
f(n-1,3-s-e,e)}}

Provalo online!


0

JavaScript (ES6), 45b

h=(n,f,a,t)=>n?h(--n,f,t,a)+f+t+h(n,a,f,t):''

es. chiamata h(4, 'A', 'B', 'C') (spostare 4 dischi dal piolo A al piolo C usando il piolo ausiliario B)

ritorna 'ABACBCABCACBABACBCBACABCABACBC'(sposta un disco dal piolo A al piolo B, sposta un disco dal piolo A al piolo C, sposta un disco dal piolo B al piolo C, ecc.)


1
Bello. Mi chiedo se i parametri f, a, t debbano includere valori predefiniti nella definizione della funzione? In caso contrario, i contributi potrebbero includere dati arbitrari in argomenti aggiuntivi. Sono un novizio, quindi qualcuno più esperto dovrebbe consigliare.
John Rees,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.