Towers of Hanoi

Below is the code we used in class. In the cslab, it can also be found in /cslab/class/cs243/hanoi.ml.

fun makeSet(0) = ([], [] : int list, [] : int list)
  | makeSet(n) = (n::(#1( makeSet(n-1))), [], []) ;


fun pegInOrder([]) = true
  | pegInOrder(x::[]) = true
  | pegInOrder(x::y::rest) = x > y andalso pegInOrder(y::rest);


fun pegContainsDisk(disk, []) = false 
  | pegContainsDisk(disk, x::rest) =
    if disk = x then true else pegContainsDisk(disk, rest);

fun booleanToInteger(true) = 1
  | booleanToInteger(false) = 0;

fun setContainsDiskOnce(disk, (peg1, peg2, peg3)) =
  booleanToInteger(pegContainsDisk(disk, peg1)) +
  booleanToInteger(pegContainsDisk(disk, peg2)) +
  booleanToInteger(pegContainsDisk(disk, peg3))  = 1;

fun setContainsDisks(0, pegs) = true
  | setContainsDisks(n, pegs) =
    setContainsDiskOnce(n, pegs) andalso 
      setContainsDisks(n-1, pegs);

fun numDisks([], [], []) = 0
  | numDisks([], [], a::rest) =
      let 
         val highest = numDisks([], [], rest);
      in
         if a < highest then highest else a
      end
  | numDisks([], a::rest, peg3) =
      let    
         val highest = numDisks([], rest, peg3);
      in
         if a < highest then highest else a
      end
  | numDisks(a::rest, peg2, peg3) =
      let 
         val highest = numDisks(rest, peg2, peg3);
      in
         if a < highest then highest else a
      end;


fun setValidState(pegs as (peg1, peg2, peg3)) = 
  setContainsDisks( numDisks(pegs), pegs) andalso
    pegInOrder(peg1) andalso pegInOrder(peg2) andalso 
    pegInOrder(peg3);


fun hanoi(pegs) =
  let 
    fun move((x::rest, peg2, peg3), 1, 2) = (rest, x::peg2, peg3)
        | move((x::rest, peg2, peg3), 1, 3) = (rest, peg2, x::peg3)
        | move((peg1, x::rest, peg3), 2, 1) = (x::peg1, rest, peg3)
        | move((peg1, x::rest, peg3), 2, 3) = (peg1, rest, x::peg3)
        | move((peg1, peg2, x::rest), 3, 1) = (x::peg1, peg2, rest)
        | move((peg1, peg2, x::rest), 3, 2) = (peg1, x::peg2, rest);
     fun solveHanoi(1,  pegs, from, to, use) = move(pegs, from, to) 
         | solveHanoi(n, pegs, from, to, use) =
           let
              val step1 = solveHanoi(n-1, pegs, from, use, to);
              val step2 = move(step1, from, to);
              val step3 = solveHanoi(n-1, step2, use, to, from);
        in
           step3 
       end;
in
   solveHanoi(numDisks(pegs), pegs, 1, 3, 2)
end;

fun cheatHanoi(peg1, peg2, peg3) = (peg3, peg2, peg1);


fun factorial(0) = 1
   | factorial(n) = n * factorial(n-1);

val counter = ref 0;

fun monitor(x) = (counter := !counter + 1; x);

fun factorialM(0) = 1
   | factorialM(n) = n * monitor(factorialM(n-1));

!counter;

fun monitor2(x) = (print(Int.toString(x)^"\n"); x);

fun factorialM2(0) = 1
   | factorialM2(n) = n * monitor2(factorialM2(n-1));

fun factorialMG(n, m) =
  let 
    fun factorial(0) = 1
         | factorial(x) = x * m(factorial(x-1));
  in
     factorial(n)
  end;

fun fibMG(n, m) =
  let 
    fun fib(1) = 1
         | fib(2) = 1
         | fib(x) = m(fib(x-1)) + m(fib(x-2));
  in
     fib(n)
    end;


fun listToString(list) =
  let 
     fun listToStringHelper([]) = ""
       | listToStringHelper([a]) = Int.toString(a) 
       | listToStringHelper(x::rest) = 
             Int.toString(x) ^ "," ^ listToStringHelper(rest);
  in
    "[" ^ listToStringHelper(list) ^ "]"
  end;

fun printSet(peg1, peg2, peg3) =
   print("(" ^ listToString(peg1) ^ "," ^ listToString(peg2) ^ 
          "," ^ listToString(peg3) ^ ")\n");

fun hanoiM(pegs, m) =
  let 
    fun move((x::rest, peg2, peg3), 1, 2) = (rest, x::peg2, peg3)
        | move((x::rest, peg2, peg3), 1, 3) = (rest, peg2, x::peg3)
        | move((peg1, x::rest, peg3), 2, 1) = (x::peg1, rest, peg3)
        | move((peg1, x::rest, peg3), 2, 3) = (peg1, rest, x::peg3)
        | move((peg1, peg2, x::rest), 3, 1) = (x::peg1, peg2, rest)
        | move((peg1, peg2, x::rest), 3, 2) = (peg1, x::peg2, rest);
     fun solveHanoi(1,  pegs, from, to, use) = m(move(pegs, from, to)) 
         | solveHanoi(n, pegs, from, to, use) =
           let
              val step1 = solveHanoi(n-1, pegs, from, use, to);
              val step2 = m(move(step1, from, to));
              val step3 = solveHanoi(n-1, step2, use, to, from);
        in
           step3 
       end;
in
   solveHanoi(numDisks(pegs), pegs, 1, 3, 2)
end;

fun regular(set) = hanoiM(set, fn (x) => x);

fun check(set) = hanoiM(set, 
                        fn (x) => (if not (setValidState(x)) then printSet(x) else () ;
                                   x));

fun watch(set) = hanoiM(set,
                        fn (x) => (printSet(x); x));


Thomas VanDrunen
Last modified: Mon Dec 10 12:05:46 CST 2007