let knightsmoves = [(-1,-2); (-2,-1); (1,-2); (-2,1); (-1,2); (2,-1); (1,2); (2,1)];;
(* Uncomment the following if you want alternative order of the moves *)
(*
let knightsmoves = [(1, 2); (1, -2); (-1, 2); (-1, -2); (2, 1); (2, -1); (-2, 1); (-2, -1)];;
*)

let add (a,b) (c,d) = (a+c,b+d);;
	
let onboard (a,b) =
	(a >= 0) && (a < 8) &&
	(b >= 0) && (b < 8);;

let moves pos =
     List.filter (onboard)
                 (List.map (add pos) knightsmoves);;

let filmoves pos soln = 
     List.filter (fun b -> not (List.mem b soln)) (moves pos);;

let compval soln pos1 pos2 =
     (List.length (filmoves pos1 soln)) -
      (List.length (filmoves pos2 soln));;

let sortedmoves soln =
     List.sort (compval soln)
               (filmoves (List.hd soln) (List.tl soln));;

let rec do_until f = function
      | [] -> []
      | h::t -> match f h with
                | [] -> do_until f t
                | answer -> answer;;

let rec extend1 start len soln =
      if (len == 64)
      then
        if List.mem start (moves (List.hd soln))
        then soln
        else []
      else
        do_until (fun b -> extend1 start (len+1) (b::soln))
                 (sortedmoves soln);;

let extend start = extend1 start 1 [start];;

let rec indexadd n pos soln =
      if  (List.hd soln) = pos
      then n
      else indexadd (n-1) pos (List.tl soln);;

let index pos soln = indexadd 64 pos soln;;

let printsoln soln =
	(* Print the top line *)
	for i = 1 to 8 do
		Printf.printf "-----";
	done;
	Printf.printf "-\n";

	for i = 0 to 7 do
		for j = 0 to 7 do
			Printf.printf "| %2i " (index (i,j) soln);
		done;
		Printf.printf "|\n";
		(* Print a line below *)
		for j = 1 to 8 do
			Printf.printf "-----";
		done;
		Printf.printf "-\n";
	done;;

if (!Sys.interactive)
then
      (* If we are loaded in the interpreter do nothing *)
      ()
else
      if (Array.length Sys.argv) > 2
      then
        printsoln
          (extend
             (int_of_string Sys.argv.(1), int_of_string Sys.argv.(2))
          )
      else
        Printf.printf "Usage: %s x y\n" (Sys.argv.(0));;
