--- Towers of Hanoi is a puzzle with three rods and n disks of decresing size.
--- The disks are stacked ontop of each other through the first rod.
--- The aim of the game is to move the stack of disks to another rod while
--- following these rules:
---
--- 1. Only one disk can be moved at a time
---
--- 2. You may only move a disk from the top of one of the stacks to the top of another stack
---
--- 3. No disk may be moved on top of a smaller disk
---
--- The function ;hanoi; computes the sequence of moves to solve puzzle.
module Hanoi;

open import Stdlib.Prelude;

--- Concatenates a list of strings
--- ;concat (("a" :: nil) :: "b" :: nil); evaluates to ;"a" :: "b" :: nil;
concat : List StringString;
concat := foldl (++str) "";

intercalate : StringList StringString;
intercalate sep xs := concat (intersperse sep xs);

--- Produce a singleton List
singleton : {A : Type}AList A;
singleton a := a :: nil;

--- Produce a ;String; representation of a ;List Nat;
showList : List NatString;
showList xs := "[" ++str intercalate "," (map natToString xs) ++str "]";

--- A Peg represents a peg in the towers of Hanoi game
type Peg :=
  | left : Peg
  | middle : Peg
  | right : Peg;

showPeg : PegString;
showPeg left := "left";
showPeg middle := "middle";
showPeg right := "right";

--- A Move represents a move between pegs
type Move :=
  | move : PegPegMove;

showMove : MoveString;
showMove (move from to) := showPeg from ++str " -> " ++str showPeg to;

--- Produce a list of ;Move;s that solves the towers of Hanoi game
hanoi : NatPegPegPegList Move;
hanoi zero _ _ _ := nil;
hanoi (suc n) p1 p2 p3 :=
  hanoi n p1 p3 p2 ++ singleton (move p1 p2) ++ hanoi n p3 p2 p1;

main : IO;
main := printStringLn (unlines (map showMove (hanoi 5 left middle right)));
Last modified on 2023-05-08 11:40 UTC