PROGRAM Hanoi
!--------------------------------------------------------------------------
! Fornisce l'elenco delle mosse del gioco della Torre di Hanoi.
! Algoritmo ricorsivo.
!--------------------------------------------------------------------------
  IMPLICIT NONE
  INTEGER:: N       &  ! altezza della torre
          , part=1  &  ! piolo di partenza inizializzato a 1
          , arr =2  &  ! piolo di arrivo   inizializzato a 2
          , aus =3     ! piolo ausiliario  inizializzato a 3
                       ! NOTA: "&" indica che l'istruzione continua sulla
                       ! riga seguente
  WRITE(*,*) "Gioco della Torre di Hanoi"
  WRITE(*,*) "Quanti dischi? "
  READ(*,*) N
  WRITE(*,'(1X,3(A,I2))') &
      "Piolo di partenza:",part, ", arrivo:",arr, ", ausiliario:",aus
!   Il secondo argomento di WRITE e' un FORMAT, qui inserito come stringa.
!   Il FORMAT e' un modello di record (riga), la cui struttura e'
!   specificata mediante una sequenza di descrittori racchiusa tra
!   parentesi.
!   Descrittori: X: campo contenente uno spazio
!                A: campo contenente una stringa
!                I: campo contenente un intero
!   Ai descrittori A ed I e' associato un elemento della lista di uscita;
!   al descrittore X, nessuno.
!   Il numero che segue un descrittore e' la lunghezza del campo in
!   caratteri. Un descrittore A senza lunghezza sottintende la lunghezza
!   della stringa associata.
!   Il numero che precede un descrittore e' un fattore di ripetizione
!   opzionale, salvo per X, dove e' obbligatorio.
!   Si possono ripetere sequenze di campi racchiudendoli tra parentesi e
!   premettendo un fattore di ripetizione (es.: 3(A,I2) ).
!   NOTA: quando si scrive con formato, il Fortran si potrebbe mangiare il
!   primo carattere e fare cose curiose (per non tornare all'epoca dei
!   dinosauri, rinunciamo a spiegare quali e perche'). Inserendo
!   sistematicamente uno spazio ad inizio riga, si evita qualunque noia.
!   Il FORMAT può essere usato, con analogo significato, per le letture.
  WRITE(*,*) "Elenco delle mosse"
  CALL MuoviTorre(N,part,arr,aus)
  STOP

CONTAINS
!--------------------------------------------------------------------------
RECURSIVE SUBROUTINE MuoviTorre(alt,part,arr,aus)
! Sposta una torre di altezza "alt" dal piolo "part" ad "arr", usando il
! piolo "aus" quale ausiliario.
!--------------------------------------------------------------------------
  INTEGER,INTENT(IN) :: alt, part, arr, aus
    IF (alt>0) THEN
    CALL MuoviTorre(alt-1,part,aus,arr)
    CALL MuoviDisco(part,arr)
    CALL MuoviTorre(alt-1,aus,arr,part)
  END IF
  RETURN
END SUBROUTINE MuoviTorre

!--------------------------------------------------------------------------
SUBROUTINE MuoviDisco(part,arr)
! Scrive la mossa: spostamento del disco superiore del piolo "part" al
! piolo "arr".
!--------------------------------------------------------------------------
  INTEGER,INTENT(IN) :: part, arr
  WRITE(*,'(I10," --> ",I2)') part, arr
!   Un campo dal contenuto fisso (es.: " --> ") si può inserire
!   direttamente fra i descrittori.
  RETURN
END SUBROUTINE MuoviDisco
END PROGRAM Hanoi
