Il mio professore ha dato this come esempio di Prolog. È un programma che risolve l'enigma della Torre di Hanoi, in cui devi spostare una pila di dischi in un altro peg spostando un disco dopo l'altro, senza mettere un disco più grande sopra un disco più piccolo.Solving Tower of Hanoi dichiarative (Prolog)
Ora, questo programma non mi piace. Mi è stato detto che Prolog era destinato alla programmazione dichiarativa. Non voglio programmare come risolvere il problema, voglio scrivere usando Prolog il problema è. Quindi lascia che Prolog risolva.
I miei sforzi finora sono disponibili qui sotto. Esistono due tipi di elenchi che utilizzo, una sequenza di azioni è rappresentata in questo modo: [[1,2],[3,1]]
; questo sarebbe "spostare il primo disco dal peg 1 al peg 2, spostare il disco dal peg 3 al peg 1". Il mio secondo tipo di elenco è uno stato , ad esempio, se ci sono tre pioli [[1,2,3], [], []]
significherebbe che ci sono tre dischi sul primo peg. I dischi più piccoli hanno numeri più piccoli, quindi la parte anteriore della lista interna è la cima di una pila.
% A sequence of actions (first argument) is a solution if it leads
% from the begin state (second argument) to the End state (third argument).
solution([], X, X).
solution([[FromIdx | ToIdx] | T], Begin, End) :-
moved(FromIdx, ToIdx, Begin, X),
solution(T, X, End).
% moved is true when Result is the resulting state after moving
% a disk from FromIdx to ToIdx starting at state Start
moved(FromIdx, ToIdx, Start, Result) :-
allowedMove(FromIdx, ToIdx, Start),
nth1(FromIdx, Start, [Disk|OtherDisks]),
nth1(ToIdx, Start, ToStack),
nth1(FromIdx, Result, OtherDisks),
nth1(ToIdx, Result, [Disk|ToStack]).
allowedMove(FromIdx, ToIdx, State) :-
number(FromIdx), number(ToIdx),
nth1(FromIdx, State, [FromDisk|_]),
nth1(ToIdx, State, [ToDisk|_]),
ToDisk > FromDisk.
allowedMove(_, ToIdx, State) :- nth1(ToIdx, State, []).
Il programma di cui sopra sembra funzionare, ma è troppo lento per tutto ragionevolmente complesso. Chiedendo di risolvere il classico Torre di problema Hanoi, passando tre dischi dal primo piolo per la terza e ultima, sarebbe andata in questo modo:
?- solution(Seq, [[1,2,3], [], []], [[], [], [1,2,3]]).
vorrei apportare alcune modifiche al programma in modo che funzioni per questa query. Come potrei fare per farlo? Durante la creazione di profili, posso vedere che lo nth1
utilizza molto tempo, dovrei liberarmene? Qualcosa che mi dà fastidio è che moved
è completamente deterministico e dovrebbe avere solo un risultato. Come posso accelerare questo collo di bottiglia?
Penso che l'intera implementazione sia di natura imperativa. Hai fatto uno stackoverflow.com o una ricerca su google su "torri prolog di hanoi"? Esistono numerosi esempi su come farlo in modo più relazionale. – lurker
Puoi spiegare che cosa è necessario? E alla tua domanda: sì, sì, ma tutto ciò che ho potuto trovare era nello stile della soluzione a cui mi collegavo, che è palesemente imperativo. – Alex
Suppongo che stavo digitando tutte le chiamate "nth1/3' come stavi indicando anche nella tua domanda. Ci sono alcune cose minori da risolvere, come piuttosto che "[[FromIdx | ToIdx] | T] 'una forma come' [FromIdx-ToIdx | T] 'potrebbe essere più appropriato. Nel grande, si potrebbe adottare l'approccio "standard" e usare CLP (FD) ('N #> 1, N # = N-1') e trasportare un argomento lista per le mosse piuttosto che' scrivi's comunemente vedere in altre implementazioni. – lurker