C-----------------------------------------------------------------------
C
C     Find Knight’s Tours.
C
C     Using Warnsdorff’s heuristic, find multiple solutions.
C     Optionally accept only closed tours.
C
C     This program is migrated from my implementation for ATS/Postiats.
C     Arrays with dimension 1:64 take the place of stack frames.
C
C     Compile with, for instance:
C
C         gfortran -O2 -g -std=legacy -o knights_tour knights_tour.f
C
C     or
C
C         f2c knights_tour.f
C         cc -O -o knights_tour knights_tour.c -lf2c
C
C     Usage examples:
C
C         One tour starting at a1, either open or closed:
C
C            echo "a1 1 F" | ./knights_tour
C
C         No more than 2000 closed tours starting at c5:
C
C            echo "c5 2000 T" | ./knights_tour
C
C-----------------------------------------------------------------------

      program ktour
      implicit none

      character*2 alg
      integer i, j
      integer mxtour
      logical closed

      read (*,*) alg, mxtour, closed
      call alg2ij (alg, i, j)
      call explor (i, j, mxtour, closed)

      end

C-----------------------------------------------------------------------

      subroutine explor (istart, jstart, mxtour, closed)
      implicit none

C     Explore the space of 'Warnsdorffian' knight’s paths, looking for
C     and printing complete tours.

      integer istart, jstart    ! The starting position.
      integer mxtour            ! The maximum number of tours to print.
      logical closed            ! Closed tours only?

      integer board(1:8,1:8)
      integer imove(1:8,1:64)
      integer jmove(1:8,1:64)
      integer nmove(1:64)
      integer n
      integer itours
      logical goodmv
      logical isclos

      itours = 0
      call initbd (board)
      n = 1
      nmove(1) = 8
      imove(8, 1) = istart
      jmove(8, 1) = jstart

 1000 if (itours .lt. mxtour .and. n .ne. 0) then

         if (nmove(n) .eq. 9) then
            n = n - 1
            if (n .ne. 0) then
               call unmove (board, imove, jmove, nmove, n)
               nmove(n) = nmove(n) + 1
            end if
         else if (goodmv (imove, nmove, n)) then
            call mkmove (board, imove, jmove, nmove, n)
            if (n .eq. 64) then
               if (.not. closed) then
                  itours = itours + 1
                  call prnt (board, itours)
               else if (isclos (board)) then
                  itours = itours + 1
                  call prnt (board, itours)
               end if
               call unmove (board, imove, jmove, nmove, n)
               nmove(n) = 9
            else if (n .eq. 63) then
               call possib (board, n, imove, jmove, nmove)
               n = n + 1
               nmove(n) = 1
            else
               call nxtmov (board, n, imove, jmove, nmove)
               n = n + 1
               nmove(n) = 1
            end if
         else
            nmove(n) = nmove(n) + 1
         end if

         goto 1000
      end if

      end

C-----------------------------------------------------------------------

      subroutine initbd (board)
      implicit none

C     Initialize a chessboard with empty squares.

      integer board(1:8,1:8)

      integer i, j

      do 1010 j = 1, 8
         do 1000 i = 1, 8
            board(i, j) = -1
 1000    continue
 1010 continue

      end

C-----------------------------------------------------------------------

      subroutine mkmove (board, imove, jmove, nmove, n)
      implicit none

C     Fill a square with a move number.

      integer board(1:8, 1:8)
      integer imove(1:8, 1:64)
      integer jmove(1:8, 1:64)
      integer nmove(1:64)
      integer n

      board(imove(nmove(n), n), jmove(nmove(n), n)) = n

      end

C-----------------------------------------------------------------------

      subroutine unmove (board, imove, jmove, nmove, n)
      implicit none

C     Unmake a mkmove.

      integer board(1:8, 1:8)
      integer imove(1:8, 1:64)
      integer jmove(1:8, 1:64)
      integer nmove(1:64)
      integer n

      board(imove(nmove(n), n), jmove(nmove(n), n)) = -1

      end

C-----------------------------------------------------------------------

      function goodmv (imove, nmove, n)
      implicit none

      logical goodmv
      integer imove(1:8, 1:64)
      integer nmove(1:64)
      integer n

      goodmv = (imove(nmove(n), n) .ne. -1)

      end

C-----------------------------------------------------------------------

      subroutine prnt (board, itours)
      implicit none

C     Print a knight's tour.

      integer board(1:8,1:8)
      integer itours

10000 format (1X)

C     The following plethora of format statements seemed a simple way to
C     get this working with f2c. (For gfortran, the 'I0' format
C     sufficed.)
10010 format (1X, "Tour number ", I1)
10020 format (1X, "Tour number ", I2)
10030 format (1X, "Tour number ", I3)
10040 format (1X, "Tour number ", I4)
10050 format (1X, "Tour number ", I5)
10060 format (1X, "Tour number ", I6)
10070 format (1X, "Tour number ", I20)

      if (itours .lt. 10) then
         write (*, 10010) itours
      else if (itours .lt. 100) then
         write (*, 10020) itours
      else if (itours .lt. 1000) then
         write (*, 10030) itours
      else if (itours .lt. 10000) then
         write (*, 10040) itours
      else if (itours .lt. 100000) then
         write (*, 10050) itours
      else if (itours .lt. 1000000) then
         write (*, 10060) itours
      else
         write (*, 10070) itours
      end if
      call prntmv (board)
      call prntbd (board)
      write (*, 10000)

      end

C-----------------------------------------------------------------------

      subroutine prntbd (board)
      implicit none

C     Print a chessboard with the move number in each square.

      integer board(1:8,1:8)

      integer i, j

10000 format (1X, "    ", 8("+----"), "+")
10010 format (1X, I2, " ", 8(" | ", I2), " | ")
10020 format (1X, "   ", 8("    ", A1))

      do 1000 i = 8, 1, -1
         write (*, 10000)
         write (*, 10010) i, (board(i, j), j = 1, 8)
 1000 continue
      write (*, 10000)
      write (*, 10020) 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'

      end

C-----------------------------------------------------------------------

      subroutine prntmv (board)
      implicit none

C     Print the moves of a knight's path, in algebraic notation.

      integer board(1:8,1:8)

      integer ipos(1:64)
      integer jpos(1:64)
      integer numpos
      character*2 alg(1:64)
      integer columns(1:8)
      integer k
      integer m

      character*72 lines(1:8)

10000 format (1X, A)

      call bd2pos (board, ipos, jpos, numpos)

C     Convert the positions to algebraic notation.
      do 1000 k = 1, numpos
         call ij2alg (ipos(k), jpos(k), alg(k))
 1000 continue

C     Fill lines with algebraic notations.
      do 1020 m = 1, 8
         columns(m) = 1
 1020 continue
      m = 1
      do 1100 k = 1, numpos
         lines(m)(columns(m) : columns(m) + 1) = alg(k)(1:2)
         columns(m) = columns(m) + 2
         if (k .ne. numpos) then
            lines(m)(columns(m) : columns(m) + 3) = " -> "
            columns(m) = columns(m) + 4
         else if (numpos .eq. 64 .and.
     $           ((abs (ipos(numpos) - ipos(1)) .eq. 2
     $           .and. abs (jpos(numpos) - jpos(1)) .eq. 1) .or.
     $           ((abs (ipos(numpos) - ipos(1)) .eq. 1
     $           .and. abs (jpos(numpos) - jpos(1)) .eq. 2)))) then
            lines(m)(columns(m) : columns(m) + 8) = " -> cycle"
            columns(m) = columns(m) + 9
         endif
         if (mod (k, 8) .eq. 0) m = m + 1
 1100 continue

C     Print the lines that have stuff in them.
      do 1200 m = 1, 8
         if (columns(m) .ne. 1) then
            write (*, 10000) lines(m)(1 : columns(m) - 1)
         end if
 1200 continue

      end

C-----------------------------------------------------------------------

      function isclos (board)
      implicit none

C     Is a board a closed tour?

      logical isclos
      integer board(1:8,1:8)
      integer ipos(1:64)        ! The i-positions in order.
      integer jpos(1:64)        ! The j-positions in order.
      integer numpos            ! The number of positions so far.

      call bd2pos (board, ipos, jpos, numpos)

      isclos = (numpos .eq. 64 .and.
     $     ((abs (ipos(numpos) - ipos(1)) .eq. 2
     $     .and. abs (jpos(numpos) - jpos(1)) .eq. 1) .or.
     $     ((abs (ipos(numpos) - ipos(1)) .eq. 1
     $     .and. abs (jpos(numpos) - jpos(1)) .eq. 2))))

      end

C-----------------------------------------------------------------------

      subroutine bd2pos (board, ipos, jpos, numpos)
      implicit none

C     Convert from a board to a list of board positions.

      integer board(1:8,1:8)
      integer ipos(1:64)        ! The i-positions in order.
      integer jpos(1:64)        ! The j-positions in order.
      integer numpos            ! The number of positions so far.

      integer i, j

      numpos = 0
      do 1010 i = 1, 8
         do 1000 j = 1, 8
            if (board(i, j) .ne. -1) then
               numpos = max (board(i, j), numpos)
               ipos(board(i, j)) = i
               jpos(board(i, j)) = j
            end if
 1000    continue
 1010 continue

      end

C-----------------------------------------------------------------------

      subroutine nxtmov (board, n, imove, jmove, nmove)
      implicit none

C     Find possible next moves. Prune and sort the moves according to
C     Warnsdorff's heuristic, keeping only those that have the minimum
C     number of legal following moves.

      integer board(1:8,1:8)
      integer n
      integer imove(1:8,1:64)
      integer jmove(1:8,1:64)
      integer nmove(1:64)

      integer w1, w2, w3, w4, w5, w6, w7, w8
      integer w
      integer n1
      integer pickw

      call possib (board, n, imove, jmove, nmove)

      n1 = n + 1
      nmove(n1) = 1
      call countf (board, n1, imove, jmove, nmove, w1)
      nmove(n1) = 2
      call countf (board, n1, imove, jmove, nmove, w2)
      nmove(n1) = 3
      call countf (board, n1, imove, jmove, nmove, w3)
      nmove(n1) = 4
      call countf (board, n1, imove, jmove, nmove, w4)
      nmove(n1) = 5
      call countf (board, n1, imove, jmove, nmove, w5)
      nmove(n1) = 6
      call countf (board, n1, imove, jmove, nmove, w6)
      nmove(n1) = 7
      call countf (board, n1, imove, jmove, nmove, w7)
      nmove(n1) = 8
      call countf (board, n1, imove, jmove, nmove, w8)

      w = pickw (w1, w2, w3, w4, w5, w6, w7, w8)

      if (w .eq. 0) then
         call disabl (imove(1, n1), jmove(1, n1))
         call disabl (imove(2, n1), jmove(2, n1))
         call disabl (imove(3, n1), jmove(3, n1))
         call disabl (imove(4, n1), jmove(4, n1))
         call disabl (imove(5, n1), jmove(5, n1))
         call disabl (imove(6, n1), jmove(6, n1))
         call disabl (imove(7, n1), jmove(7, n1))
         call disabl (imove(8, n1), jmove(8, n1))
      else
         if (w .ne. w1) call disabl (imove(1, n1), jmove(1, n1))
         if (w .ne. w2) call disabl (imove(2, n1), jmove(2, n1))
         if (w .ne. w3) call disabl (imove(3, n1), jmove(3, n1))
         if (w .ne. w4) call disabl (imove(4, n1), jmove(4, n1))
         if (w .ne. w5) call disabl (imove(5, n1), jmove(5, n1))
         if (w .ne. w6) call disabl (imove(6, n1), jmove(6, n1))
         if (w .ne. w7) call disabl (imove(7, n1), jmove(7, n1))
         if (w .ne. w8) call disabl (imove(8, n1), jmove(8, n1))
      end if

      end

C-----------------------------------------------------------------------

      subroutine countf (board, n, imove, jmove, nmove, w)
      implicit none

C     Count the number of moves possible after an nth move.

      integer board(1:8,1:8)
      integer n
      integer imove(1:8,1:64)
      integer jmove(1:8,1:64)
      integer nmove(1:64)
      integer w

      logical goodmv
      integer n1

      if (goodmv (imove, nmove, n)) then
         call mkmove (board, imove, jmove, nmove, n)
         call possib (board, n, imove, jmove, nmove)
         n1 = n + 1
         w = 0
         if (imove(1, n1) .ne. -1) w = w + 1
         if (imove(2, n1) .ne. -1) w = w + 1
         if (imove(3, n1) .ne. -1) w = w + 1
         if (imove(4, n1) .ne. -1) w = w + 1
         if (imove(5, n1) .ne. -1) w = w + 1
         if (imove(6, n1) .ne. -1) w = w + 1
         if (imove(7, n1) .ne. -1) w = w + 1
         if (imove(8, n1) .ne. -1) w = w + 1
         call unmove (board, imove, jmove, nmove, n)
      else
C        The nth move itself is impossible.
         w = 0
      end if

      end

C-----------------------------------------------------------------------

      function pickw (w1, w2, w3, w4, w5, w6, w7, w8)
      implicit none

C     From w1..w8, pick out the least nonzero value (or zero if they all
C     equal zero).

      integer pickw
      integer w1, w2, w3, w4, w5, w6, w7, w8

      integer w
      integer pickw1

      w = 0
      w = pickw1 (w, w1)
      w = pickw1 (w, w2)
      w = pickw1 (w, w3)
      w = pickw1 (w, w4)
      w = pickw1 (w, w5)
      w = pickw1 (w, w6)
      w = pickw1 (w, w7)
      w = pickw1 (w, w8)

      pickw = w

      end

C-----------------------------------------------------------------------

      function pickw1 (u, v)
      implicit none

C     A small function used by pickw.

      integer pickw1
      integer u, v

      if (v .eq. 0) then
         pickw1 = u
      else if (u .eq. 0) then
         pickw1 = v
      else
         pickw1 = min (u, v)
      end if

      end

C-----------------------------------------------------------------------

      subroutine possib (board, n, imove, jmove, nmove)
      implicit none

C     Find moves that are possible from an nth-move position.

      integer board(1:8,1:8)
      integer n
      integer imove(1:8,1:64)
      integer jmove(1:8,1:64)
      integer nmove(1:64)

      integer i, j
      integer n1

      i = imove(nmove(n), n)
      j = jmove(nmove(n), n)
      n1 = n + 1
      call trymov (board, i + 1, j + 2, imove(1, n1), jmove(1, n1))
      call trymov (board, i + 2, j + 1, imove(2, n1), jmove(2, n1))
      call trymov (board, i + 1, j - 2, imove(3, n1), jmove(3, n1))
      call trymov (board, i + 2, j - 1, imove(4, n1), jmove(4, n1))
      call trymov (board, i - 1, j + 2, imove(5, n1), jmove(5, n1))
      call trymov (board, i - 2, j + 1, imove(6, n1), jmove(6, n1))
      call trymov (board, i - 1, j - 2, imove(7, n1), jmove(7, n1))
      call trymov (board, i - 2, j - 1, imove(8, n1), jmove(8, n1))

      end

C-----------------------------------------------------------------------

      subroutine trymov (board, i, j, imove, jmove)
      implicit none

C     Try a move to square (i, j).

      integer board(1:8,1:8)
      integer i, j
      integer imove, jmove

      call disabl (imove, jmove)
      if (1 .le. i .and. i .le. 8 .and. 1 .le. j .and. j .le. 8) then
         if (board(i,j) .eq. -1) then
            call enable (i, j, imove, jmove)
         end if
      end if

      end

C-----------------------------------------------------------------------

      subroutine enable (i, j, imove, jmove)
      implicit none

C     Enable a potential move.

      integer i, j
      integer imove, jmove

      imove = i
      jmove = j

      end

C-----------------------------------------------------------------------

      subroutine disabl (imove, jmove)
      implicit none

C     Disable a potential move.

      integer imove, jmove

      imove = -1
      jmove = -1

      end

C-----------------------------------------------------------------------

      subroutine alg2ij (alg, i, j)
      implicit none

C     Convert, for instance, 'c5' to i=3,j=5.

      character*2 alg
      integer i, j

      if (alg(1:1) .eq. 'a') j = 1
      if (alg(1:1) .eq. 'b') j = 2
      if (alg(1:1) .eq. 'c') j = 3
      if (alg(1:1) .eq. 'd') j = 4
      if (alg(1:1) .eq. 'e') j = 5
      if (alg(1:1) .eq. 'f') j = 6
      if (alg(1:1) .eq. 'g') j = 7
      if (alg(1:1) .eq. 'h') j = 8

      if (alg(2:2) .eq. '1') i = 1
      if (alg(2:2) .eq. '2') i = 2
      if (alg(2:2) .eq. '3') i = 3
      if (alg(2:2) .eq. '4') i = 4
      if (alg(2:2) .eq. '5') i = 5
      if (alg(2:2) .eq. '6') i = 6
      if (alg(2:2) .eq. '7') i = 7
      if (alg(2:2) .eq. '8') i = 8

      end

C-----------------------------------------------------------------------

      subroutine ij2alg (i, j, alg)
      implicit none

C     Convert, for instance, i=3,j=5 to 'c5'.

      integer i, j
      character*2 alg

      character alg1
      character alg2

      if (j .eq. 1) alg1 = 'a'
      if (j .eq. 2) alg1 = 'b'
      if (j .eq. 3) alg1 = 'c'
      if (j .eq. 4) alg1 = 'd'
      if (j .eq. 5) alg1 = 'e'
      if (j .eq. 6) alg1 = 'f'
      if (j .eq. 7) alg1 = 'g'
      if (j .eq. 8) alg1 = 'h'

      if (i .eq. 1) alg2 = '1'
      if (i .eq. 2) alg2 = '2'
      if (i .eq. 3) alg2 = '3'
      if (i .eq. 4) alg2 = '4'
      if (i .eq. 5) alg2 = '5'
      if (i .eq. 6) alg2 = '6'
      if (i .eq. 7) alg2 = '7'
      if (i .eq. 8) alg2 = '8'

      alg(1:1) = alg1
      alg(2:2) = alg2

      end

C-----------------------------------------------------------------------


package main

import (
    "fmt"
    "math/rand"
    "time"
)

// input, 0-based start position
const startRow = 0
const startCol = 0

func main() {
    rand.Seed(time.Now().Unix())
    for !knightTour() {
    }
}

var moves = []struct{ dr, dc int }{
    {2, 1},
    {2, -1},
    {1, 2},
    {1, -2},
    {-1, 2},
    {-1, -2},
    {-2, 1},
    {-2, -1},
}

// Attempt knight tour starting at startRow, startCol using Warnsdorff's rule
// and random tie breaking.  If a tour is found, print it and return true.
// Otherwise no backtracking, just return false.
func knightTour() bool {
    // 8x8 board.  squares hold 1-based visit order.  0 means unvisited.
    board := make([][]int, 8)
    for i := range board {
        board[i] = make([]int, 8)
    }
    r := startRow
    c := startCol
    board[r][c] = 1 // first move
    for move := 2; move <= 64; move++ {
        minNext := 8
        var mr, mc, nm int
    candidateMoves:
        for _, cm := range moves {
            cr := r + cm.dr
            if cr < 0 || cr >= 8 { // off board
                continue
            }
            cc := c + cm.dc
            if cc < 0 || cc >= 8 { // off board
                continue
            }
            if board[cr][cc] > 0 { // already visited
                continue
            }
            // cr, cc candidate legal move.
            p := 0 // count possible next moves.
            for _, m2 := range moves {
                r2 := cr + m2.dr
                if r2 < 0 || r2 >= 8 {
                    continue
                }
                c2 := cc + m2.dc
                if c2 < 0 || c2 >= 8 {
                    continue
                }
                if board[r2][c2] > 0 {
                    continue
                }
                p++
                if p > minNext { // bail out as soon as it's eliminated
                    continue candidateMoves
                }
            }
            if p < minNext { // it's better.  keep it.
                minNext = p // new min possible next moves
                nm = 1      // number of candidates with this p
                mr = cr     // best candidate move
                mc = cc
                continue
            }
            // it ties for best so far.
            // keep it with probability 1/(number of tying moves)
            nm++                    // number of tying moves
            if rand.Intn(nm) == 0 { // one chance to keep it
                mr = cr
                mc = cc
            }
        }
        if nm == 0 { // no legal move
            return false
        }
        // make selected move
        r = mr
        c = mc
        board[r][c] = move
    }
    // tour complete.  print board.
    for _, r := range board {
        for _, m := range r {
            fmt.Printf("%3d", m)
        }
        fmt.Println()
    }
    return true
}


import Data.Bifunctor (bimap)
import Data.Char (chr, ord)
import Data.List (intercalate, minimumBy, sort, (\\))
import Data.Ord (comparing)
import Control.Monad (join)

---------------------- KNIGHT'S TOUR ---------------------

type Square = (Int, Int)

knightTour :: [Square] -> [Square]
knightTour moves
  | null possibilities = reverse moves
  | otherwise = knightTour $ newSquare : moves
  where
    newSquare =
      minimumBy
        (comparing (length . findMoves))
        possibilities
    possibilities = findMoves $ head moves
    findMoves = (\\ moves) . knightOptions

knightOptions :: Square -> [Square]
knightOptions (x, y) =
  knightMoves >>= go . bimap (+ x) (+ y)
  where
    go move
      | uncurry (&&) (both onBoard move) = [move]
      | otherwise = []

knightMoves :: [(Int, Int)]
knightMoves =
  ((>>=) <*> (\deltas n -> deltas >>= go n)) [1, 2, -1, -2]
  where
    go i x
      | abs i /= abs x = [(i, x)]
      | otherwise = []

onBoard :: Int -> Bool
onBoard = (&&) . (0 <) <*> (9 >)

both :: (a -> b) -> (a,  a) -> (b,  b)
both = join bimap

--------------------------- TEST -------------------------
startPoint :: String
startPoint = "e5"

algebraic :: (Int, Int) -> String
algebraic (x, y) = [chr (x + 96), chr (y + 48)]

main :: IO ()
main =
  printTour $
    algebraic
      <$> knightTour
        [(\[x, y] -> (ord x - 96, ord y - 48)) startPoint]
  where
    printTour [] = return ()
    printTour tour = do
      putStrLn $ intercalate " -> " $ take 8 tour
      printTour $ drop 8 tour


link printf

procedure main(A)
ShowTour(KnightsTour(Board(8)))
end

procedure KnightsTour(B,sq,tbrk,debug)  #: Warnsdorff’s algorithm

/B := Board(8)                          # create 8x8 board if none given
/sq := ?B.files || ?B.ranks             # random initial position (default)
sq2fr(sq,B)                             # validate initial sq
if type(tbrk) == "procedure" then
   B.tiebreak := tbrk                   # override tie-breaker
if \debug then write("Debug log : move#, move : (accessibility) choices")

choices := []                           # setup to track moves and choices
every (movesto := table())[k := key(B.movesto)] := copy(B.movesto[k])

B.tour := []                            # new tour
repeat {
   put(B.tour,sq)                       # record move

   ac := 9                              # accessibility counter > maximum
   while get(choices)                   # empty choices for tiebreak
   every delete(movesto[nextsq := !movesto[sq]],sq) do {  # make sq unavailable
      if ac >:= *movesto[nextsq] then   # reset to lower accessibility count
         while get(choices)             # . re-empty choices
      if ac = *movesto[nextsq] then
         put(choices,nextsq)            # keep least accessible sq and any ties
      }

   if \debug then {                     # move#, move, (accessibility), choices
      writes(sprintf("%d. %s : (%d) ",*B.tour,sq,ac))
      every writes(" ",!choices|"\n")
      }
   sq := B.tiebreak(choices,B) | break  # choose next sq until out of choices
   }
return B
end

procedure RandomTieBreaker(S,B)                   # random choice
return ?S
end

procedure FirstTieBreaker(S,B)                    # first one in the list
return !S
end

procedure RothTieBreaker(S,B)                    # furthest from the center
if *S = 0 then fail                              # must fail if []
every fr := sq2fr(s := !S,B) do {
   d := sqrt(abs(fr[1]-1 - (B.N-1)*0.5)^2 + abs(fr[2]-1 - (B.N-1)*0.5)^2)
   if (/md := d) | ( md >:= d) then msq := s     # save sq
   }
return msq
end

record board(N,ranks,files,movesto,tiebreak,tour)  # structure for board

procedure Board(N)                      #: create board
N := *&lcase >=( 0 < integer(N)) | stop("N=",image(N)," is out of range.")
B := board(N,[],&lcase[1+:N],table(),RandomTieBreaker)       # setup
every put(B.ranks,N to 1 by -1)                              # add rank #s
every sq := !B.files || !B.ranks do                          # for each sq add
   every insert(B.movesto[sq] := set(), KnightMoves(sq,B))   # moves to next sq
return B
end

procedure sq2fr(sq,B)                   #: return numeric file & rank
f := find(sq[1],B.files)                | runerr(205,sq)
r := integer(B.ranks[sq[2:0]])          | runerr(205,sq)
return [f,r]
end

procedure KnightMoves(sq,B)         #: generate all Kn accessible moves from sq
fr := sq2fr(sq,B)
every ( i := -2|-1|1|2 ) & ( j := -2|-1|1|2 ) do
   if (abs(i)~=abs(j)) & (0<(ri:=fr[2]+i)<=B.N) & (0<(fj:=fr[1]+j)<=B.N) then
      suspend B.files[fj]||B.ranks[ri]
end

procedure ShowTour(B)                   #: show the tour
write("Board size = ",B.N)
write("Tour length = ",*B.tour)
write("Tie Breaker = ",image(B.tiebreak))

every !(squares := list(B.N)) := list(B.N,"-")
every fr := sq2fr(B.tour[m := 1 to *B.tour],B) do
   squares[fr[2],fr[1]] := m

every (hdr1 := "     ") ||:= right(!B.files,3)
every (hdr2 := "    +") ||:= repl((1 to B.N,"-"),3) | "-+"

every write(hdr1|hdr2)
every r := 1 to B.N do {
   writes(right(B.ranks[r],3)," |")
   every writes(right(squares[r,f := 1 to B.N],3))
   write(" |",right(B.ranks[r],3))
   }
every write(hdr2|hdr1|&null)
end


import java.util.*;

public class KnightsTour {
    private final static int base = 12;
    private final static int[][] moves = {{1,-2},{2,-1},{2,1},{1,2},{-1,2},
        {-2,1},{-2,-1},{-1,-2}};
    private static int[][] grid;
    private static int total;

    public static void main(String[] args) {
        grid = new int[base][base];
        total = (base - 4) * (base - 4);

        for (int r = 0; r < base; r++)
            for (int c = 0; c < base; c++)
                if (r < 2 || r > base - 3 || c < 2 || c > base - 3)
                    grid[r][c] = -1;

        int row = 2 + (int) (Math.random() * (base - 4));
        int col = 2 + (int) (Math.random() * (base - 4));

        grid[row][col] = 1;

        if (solve(row, col, 2))
            printResult();
        else System.out.println("no result");

    }

    private static boolean solve(int r, int c, int count) {
        if (count > total)
            return true;

        List<int[]> nbrs = neighbors(r, c);

        if (nbrs.isEmpty() && count != total)
            return false;

        Collections.sort(nbrs, new Comparator<int[]>() {
            public int compare(int[] a, int[] b) {
                return a[2] - b[2];
            }
        });

        for (int[] nb : nbrs) {
            r = nb[0];
            c = nb[1];
            grid[r][c] = count;
            if (!orphanDetected(count, r, c) && solve(r, c, count + 1))
                return true;
            grid[r][c] = 0;
        }

        return false;
    }

    private static List<int[]> neighbors(int r, int c) {
        List<int[]> nbrs = new ArrayList<>();

        for (int[] m : moves) {
            int x = m[0];
            int y = m[1];
            if (grid[r + y][c + x] == 0) {
                int num = countNeighbors(r + y, c + x);
                nbrs.add(new int[]{r + y, c + x, num});
            }
        }
        return nbrs;
    }

    private static int countNeighbors(int r, int c) {
        int num = 0;
        for (int[] m : moves)
            if (grid[r + m[1]][c + m[0]] == 0)
                num++;
        return num;
    }

    private static boolean orphanDetected(int cnt, int r, int c) {
        if (cnt < total - 1) {
            List<int[]> nbrs = neighbors(r, c);
            for (int[] nb : nbrs)
                if (countNeighbors(nb[0], nb[1]) == 0)
                    return true;
        }
        return false;
    }

    private static void printResult() {
        for (int[] row : grid) {
            for (int i : row) {
                if (i == -1) continue;
                System.out.printf("%2d ", i);
            }
            System.out.println();
        }
    }
}


class KnightTour {
 constructor() {
  this.width = 856;
  this.height = 856;
  this.cellCount = 8;
  this.size = 0;
  this.knightPiece = "\u2658";
  this.knightPos = {
   x: 0,
   y: 0
  };
  this.ctx = null;
  this.step = this.width / this.cellCount;
  this.lastTime = 0;
  this.wait;
  this.delay;
  this.success;
  this.jumps;
  this.directions = [];
  this.visited = [];
  this.path = [];
  document.getElementById("start").addEventListener("click", () => {
   this.startHtml();
  });
  this.init();
  this.drawBoard();
 }

 drawBoard() {
  let a = false, xx, yy;
  for (let y = 0; y < this.cellCount; y++) {
   for (let x = 0; x < this.cellCount; x++) {
    if (a) {
     this.ctx.fillStyle = "#607db8";
    } else {
     this.ctx.fillStyle = "#aecaf0";
    }
    a = !a;
    xx = x * this.step;
    yy = y * this.step;
    this.ctx.fillRect(xx, yy, xx + this.step, yy + this.step);
   }
   if (!(this.cellCount & 1)) a = !a;
  }
  if (this.path.length) {
   const s = this.step >> 1;
   this.ctx.lineWidth = 3;
   this.ctx.fillStyle = "black";
   this.ctx.beginPath();
   this.ctx.moveTo(this.step * this.knightPos.x + s, this.step * this.knightPos.y + s);
   let a, b, v = this.path.length - 1;
   for (; v > -1; v--) {
    a = this.path[v].pos.x * this.step + s;
    b = this.path[v].pos.y * this.step + s;
    this.ctx.lineTo(a, b);
    this.ctx.fillRect(a - 5, b - 5, 10, 10);
   }
   this.ctx.stroke();
  }
 }

 createMoves(pos) {
  const possibles = [];
  let x = 0,
   y = 0,
   m = 0,
   l = this.directions.length;
  for (; m < l; m++) {
   x = pos.x + this.directions[m].x;
   y = pos.y + this.directions[m].y;
   if (x > -1 && x < this.cellCount && y > -1 && y < this.cellCount && !this.visited[x + y * this.cellCount]) {
    possibles.push({
     x,
     y
    })
   }
  }
  return possibles;
 }

 warnsdorff(pos) {
  const possibles = this.createMoves(pos);
  if (possibles.length < 1) return [];
  const moves = [];
  for (let p = 0, l = possibles.length; p < l; p++) {
   let ps = this.createMoves(possibles[p]);
   moves.push({
    len: ps.length,
    pos: possibles[p]
   });
  }
  moves.sort((a, b) => {
   return b.len - a.len;
  });
  return moves;
 }

 startHtml() {
  this.cellCount = parseInt(document.getElementById("cellCount").value);
  this.size = Math.floor(this.width / this.cellCount)
  this.wait = this.delay = parseInt(document.getElementById("delay").value);
  this.step = this.width / this.cellCount;
  this.ctx.font = this.size + "px Arial";
  document.getElementById("log").innerText = "";
  document.getElementById("path").innerText = "";
  this.path = [];
  this.jumps = 1;
  this.success = true;
  this.visited = [];
  const cnt = this.cellCount * this.cellCount;
  for (let a = 0; a < cnt; a++) {
   this.visited.push(false);
  }
  const kx = parseInt(document.getElementById("knightx").value),
   ky = parseInt(document.getElementById("knighty").value);
  this.knightPos = {
   x: (kx > this.cellCount || kx < 0) ? Math.floor(Math.random() * this.cellCount) : kx,
   y: (ky > this.cellCount || ky < 0) ? Math.floor(Math.random() * this.cellCount) : ky
  };
  this.mainLoop = (time = 0) => {
   const dif = time - this.lastTime;
   this.lastTime = time;
   this.wait -= dif;
   if (this.wait > 0) {
    requestAnimationFrame(this.mainLoop);
    return;
   }
   this.wait = this.delay;
   let moves;
   if (this.success) {
    moves = this.warnsdorff(this.knightPos);
   } else {
    if (this.path.length > 0) {
     const path = this.path[this.path.length - 1];
     moves = path.m;
     if (moves.length < 1) this.path.pop();
     this.knightPos = path.pos
     this.visited[this.knightPos.x + this.knightPos.y * this.cellCount] = false;
     this.jumps--;
     this.wait = this.delay;
    } else {
     document.getElementById("log").innerText = "Can't find a solution!";
     return;
    }
   }
   this.drawBoard();
   const ft = this.step - (this.step >> 3);
   this.ctx.fillStyle = "#000";
   this.ctx.fillText(this.knightPiece, this.knightPos.x * this.step, this.knightPos.y * this.step + ft);
   if (moves.length < 1) {
    if (this.jumps === this.cellCount * this.cellCount) {
     document.getElementById("log").innerText = "Tour finished!";
     let str = "";
     for (let z of this.path) {
      str += `${1 + z.pos.x + z.pos.y * this.cellCount}, `;
     }
     str += `${1 + this.knightPos.x + this.knightPos.y * this.cellCount}`;
     document.getElementById("path").innerText = str;
     return;
    } else {
     this.success = false;
    }
   } else {
    this.visited[this.knightPos.x + this.knightPos.y * this.cellCount] = true;
    const move = moves.pop();
    this.path.push({
     pos: this.knightPos,
     m: moves
    });
    this.knightPos = move.pos
    this.success = true;
    this.jumps++;
   }
   requestAnimationFrame(this.mainLoop);
  };
  this.mainLoop();
 }

 init() {
  const canvas = document.createElement("canvas");
  canvas.id = "cv";
  canvas.width = this.width;
  canvas.height = this.height;
  this.ctx = canvas.getContext("2d");
  document.getElementById("out").appendChild(canvas);
  this.directions = [{
    x: -1,
    y: -2
   }, {
    x: -2,
    y: -1
   }, {
    x: 1,
    y: -2
   }, {
    x: 2,
    y: -1
   },
   {
    x: -1,
    y: 2
   }, {
    x: -2,
    y: 1
   }, {
    x: 1,
    y: 2
   }, {
    x: 2,
    y: 1
   }
  ];
 }
}
new KnightTour();


# define	NUMBER_OF_POINTS	100000
# define	NUMBER_OF_CLUSTERS	11
# define	MAXIMUM_ITERATIONS	100
# define	RADIUS			10.0

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef struct {
	double	x;
	double	y;
	int		group;
} POINT;

/*-------------------------------------------------------
	gen_xy

	This function allocates a block of memory for data points,
	gives the data points random values and returns a pointer to them.
	The data points fall within a circle of the radius passed to
	the function. This does not create a uniform 2-dimensional
	distribution.
-------------------------------------------------------*/
POINT * gen_xy(int num_pts, double radius)
{
	int		i;
	double	ang, r;
	POINT * pts;

	pts = (POINT*) malloc(sizeof(POINT) * num_pts);

	for ( i = 0; i < num_pts; i++ ) {
		ang = 2.0 * M_PI * rand() / (RAND_MAX - 1.);
		r = radius * rand() / (RAND_MAX - 1.);
		pts[i].x = r * cos(ang);
		pts[i].y = r * sin(ang);
	}
	return pts;
}

/*-------------------------------------------------------
	dist2

	This function returns the squared euclidean distance
	between two data points.
-------------------------------------------------------*/
double dist2(POINT * a, POINT * b)
{
	double x = a->x - b->x;
	double y = a->y - b->y;
	return x*x + y*y;
}

/*------------------------------------------------------
	nearest

  This function returns the index of the cluster centroid
  nearest to the data point passed to this function.
------------------------------------------------------*/
int nearest(POINT * pt, POINT * cent, int n_cluster)
{
	int i, clusterIndex;
	double d, min_d;

	min_d = HUGE_VAL;
	clusterIndex = pt->group;
	for (i = 0; i < n_cluster; i++) {
		d = dist2(&cent[i], pt);
		if ( d < min_d ) {
			min_d = d;
			clusterIndex = i;
		}
	}
	return clusterIndex;
}

/*------------------------------------------------------
	nearestDistance

  This function returns the distance of the cluster centroid
  nearest to the data point passed to this function.
------------------------------------------------------*/
double nearestDistance(POINT * pt, POINT * cent, int n_cluster)
{
	int i;
	double d, min_d;

	min_d = HUGE_VAL;
	for (i = 0; i < n_cluster; i++) {
		d = dist2(&cent[i], pt);
		if ( d < min_d ) {
			min_d = d;
		}
	}

	return min_d;
}

/*----------------------------------------------------------------------
  bisectionSearch

  This function makes a bisectional search of an array of values that are
  ordered in increasing order, and returns the index of the first element
  greater than the search value passed as a parameter.

  This code is adapted from code by Andy Allinger given to the public
  domain.

  Input:
		x	A pointer to an array of values in increasing order to be searched.
		n	The number of elements in the input array x.
		v	The search value.
  Output:
		Returns the index of the first element greater than the search value, v.
----------------------------------------------------------------------*/
int bisectionSearch(double *x, int n, double v)
{
	int il, ir, i;

	if (n < 1) {
		return 0;
	}
	/* If v is less than x(0) or greater than x(n-1)  */
	if (v < x[0]) {
		return 0;
	}
	else if (v > x[n-1]) {
		return n - 1;
	}

	/*bisection search */
	il = 0;
	ir = n - 1;

	i = (il + ir) / 2;
	while ( i != il ) {
		if (x[i] <= v) {
			il = i;
		} else {
			ir = i;
		}
		i = (il + ir) / 2;
	}

	if (x[i] <= v)
		i = ir;
	return i;
} /* end of bisectionSearch */

/*-------------------------------------------------------
	kppAllinger

	This function uses the K-Means++ method to select
	the cluster centroids.

	This code is adapted from code by Andy Allinger given to the
	public domain.

	Input:
		pts		A pointer to an array of data points.
		num_pts		The number of points in the pts array.
		centroids	A pointer to an array to receive the centroids.
		num_clusters	The number of clusters to be found.

	Output:
		centroids	A pointer to the array of centroids found.
-------------------------------------------------------*/
void kppAllinger(POINT * pts, int num_pts, POINT * centroids,
		 int num_clusters)
{
	int j;
	int selectedIndex;
	int cluster;
	double sum;
	double d;
	double random;
	double * cumulativeDistances;
	double * shortestDistance;

	cumulativeDistances = (double*) malloc(sizeof(double) * num_pts);
	shortestDistance = (double*) malloc(sizeof(double) * num_pts);

	/* Pick the first cluster centroids at random. */
	selectedIndex = rand() % num_pts;
	centroids[0] = pts[ selectedIndex ];

	for (j = 0; j < num_pts; ++j)
		shortestDistance[j] = HUGE_VAL;

	/* Select the centroids for the remaining clusters. */
	for (cluster = 1; cluster < num_clusters; cluster++) {

		/* For each point find its closest distance to any of
		   the previous cluster centers */
		for ( j = 0; j < num_pts; j++ ) {
			d = dist2(&pts[j], &centroids[cluster-1] );

			if (d < shortestDistance[j])
				shortestDistance[j] = d;
		}

		/* Create an array of the cumulative distances. */
		sum = 0.0;
		for (j = 0; j < num_pts; j++) {
			sum += shortestDistance[j];
			cumulativeDistances[j] = sum;
		}

		/* Select a point at random. Those with greater distances
		   have a greater probability of being selected. */
		random = (float) rand() / (float) RAND_MAX * sum;
		selectedIndex = bisectionSearch(cumulativeDistances, num_pts, random);

		/* assign the selected point as the center */
		centroids[cluster] = pts[selectedIndex];
	}

	/* Assign each point the index of it's nearest cluster centroid. */
	for (j = 0; j < num_pts; j++)
		pts[j].group = nearest(&pts[j], centroids, num_clusters);

	free(shortestDistance);
	free(cumulativeDistances);

	return;
}	/* end, kppAllinger */

/*-------------------------------------------------------
	kpp

	This function uses the K-Means++ method to select
	the cluster centroids.
-------------------------------------------------------*/
void kpp(POINT * pts, int num_pts, POINT * centroids,
		 int num_clusters)
{
	int j;
	int cluster;
	double sum;
	double * distances;

	distances = (double*) malloc(sizeof(double) * num_pts);

	/* Pick the first cluster centroids at random. */
	centroids[0] = pts[ rand() % num_pts ];

	/* Select the centroids for the remaining clusters. */
	for (cluster = 1; cluster < num_clusters; cluster++) {

		/* For each data point find the nearest centroid, save its
		   distance in the distance array, then add it to the sum of
		   total distance. */
		sum = 0.0;
		for ( j = 0; j < num_pts; j++ ) {
			distances[j] =
				nearestDistance(&pts[j], centroids, cluster);
			sum += distances[j];
		}

		/* Find a random distance within the span of the total distance. */
		sum = sum * rand() / (RAND_MAX - 1);

		/* Assign the centroids. the point with the largest distance
			will have a greater probability of being selected. */
		for (j = 0; j < num_pts; j++ ) {
			sum -= distances[j];
			if ( sum <= 0)
			{
				centroids[cluster] = pts[j];
				break;
			}
		}
	}

	/* Assign each observation the index of it's nearest cluster centroid. */
	for (j = 0; j < num_pts; j++)
		pts[j].group = nearest(&pts[j], centroids, num_clusters);

	free(distances);

	return;
}	/* end, kpp */

/*-------------------------------------------------------
	lloyd

	This function clusters the data using Lloyd's K-Means algorithm
	after selecting the intial centroids using the K-Means++
	method.
	It returns a pointer to the memory it allocates containing
	the array of cluster centroids.
-------------------------------------------------------*/
POINT * lloyd(POINT * pts, int num_pts, int num_clusters, int maxTimes)
{
	int i, clusterIndex;
	int changes;
	int acceptable = num_pts / 1000;	/* The maximum point changes acceptable. */

	if (num_clusters == 1 || num_pts <= 0 || num_clusters > num_pts )
		return 0;

	POINT * centroids = (POINT *)malloc(sizeof(POINT) * num_clusters);

	if ( maxTimes < 1 )
		maxTimes = 1;

/*	Assign initial clustering randomly using the Random Partition method
	for (i = 0; i < num_pts; i++ ) {
		pts[i].group = i % num_clusters;
	}
*/

	/* or use the k-Means++ method */

/* Original version
	kpp(pts, num_pts, centroids, num_clusters);
*/
	/* Faster Allinger version */
	kppAllinger(pts, num_pts, centroids, num_clusters);

	do {
		/* Calculate the centroid of each cluster.
		  ----------------------------------------*/

		/* Initialize the x, y and cluster totals. */
		for ( i = 0; i < num_clusters; i++ ) {
			centroids[i].group = 0;		/* used to count the cluster members. */
			centroids[i].x = 0;			/* used for x value totals. */
			centroids[i].y = 0;			/* used for y value totals. */
		}

		/* Add each observation's x and y to its cluster total. */
		for (i = 0; i < num_pts; i++) {
			clusterIndex = pts[i].group;
			centroids[clusterIndex].group++;
			centroids[clusterIndex].x += pts[i].x;
			centroids[clusterIndex].y += pts[i].y;
		}

		/* Divide each cluster's x and y totals by its number of data points. */
		for ( i = 0; i < num_clusters; i++ ) {
			centroids[i].x /= centroids[i].group;
			centroids[i].y /= centroids[i].group;
		}

		/* Find each data point's nearest centroid */
		changes = 0;
		for ( i = 0; i < num_pts; i++ ) {
			clusterIndex = nearest(&pts[i], centroids, num_clusters);
			if (clusterIndex != pts[i].group) {
				pts[i].group = clusterIndex;
				changes++;
			}
		}

		maxTimes--;
	} while ((changes > acceptable) && (maxTimes > 0));

	/* Set each centroid's group index */
	for ( i = 0; i < num_clusters; i++ )
		centroids[i].group = i;

	return centroids;
}	/* end, lloyd */

/*-------------------------------------------------------
	print_eps

	this function prints the results.
-------------------------------------------------------*/
void print_eps(POINT * pts, int num_pts, POINT * centroids, int num_clusters)
{
#	define W 400
#	define H 400

	int i, j;
	double min_x, max_x, min_y, max_y, scale, cx, cy;
	double *colors = (double *) malloc(sizeof(double) * num_clusters * 3);

	for (i = 0; i < num_clusters; i++) {
		colors[3*i + 0] = (3 * (i + 1) % 11)/11.;
		colors[3*i + 1] = (7 * i % 11)/11.;
		colors[3*i + 2] = (9 * i % 11)/11.;
	}

	max_x = max_y = - HUGE_VAL;
	min_x = min_y = HUGE_VAL;
	for (j = 0; j < num_pts; j++) {
		if (max_x < pts[j].x) max_x = pts[j].x;
		if (min_x > pts[j].x) min_x = pts[j].x;
		if (max_y < pts[j].y) max_y = pts[j].y;
		if (min_y > pts[j].y) min_y = pts[j].y;
	}

	scale = W / (max_x - min_x);
	if (scale > H / (max_y - min_y))
		scale = H / (max_y - min_y);
	cx = (max_x + min_x) / 2;
	cy = (max_y + min_y) / 2;

	printf("%%!PS-Adobe-3.0\n%%%%BoundingBox: -5 -5 %d %d\n", W + 10, H + 10);
	printf( "/l {rlineto} def /m {rmoveto} def\n"
		"/c { .25 sub exch .25 sub exch .5 0 360 arc fill } def\n"
		"/s { moveto -2 0 m 2 2 l 2 -2 l -2 -2 l closepath "
		"	gsave 1 setgray fill grestore gsave 3 setlinewidth"
		" 1 setgray stroke grestore 0 setgray stroke }def\n"
	);

	for (i = 0; i < num_clusters; i++) {
		printf("%g %g %g setrgbcolor\n",
			colors[3*i], colors[3*i + 1], colors[3*i + 2]);

		for (j = 0; j < num_pts; j++) {
			if (pts[j].group != i) continue;
			printf("%.3f %.3f c\n",
				(pts[j].x - cx) * scale + W / 2,
				(pts[j].y - cy) * scale + H / 2);
		}
		printf("\n0 setgray %g %g s\n",
			(centroids[i].x - cx) * scale + W / 2,
			(centroids[i].y - cy) * scale + H / 2);
	}
	printf("\n%%%%EOF");

	free(colors);

	return;
}	/* end print_eps */

/*-------------------------------------------------------
	main
-------------------------------------------------------*/
int main()
{
	int		num_pts = NUMBER_OF_POINTS;
	int		num_clusters = NUMBER_OF_CLUSTERS;
	int		maxTimes = MAXIMUM_ITERATIONS;
	double	radius = RADIUS;
	POINT * pts;
	POINT * centroids;

	/* Generate the observations */
	pts = gen_xy(num_pts, radius);

	/* Cluster using the Lloyd algorithm and K-Means++ initial centroids. */
	centroids = lloyd(pts, num_pts, num_clusters, maxTimes);

	/* Print the results */
	print_eps(pts, num_pts, centroids, num_clusters);

	free(pts);
	free(centroids);

	return 0;
}


using .Hidato       # Note that the . here means to look locally for the module rather than in the libraries

const chessboard = """
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 """

const knightmoves = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]]

board, maxmoves, fixed, starts = hidatoconfigure(chessboard)
printboard(board, " 0", "  ")
hidatosolve(board, maxmoves, knightmoves, fixed, starts[1][1], starts[1][2], 1)
printboard(board)


import std.stdio, std.math, std.random, std.typecons, std.algorithm;

// On Windows this uses the printf from the Microsoft C runtime,
// that doesn't handle real type and some of the C99 format
// specifiers, but it's faster for bulk printing.
extern(C) nothrow int printf(const char*, ...);

struct Point {
    immutable double x, y; // Or float.
    size_t cluster;
}

Point[] generatePoints(in size_t nPoints,
                       in double radius,
                       ref Xorshift rnd)
in {
    assert(nPoints > 0);
    assert(radius > 0);
} out(result) {
    assert(result.length == nPoints);
    foreach (const ref p; result) {
        assert(p.cluster == 0);
        assert(!p.x.isNaN && !p.y.isNaN);
    }
} body {
    Point[] points;
    points.reserve(nPoints);

    // This is not a uniform 2D distribution.
    foreach (immutable i; 0 .. nPoints) {
        immutable r = uniform(0.0, radius, rnd);
        immutable ang = uniform(0.0, 2 * PI, rnd);
        points ~= Point(r * ang.cos, r * ang.sin); // Sincos?
    }

    return points;
}

struct ClusterCenter {
    double x, y;
    void opAssign(in ref Point p) pure nothrow @nogc {
        this.x = p.x;
        this.y = p.y;
    }
}

const(ClusterCenter)[] lloyd(Point[] points,
                             in size_t nclusters,
                             ref Xorshift rnd)
in {
    assert(points.length >= nclusters);
    assert(nclusters > 0);
    foreach (const ref p; points)
        assert(!p.x.isNaN && !p.y.isNaN);
} out(result) {
    assert(result.length == nclusters);
    foreach (const ref cc; result)
        assert(!cc.x.isNaN && !cc.y.isNaN);
} body {
    /// Distance and index of the closest cluster center.
    static Tuple!(size_t, double)
    nearestClusterCenter(in ref Point point,
                         in ClusterCenter[] centers) pure nothrow @nogc
    in {
        assert(centers.length > 0);
    } out(result) {
        assert(result[0] < centers.length);
        immutable ClusterCenter c = centers[result[0]];
        immutable d = (c.x - point.x) ^^ 2  +  (c.y - point.y) ^^ 2;
        assert(feqrel(result[1], d) > 45); // Arbitrary.
    } body {
        static double sqrDistance2D(in ref ClusterCenter a,
                                    in ref Point b) pure nothrow @nogc{
            return (a.x - b.x) ^^ 2 + (a.y - b.y) ^^ 2;
        }

        size_t minIndex = point.cluster;
        double minDist = double.max;

        foreach (immutable i, const ref cc; centers) {
            immutable d = sqrDistance2D(cc, point);
            if (minDist > d) {
                minDist = d;
                minIndex = i;
            }
        }

        return tuple(minIndex, minDist);
    }

    static void kMeansPP(Point[] points,
                         ClusterCenter[] centers,
                         ref Xorshift rnd)
    in {
        assert(points.length >= centers.length);
        assert(centers.length > 0);
    } body {
        centers[0] = points[uniform(0, $, rnd)];
        auto d = new double[points.length];

        foreach (immutable i; 1 .. centers.length) {
            double sum = 0;
            foreach (immutable j, const ref p; points) {
                d[j] = nearestClusterCenter(p, centers[0 .. i])[1];
                sum += d[j];
            }

            sum = uniform(0.0, sum, rnd);

            foreach (immutable j, immutable dj; d) {
                sum -= dj;
                if (sum > 0)
                    continue;
                centers[i] = points[j];
                break;
            }
        }

        foreach (ref p; points)
            // Implicit cast of Hconst!ClusterCenter
            // to ClusterCenter[].
            p.cluster = nearestClusterCenter(p, centers)[0];
    }

    auto centers = new ClusterCenter[nclusters];
    kMeansPP(points, centers, rnd);
    auto clusterSizes = new size_t[centers.length];

    size_t changed;
    do {
        // Find clusters centroids.
        centers[] = ClusterCenter(0, 0);
        clusterSizes[] = 0;

        foreach (immutable i, const ref p; points)
            with (centers[p.cluster]) {
                clusterSizes[p.cluster]++;
                x += p.x;
                y += p.y;
            }

        foreach (immutable i, ref cc; centers) {
            cc.x /= clusterSizes[i];
            cc.y /= clusterSizes[i];
        }

        // Find closest centroid of each point.
        changed = 0;
        foreach (ref p; points) {
            immutable minI = nearestClusterCenter(p, centers)[0];
            if (minI != p.cluster) {
                changed++;
                p.cluster = minI;
            }
        }
    // Stop when 99.9% of points are good.
    } while (changed > (points.length >> 10));

    return centers;
}

void printEps(in Point[] points, in ClusterCenter[] centers,
              in size_t W = 400, in size_t H = 400) nothrow
in {
    assert(points.length >= centers.length);
    assert(centers.length > 0);
    assert(W > 0 && H > 0);
    foreach (const ref p; points)
        assert(!p.x.isNaN && !p.y.isNaN);
    foreach (const ref cc; centers)
        assert(!cc.x.isNaN && !cc.y.isNaN);
} body {
    auto findBoundingBox() nothrow @nogc {
        double min_x, max_x, min_y, max_y;
        max_x = max_y = -double.max;
        min_x = min_y = double.max;

        foreach (const ref p; points) {
            if (max_x < p.x) max_x = p.x;
            if (min_x > p.x) min_x = p.x;
            if (max_y < p.y) max_y = p.y;
            if (min_y > p.y) min_y = p.y;
        }
        assert(max_x > min_x && max_y > min_y);

        return tuple(min(W / (max_x - min_x), H / (max_y - min_y)),
                     (max_x + min_x) / 2, (max_y + min_y) / 2);
    }
    //immutable (scale, cx, cy) = findBoundingBox();
    immutable sc_cx_cy = findBoundingBox();
    immutable double scale = sc_cx_cy[0];
    immutable double cx = sc_cx_cy[1];
    immutable double cy = sc_cx_cy[2];

    static immutable struct Color { immutable double r, g, b; }

    immutable size_t k = centers.length;
    Color[] colors;
    colors.reserve(centers.length);
    foreach (immutable i; 0 .. centers.length)
        colors ~= Color((3 * (i + 1) % k) / double(k),
                        (7 * i % k) / double(k),
                        (9 * i % k) / double(k));

    printf("%%!PS-Adobe-3.0\n%%%%BoundingBox: -5 -5 %d %d\n",
           W + 10, H + 10);

    printf("/l {rlineto} def /m {rmoveto} def\n" ~
           "/c { .25 sub exch .25 sub exch .5 0 360 arc fill } def\n" ~
           "/s { moveto -2 0 m 2 2 l 2 -2 l -2 -2 l closepath " ~
           "   gsave 1 setgray fill grestore gsave 3 setlinewidth" ~
           " 1 setgray stroke grestore 0 setgray stroke }def\n");

    foreach (immutable i, const ref cc; centers) {
        printf("%g %g %g setrgbcolor\n", colors[i].tupleof);

        foreach (const ref p; points) {
            if (p.cluster != i)
                continue;
            printf("%.3f %.3f c\n",
                   (p.x - cx) * scale + W / 2,
                   (p.y - cy) * scale + H / 2);
        }

        printf("\n0 setgray %g %g s\n",
               (cc.x - cx) * scale + W / 2,
               (cc.y - cy) * scale + H / 2);
    }

    "\n%%%%EOF".printf;
}

void main() {
    enum size_t nPoints = 100_000;
    enum size_t nClusters = 11; // k.
    auto rnd = 1.Xorshift; // For speed and repeatability.

    auto points = generatePoints(nPoints, 10, rnd);
    const clusterCenters = lloyd(points, nClusters, rnd);
    printEps(points, clusterCenters);
}


data class Square(val x : Int, val y : Int)

val board = Array(8 * 8, { Square(it / 8 + 1, it % 8 + 1) })
val axisMoves = arrayOf(1, 2, -1, -2)

fun <T> allPairs(a: Array<T>) = a.flatMap { i -> a.map { j -> Pair(i, j) } }

fun knightMoves(s : Square) : List<Square> {
    val moves = allPairs(axisMoves).filter{ Math.abs(it.first) != Math.abs(it.second) }
    fun onBoard(s : Square) = board.any {it == s}
    return moves.map { Square(s.x + it.first, s.y + it.second) }.filter(::onBoard)
}

fun knightTour(moves : List<Square>) : List<Square> {
    fun findMoves(s: Square) = knightMoves(s).filterNot { m -> moves.any { it == m } }
    val newSquare = findMoves(moves.last()).minBy { findMoves(it).size }
    return if (newSquare == null) moves else knightTour(moves + newSquare)
}

fun knightTourFrom(start : Square) = knightTour(listOf(start))

fun main(args : Array<String>) {
    var col = 0
    for ((x, y) in knightTourFrom(Square(1, 1))) {
        System.out.print("$x,$y")
        System.out.print(if (col == 7) "\n" else " ")
        col = (col + 1) % 8
    }
}


>type kmeanscluster
 function kmeanscluster (x: numerical, k: index)
     n=rows(x); m=cols(x);
     i=floor((0:k)/k*(n-1))+1;
     means=zeros(k,m);
     loop 1 to k;
         means[#]=sum(x[i[#]:(i[#+1]-1)]')'/(i[#+1]-i[#]);
     end;
     j=1:n;
     loop 1 to n;
         d=sum((x[#]-means)^2);
         j[#]=extrema(d')[2];
     end;
     repeat
         loop 1 to k;
             i=nonzeros(j==#);
             if cols(i)==0 then means[#]=1;
             else means[#]=(sum(x[i]')/cols(i))';
             endif;
         end;
         jold=j;
         loop 1 to n;
             d=sum((x[#]-means)^2);
             j[#]=extrema(d')[2];
         end;
         if all(jold==j) then break; endif;
     end
     return j
 endfunction


***********************************************************************
* KMPP - K-Means++ - Traditional data clustering with a special initialization
* Public Domain - This program may be used by any person for any purpose.
*
* Origin:
*    Hugo Steinhaus, 1956
*
* Refer to:
*    "kmeans++: the advantages of careful seeding"
*    David Arthur and Sergei Vassilvitskii
*    Proceedings of the eighteenth annual ACM-SIAM symposium
*      on Discrete algorithms, 2007
*
*____Variable_______I/O_______Description___________________Type_______
*    X(P,N)         In        Data points                   Real
*    P              In        Dimension of the data         Integer
*    N              In        Number of points              Integer
*    K              In        # clusters                    Integer
*    C(P,K)         Out       Center points of clusters     Real
*    Z(N)           Out       What cluster a point is in    Integer
*    WORK(N)        Neither                                 Real
*    IFAULT         Out       Error code                    Integer
************************************************************************
      SUBROUTINE KMPP (X, P, N, K, C, Z, WORK, IFAULT)

       IMPLICIT NONE
       INTEGER P, N, K, Z, IFAULT
       REAL X, C, WORK
       DIMENSION X(P,N), C(P,K), Z(N), WORK(N)

*               constants
       INTEGER ITER                 ! maximum iterations
       REAL BIG                     ! arbitrary large number
       PARAMETER (ITER = 1000,
     $            BIG = 1E33)

*                local variables
       INTEGER
     $         H,          ! count iterations
     $         I,          ! count points
     $         I1,         ! point marked as initial center
     $         J,          ! count dimensions
     $         L,          ! count clusters
     $         L0,         ! present cluster ID
     $         L1          ! new cluster ID

       REAL
     $      BEST,                 ! shortest distance to a center
     $      D2,                   ! squared distance
     $      TOT,                  ! a total
     $      W                     ! temp scalar

       LOGICAL CHANGE             ! whether any points have been reassigned

************************************************************************
*           Begin.
************************************************************************
       IFAULT = 0
       IF (K < 1 .OR. K > N) THEN       ! K out of bounds
         IFAULT = 3
         RETURN
       END IF
       DO I = 1, N                       ! clear Z
         Z(I) = 0
       END DO

************************************************************************
*        initial centers
************************************************************************
       DO I = 1, N
         WORK(I) = BIG
       END DO

       CALL RANDOM_NUMBER (W)
       I1 = MIN(INT(W * FLOAT(N)) + 1, N)  ! choose first center at random
       DO J = 1, P
         C(J,1) = X(J,I1)
       END DO

       DO L = 2, K                    ! initialize other centers
         TOT = 0.
         DO I = 1, N                     ! measure from each point
           BEST = WORK(I)
           D2 = 0.                         ! to prior center
           DO J = 1, P
             D2 = D2 + (X(J,I) - C(J,L-1)) **2  ! Squared Euclidean distance
             IF (D2 .GE. BEST) GO TO 10               ! needless to add to D2
           END DO                          ! next J
           IF (D2 < BEST) BEST = D2          ! shortest squared distance
           WORK(I) = BEST
  10       TOT = TOT + BEST             ! cumulative squared distance
         END DO                      ! next data point

************************************************************************
* Choose center with probability proportional to its squared distance
*     from existing centers.
************************************************************************
         CALL RANDOM_NUMBER (W)
         W = W * TOT    ! uniform at random over cumulative distance
         TOT = 0.
         DO I = 1, N
           I1 = I
           TOT = TOT + WORK(I)
           IF (TOT > W) GO TO 20
         END DO                ! next I
  20     CONTINUE
         DO J = 1, P         ! assign center
           C(J,L) = X(J,I1)
         END DO
       END DO               ! next center to initialize

************************************************************************
*                      main loop
************************************************************************
       DO H = 1, ITER
         CHANGE = .FALSE.

*             find nearest center for each point
         DO I = 1, N
           L0 = Z(I)
           L1 = 0
           BEST = BIG
           DO L = 1, K
             D2 = 0.
             DO J = 1, P
               D2 = D2 + (X(J,I) - C(J,L)) **2
               IF (D2 .GE. BEST) GO TO 30
             END DO
  30         CONTINUE
             IF (D2 < BEST) THEN           ! new nearest center
               BEST = D2
               L1 = L
             END IF
           END DO        ! next L

           IF (L0 .NE. L1) THEN
             Z(I) = L1                   !  reassign point
             CHANGE = .TRUE.
           END IF
         END DO         ! next I
         IF (.NOT. CHANGE) RETURN      ! success

************************************************************************
*           find cluster centers
************************************************************************
         DO L = 1, K              ! zero population
           WORK(L) = 0.
         END DO
         DO L = 1, K               ! zero centers
           DO J = 1, P
             C(J,L) = 0.
           END DO
         END DO

         DO I = 1, N
           L = Z(I)
           WORK(L) = WORK(L) + 1.             ! count
           DO J = 1, P
             C(J,L) = C(J,L) + X(J,I)         ! add
           END DO
         END DO

         DO L = 1, K
           IF (WORK(L) < 0.5) THEN          ! empty cluster check
             IFAULT = 1                     ! fatal error
             RETURN
           END IF
           W = 1. / WORK(L)
           DO J = 1, P
             C(J,L) = C(J,L) * W     ! multiplication is faster than division
           END DO
         END DO

       END DO                   ! next H
       IFAULT = 2                ! too many iterations
       RETURN

      END  ! of KMPP

************************************************************************
*             test program (extra credit #1)
************************************************************************
      PROGRAM TPEC1
       IMPLICIT NONE
       INTEGER N, P, K
       REAL TWOPI
       PARAMETER (N = 30 000,
     $            P = 2,
     $            K = 6,
     $            TWOPI = 6.2831853)
       INTEGER I, L, Z(N), IFAULT
       REAL X(P,N), C(P,K), R, THETA, W, WORK(N)

*             Begin
       CALL RANDOM_SEED()
       DO I = 1, N                      ! random points over unit circle
         CALL RANDOM_NUMBER (W)
         R = SQRT(W)                      ! radius
         CALL RANDOM_NUMBER (W)
         THETA = W * TWOPI                ! angle
         X(1,I) = R * COS(THETA)          ! Cartesian coordinates
         X(2,I) = R * SIN(THETA)
       END DO

*             Call subroutine
       CALL KMPP (X, P, N, K, C, Z, WORK, IFAULT)
       PRINT *, 'kmpp returns with error code ', IFAULT

*            Print lists of points in each cluster
       DO L = 1, K
         PRINT *, 'Cluster ', L, ' contains points: '
  10     FORMAT (I6, $)
  20     FORMAT ()
         DO I = 1, N
           IF (Z(I) .EQ. L) PRINT 10, I
         END DO
         PRINT 20
       END DO

*         Write CSV file with Y-coordinates in different columns by cluster
       OPEN (UNIT=1, FILE='tpec1.csv', STATUS='NEW', IOSTAT=IFAULT)
       IF (IFAULT .NE. 0) PRINT *, 'tpec1: trouble opening file'
  30   FORMAT (F8.4, $)
  40   FORMAT (',', $)
  50   FORMAT (F8.4)
       DO I = 1, N
         WRITE (UNIT=1, FMT=30, IOSTAT=IFAULT) X(1,I)
         IF (IFAULT .NE. 0) PRINT *, 'tpec1: trouble writing X-coord'
         DO L = 1, Z(I)                     ! one comma per cluster ID
           WRITE (UNIT=1, FMT=40, IOSTAT=IFAULT)
           IF (IFAULT .NE. 0) PRINT *, 'tpec1: trouble writing comma'
         END DO
         WRITE (UNIT=1, FMT=50, IOSTAT=IFAULT) X(2,I)
         IF (IFAULT .NE. 0) PRINT *, 'tpec1: trouble writing Y-coord'
       END DO

*           Write the centroids in the far column
       DO L = 1, K
         WRITE (UNIT=1, FMT=30, IOSTAT=IFAULT) C(1,L)
         IF (IFAULT .NE. 0) PRINT *, 'tpec1: trouble writing X-coord'
         DO I = 1, K+1
           WRITE (UNIT=1, FMT=40, IOSTAT=IFAULT)
           IF (IFAULT .NE. 0) PRINT *, 'tpec1: trouble writing comma'
         END DO
         WRITE (UNIT=1, FMT=50, IOSTAT=IFAULT) C(2,L)
         IF (IFAULT .NE. 0) PRINT *, 'tpec1: trouble writing Y-coord'
       END DO
       CLOSE (UNIT=1)

      END  ! of test program


10 mode 1:defint a-z
20 input "Board size: ",size
30 input "Start position: ",a$
40 x=asc(mid$(a$,1,1))-96
50 y=val(mid$(a$,2,1))
60 dim play(size,size)
70 for q=1 to 8
80 read dx(q),dy(q)
90 next
100 data 2,1,1,2,-1,2,-2,1,-2,-1,-1,-2,1,-2,2,-1
110 pen 0:paper 1
120 for q=1 to size
130 locate 3*q+1,24-size
140 print chr$(96+q);
150 locate 3*(size+1)+1,26-q
160 print using "#"; q;
170 next
180 pen 1:paper 0
190 ' main loop
200 n=n+1
210 play(x,y)=n
220 locate 3*x,26-y
230 print using "##"; n;
240 if n=size*size then call &bb06:end
250 nmov=100
260 for q=1 to 8
270 xc=x+dx(q)
280 yc=y+dy(q)
290 gosub 360
300 if nm<nmov then nmov=nm:qm=q
310 next
320 x=x+dx(qm)
330 y=y+dy(qm)
340 goto 200
350 ' find moves
360 if xc<1 or yc<1 or xc>size or yc>size then nm=1000:return
370 if play(xc,yc) then nm=2000:return
380 nm=0
390 for q2=1 to 8
400 xt=xc+dx(q2)
410 yt=yc+dy(q2)
420 if xt<1 or yt<1 or xt>size or yt>size then 460
430 if play(xt,yt) then 460
440 nm=nm+1
450 ' skip this move
460 next
470 return


package main

import (
    "fmt"
    "image"
    "image/color"
    "image/draw"
    "image/png"
    "math"
    "math/rand"
    "os"
    "time"
)

type r2 struct {
    x, y float64
}

type r2c struct {
    r2
    c int // cluster number
}

// kmpp implements K-means++, satisfying the basic task requirement
func kmpp(k int, data []r2c) {
    kMeans(data, kmppSeeds(k, data))
}

// kmppSeeds is the ++ part.
// It generates the initial means for the k-means algorithm.
func kmppSeeds(k int, data []r2c) []r2 {
    s := make([]r2, k)
    s[0] = data[rand.Intn(len(data))].r2
    d2 := make([]float64, len(data))
    for i := 1; i < k; i++ {
        var sum float64
        for j, p := range data {
            _, dMin := nearest(p, s[:i])
            d2[j] = dMin * dMin
            sum += d2[j]
        }
        target := rand.Float64() * sum
        j := 0
        for sum = d2[0]; sum < target; sum += d2[j] {
            j++
        }
        s[i] = data[j].r2
    }
    return s
}

// nearest finds the nearest mean to a given point.
// return values are the index of the nearest mean, and the distance from
// the point to the mean.
func nearest(p r2c, mean []r2) (int, float64) {
    iMin := 0
    dMin := math.Hypot(p.x-mean[0].x, p.y-mean[0].y)
    for i := 1; i < len(mean); i++ {
        d := math.Hypot(p.x-mean[i].x, p.y-mean[i].y)
        if d < dMin {
            dMin = d
            iMin = i
        }
    }
    return iMin, dMin
}

// kMeans algorithm.  Lloyd's
func kMeans(data []r2c, mean []r2) {
    // initial assignment
    for i, p := range data {
        cMin, _ := nearest(p, mean)
        data[i].c = cMin
    }
    mLen := make([]int, len(mean))
    for {
        // update means
        for i := range mean {
            mean[i] = r2{}
            mLen[i] = 0
        }
        for _, p := range data {
            mean[p.c].x += p.x
            mean[p.c].y += p.y
            mLen[p.c]++
        }
        for i := range mean {
            inv := 1 / float64(mLen[i])
            mean[i].x *= inv
            mean[i].y *= inv
        }
        // make new assignments, count changes
        var changes int
        for i, p := range data {
            if cMin, _ := nearest(p, mean); cMin != p.c {
                changes++
                data[i].c = cMin
            }
        }
        if changes == 0 {
            return
        }
    }
}

// parameters for extra credit exercises
type ecParam struct {
    k          int
    nPoints    int
    xBox, yBox int
    stdv       int
}

// extra credit 1 and 2:
func main() {
    ec := &ecParam{6, 30000, 300, 200, 30}

    origin, data := genECData(ec)
    vis(ec, data, "origin")
    fmt.Println("Data set origins:")
    fmt.Println("    x      y")
    for _, o := range origin {
        fmt.Printf("%5.1f  %5.1f\n", o.x, o.y)
    }

    kmpp(ec.k, data)

    fmt.Println(
        "\nCluster centroids, mean distance from centroid, number of points:")
    fmt.Println("    x      y  distance  points")
    cent := make([]r2, ec.k)
    cLen := make([]int, ec.k)
    inv := make([]float64, ec.k)
    for _, p := range data {
        cent[p.c].x += p.x
        cent[p.c].y += p.y
        cLen[p.c]++
    }
    for i, iLen := range cLen {
        inv[i] = 1 / float64(iLen)
        cent[i].x *= inv[i]
        cent[i].y *= inv[i]
    }
    dist := make([]float64, ec.k)
    for _, p := range data {
        dist[p.c] += math.Hypot(p.x-cent[p.c].x, p.y-cent[p.c].y)
    }
    for i, iLen := range cLen {
        fmt.Printf("%5.1f  %5.1f  %8.1f  %6d\n",
            cent[i].x, cent[i].y, dist[i]*inv[i], iLen)
    }
    vis(ec, data, "clusters")
}

// genECData generates random data for extra credit tasks.
// k origin points are randomly selected in a bounding box.
// nPoints/k coordinates are then generated for each origin point.
// The x and y coordinates of the data are normally distributed
// with standard deviation stdv.  Thus data coordinates are not
// constrained to the origin box; they can range to +/- max float64.
func genECData(ec *ecParam) (orig []r2, data []r2c) {
    rand.Seed(time.Now().UnixNano())
    orig = make([]r2, ec.k)
    data = make([]r2c, ec.nPoints)
    for i, n := 0, 0; i < ec.k; i++ {
        x := rand.Float64() * float64(ec.xBox)
        y := rand.Float64() * float64(ec.yBox)
        orig[i] = r2{x, y}
        for j := ec.nPoints / ec.k; j > 0; j-- {
            data[n].x = rand.NormFloat64()*float64(ec.stdv) + x
            data[n].y = rand.NormFloat64()*float64(ec.stdv) + y
            data[n].c = i
            n++
        }
    }
    return
}

// vis writes a .png for extra credit 2.
func vis(ec *ecParam, data []r2c, fn string) {
    colors := make([]color.NRGBA, ec.k)
    for i := range colors {
        i3 := i * 3
        third := i3 / ec.k
        frac := uint8((i3 % ec.k) * 255 / ec.k)
        switch third {
        case 0:
            colors[i] = color.NRGBA{frac, 255 - frac, 0, 255}
        case 1:
            colors[i] = color.NRGBA{0, frac, 255 - frac, 255}
        case 2:
            colors[i] = color.NRGBA{255 - frac, 0, frac, 255}
        }
    }
    bounds := image.Rect(-ec.stdv, -ec.stdv, ec.xBox+ec.stdv, ec.yBox+ec.stdv)
    im := image.NewNRGBA(bounds)
    draw.Draw(im, bounds, image.NewUniform(color.White), image.ZP, draw.Src)
    fMinX := float64(bounds.Min.X)
    fMaxX := float64(bounds.Max.X)
    fMinY := float64(bounds.Min.Y)
    fMaxY := float64(bounds.Max.Y)
    for _, p := range data {
        imx := math.Floor(p.x)
        imy := math.Floor(float64(ec.yBox) - p.y)
        if imx >= fMinX && imx < fMaxX && imy >= fMinY && imy < fMaxY {
            im.SetNRGBA(int(imx), int(imy), colors[p.c])
        }
    }
    f, err := os.Create(fn + ".png")
    if err != nil {
        fmt.Println(err)
        return
    }
    err = png.Encode(f, im)
    if err != nil {
        fmt.Println(err)
    }
    err = f.Close()
    if err != nil {
        fmt.Println(err)
    }
}


N = 8

moves = { {1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2} }

function Move_Allowed( board, x, y )
    if board[x][y] >= 8 then return false end

    local new_x, new_y = x + moves[board[x][y]+1][1], y + moves[board[x][y]+1][2]
    if new_x >= 1 and new_x <= N and new_y >= 1 and new_y <= N and board[new_x][new_y] == 0 then return true end

    return false
end

board = {}
for i = 1, N do
    board[i] = {}
    for j = 1, N do
        board[i][j] = 0
    end
end

x, y = 1, 1

lst = {}
lst[1] = { x, y }

repeat
    if Move_Allowed( board, x, y ) then
        board[x][y] = board[x][y] + 1
        x, y = x+moves[board[x][y]][1], y+moves[board[x][y]][2]
        lst[#lst+1] = { x, y }
    else
        if board[x][y] >= 8 then
            board[x][y] = 0
            lst[#lst] = nil
            if #lst == 0 then
                print "No solution found."
                os.exit(1)
            end
            x, y = lst[#lst][1], lst[#lst][2]
        end
        board[x][y] = board[x][y] + 1
    end
until #lst == N^2

last = lst[1]
for i = 2, #lst do
    print( string.format( "%s%d - %s%d", string.sub("ABCDEFGH",last[1],last[1]), last[2], string.sub("ABCDEFGH",lst[i][1],lst[i][1]), lst[i][2] ) )
    last = lst[i]
end


{-# LANGUAGE Strict,FlexibleInstances #-}
module KMeans where

import Control.Applicative
import Control.Monad.Random
import Data.List (minimumBy, genericLength, transpose)
import Data.Ord (comparing)
import qualified Data.Map.Strict as M

type Vec = [Float]
type Cluster = [Vec]

kMeansIteration :: [Vec] -> [Vec] -> [Cluster]
kMeansIteration pts = clusterize . fixPoint iteration
  where
    iteration = map centroid . clusterize

    clusterize centroids = M.elems $ foldr add m0 pts
      where add x = M.insertWith (++) (centroids `nearestTo` x) [x]
            m0 = M.unions $ map (`M.singleton` []) centroids

nearestTo :: [Vec] -> Vec -> Vec
nearestTo pts x =  minimumBy (comparing (distance x)) pts

distance :: Vec -> Vec -> Float
distance a b = sum $ map (^2) $ zipWith (-) a b

centroid :: [Vec] -> Vec
centroid = map mean . transpose
  where  mean pts = sum pts / genericLength pts

fixPoint :: Eq a => (a -> a) -> a -> a
fixPoint f x = if x == fx then x else fixPoint f fx where fx = f x

-- initial sampling

kMeans :: MonadRandom m => Int -> [Vec] -> m [Cluster]
kMeans n pts = kMeansIteration pts <$> take n <$> randomElements pts

kMeansPP :: MonadRandom m => Int -> [Vec] -> m [Cluster]
kMeansPP n pts = kMeansIteration pts <$> centroids
  where centroids = iterate (>>= nextCentroid) x0 !! (n-1)
        x0 = take 1 <$> randomElements pts
        nextCentroid cs = (: cs) <$> fromList (map (weight cs) pts)
        weight cs x = (x, toRational $ distance x (cs `nearestTo` x))

randomElements :: MonadRandom m => [a] -> m [a]
randomElements pts = map (pts !!) <$> getRandomRs (0, length pts)

-- sample cluster generation

instance (RandomGen g, Monoid m) => Monoid (Rand g m) where
   mempty = pure mempty
   mappend = liftA2 mappend

mkCluster n s m = take n . transpose <$> mapM randomsAround m
  where randomsAround x0 = map (\x -> x0+s*atanh x) <$> getRandomRs (-1,1)


Function KnightTour$(StartW=1, StartH=1){
    def boolean swapH, swapV=True
    if startW<=4 then swapH=true: StartW=8+1-StartW
    if startH>4 then swapV=False: StartH=8+1-StartH
    Let final=8*8, last=final-1, HighValue=final+1
    Dim Board(1 to 8, 1 to 8), Moves(1 to 8, 1 to 8)=HighValue
    f=stack:=1,2,3,4,5,6,7,8
    if 8-StartW=2 and StartH=2 then stack f {shift 1,-8}
    Function KnightMove(x,w,h) {
        a=2:b=1:z=1:p=1
        if x mod 2=1 then swap a,b
        if x>2 then p-! : if x>4 then swap z, p : if x>6 then p-!
        w+=z*a
        h+=p*b
        if w>=1 and w<=8 and h>=1 and h<=8 then =(w, h) else =(,)
    }
    For j=1 to 8 :For i=1 to 8
    s=stack
    For k=1 to 8
        m=KnightMove(stackitem(f, k),i, j)
        if len(m)>1 then Stack s {data m}
    Next : Board(i,j)=s : Next
           stack f {shift 1,-8}
    Next
    For i=1 to 8 :For j=1 to 8
    s=Board(i, j)
    if len(s)>2 then
        so=queue
        For k=1 to len(s)
            m=stackitem(s, k)
            Append so, Len(Board(m#val(0), m#val(1))) :=m
        Next
        sort ascending so as number
        s=stack
        stack s {for k=0 to len(so)-1:data so(k!):next}
        Board(i,j)=s
    end if
    Next : Next
    s= Board(StartW, StartH)
    n=0
    BackTrack=Stack
    Moves=1
    Moves(StartW, StartH)=1
    Repeat
    n++
    While n>len(s) {
        if Len(BackTrack)=0 then Print "Break", moves : Break
        Moves--
        Stack BackTrack {Read s, n}
        m=stackitem(s, n)
        Moves(m#val(0), m#val(1))=HighValue
        n++
    }
    m=stackitem(s, n)
    w=m#val(0)
    h=m#val(1)
    if Moves(w, h)>=Moves then
        if Moves<last then
        s1=Board(w, h) :ii=-1
        for i=1 to len(s1){m1=stackitem(s1, i) :if Moves(m1#val(0),m1#val(1))>moves then ii=i-1 : exit
        }
        if ii>=0 then
            Moves++
            Moves(w,h)=Moves
            Stack BackTrack {Push n, s}
            s=s1: n=ii
        end if
        else
            Moves++
            Moves(w,h)=Moves
        end if
    end if
    until Moves=final
    Document export$
    Inventory Tour
    letters=stack:="a","b","c","d","e","f","g","h"
    f=stack:=1,2,3,4,5,6,7,8
    if swapV Else stack f {Shift 1,-8}
    if swapH then stack letters {Shift 1,-8}
    For j=1 to 8:For i=1 to 8
        Append Tour, Moves(i,j) :=stackitem$(letters, i)+str$(stackitem(f, j),"")
    Next : Next
    Sort ascending Tour as number
    one=each(Tour)
    While one {
        export$=Eval$(one)
        if not one^=last then export$="->"
        If (one^+1) mod 8=0 then
        export$={
        }
        End if
    }
    =export$
}
Document ex$
ex$= {Knight's Tour from a1
}+KnightTour$()+{Knight's Tour from h1
}+KnightTour$(8,1)+{Knight's Tour from a8
}+KnightTour$(1, 8)+{Knight's Tour from h8
}+KnightTour$(8, 8)
Clipboard ex$
Report ex$


#! /bin/sh
exec huginn -E "${0}" "${@}"
#! huginn

import Algorithms as algo;
import Mathematics as math;
import OperatingSystem as os;

class Color { r = 0.; g = 0.; b = 0.; }
class Point { x = 0.; y = 0.; group = -1; }

k_means_initial_centroids( points_, clusterCount_ ) {
	centroids = [];
	discreteRng = math.Randomizer( math.Randomizer.DISTRIBUTION.DISCRETE, 0, size( points_ ) - 1 );
	uniformRng = math.Randomizer( math.Randomizer.DISTRIBUTION.UNIFORM, 0.0, 1.0 );
	centroids.push( copy( points_[discreteRng.next()] ) );
	for ( i : algo.range( clusterCount_ - 1 ) ) {
		distances = [];
		sum = 0.0;
		for ( p : points_ ) {
			shortestDist = math.INFINITY;
			for ( c : centroids ) {
				dx = c.x - p.x;
				dy = c.y - p.y;
				d = dx * dx + dy * dy;
				if ( d < shortestDist ) {
					shortestDist = d;
				}
			}
			distances.push( ( shortestDist, p ) );
			sum += shortestDist;
		}
		sum *= uniformRng.next();
		for ( d : distances ) {
			sum -= d[0];
			if ( sum <= 0.0 ) {
				centroids.push( copy( d[1] ) );
				break;
			}
		}
	}
	for ( i, c : algo.enumerate( centroids ) ) {
		c.group = i;
	}
	return ( centroids );
}

k_means( points_, clusterCount_, maxError_ = 0.001, maxIter_ = 100 ) {
	centroids = k_means_initial_centroids( points_, clusterCount_ );
	pointCount = real( size( points_ ) );
	for ( iter : algo.range( maxIter_ ) ) {
		updated = 0.0;
		for ( p : points_ ) {
			shortestDist = math.INFINITY;
			g = 0;
			for ( c : centroids ) {
				dx = c.x - p.x;
				dy = c.y - p.y;
				dist = dx * dx + dy * dy;
				if ( dist < shortestDist ) {
					shortestDist = dist;
					g = c.group;
				}
			}
			if ( p.group != g ) {
				p.group = g;
				updated += 1.0;
			}
		}
		for ( c : centroids ) {
			n = 0;
			c.x = 0.;
			c.y = 0.;
			for ( p : points_ ) {
				if ( p.group == c.group ) {
					c.x += p.x;
					c.y += p.y;
					n += 1;
				}
			}
			if ( n > 0 ) {
				c.x /= real( n );
				c.y /= real( n );
			}
		}
		err = updated / pointCount;
		os.stderr().write_line( "err = {}\n".format( err ) );
		if ( err < maxError_ ) {
			os.stderr().write_line( "done in {} iterations\n".format( iter ) );
			break;
		}
	}
	return ( centroids );
}

gen_points( numPoints_ ) {
	phiGen = math.Randomizer( math.Randomizer.DISTRIBUTION.UNIFORM, 0., 2. * math.pi( real ) );
	rGen = math.Randomizer( math.Randomizer.DISTRIBUTION.TRIANGLE, 0., 1., 1. );
	points = [];
	for ( i : algo.range( numPoints_ ) ) {
		phi = phiGen.next();
		r = rGen.next();
		points.push( Point( r * math.cosinus( phi ), r * math.sinus( phi ) ) );
	}
	return ( points );
}

import ProgramOptions as po;

main( argv_ ) {
	poh = po.Handler( "k-means++", "k-means++ clustering algorithm demo" );
	poh.add_option(
		name: "numPoints,N",
		requirement: po.VALUE_REQUIREMENT.REQUIRED,
		help: "number of points",
		conversion: integer,
		valueName: "num",
		defaultValue: 30000
	);
	poh.add_option(
		name: "numClusters,C",
		requirement: po.VALUE_REQUIREMENT.REQUIRED,
		help: "number of custers",
		conversion: integer,
		valueName: "num",
		defaultValue: 7
	);
	poh.add_option(
		name: "maxIterations,I",
		requirement: po.VALUE_REQUIREMENT.REQUIRED,
		help: "maximum number of iterations for the algorithm to run",
		conversion: integer,
		valueName: "num",
		defaultValue: 100
	);
	poh.add_option(
		name: "maxInvalidRatio,R",
		requirement: po.VALUE_REQUIREMENT.REQUIRED,
		help: "maximum ratio of points that are still assigned to invalid centroids",
		conversion: real,
		valueName: "num",
		defaultValue: 0.001
	);
	poh.add_option(
		name: "help,H",
		requirement: po.VALUE_REQUIREMENT.NONE,
		help: "show help information and stop"
	);
	poh.add_option(
		name: "verbose,v",
		requirement: po.VALUE_REQUIREMENT.NONE,
		help: "show more info about program execution"
	);
	parsed = poh.command_line( argv_ );
	if ( parsed == none ) {
		return ( 1 );
	}
	if ( parsed.options["help"] ) {
		print( poh.help_string() + "\n" );
		return ( 0 );
	}
	if ( parsed.options["verbose"] ) {
		os.stderr().write_line( string( parsed ) + "\n" );
	}
	points = gen_points( parsed.options["numPoints"] );
	print_eps(
		points,
		k_means(
			points,
			parsed.options["numClusters"],
			parsed.options["maxInvalidRatio"],
			parsed.options["maxIterations"]
		)
	);
}

print_eps( points, cluster_centers, W = 400, H = 400 ) {
	colors = [];
	for ( i : algo.range( size( cluster_centers ) ) ) {
		ii = real( i );
		colors.push(
			Color(
				( 3. * ( ii + 1. ) % 11. ) / 11.0,
				( 7. * ii % 11. ) / 11.0,
				( 9. * ii % 11. ) / 11.0
			)
		);
	}
	max_x = max_y = - math.INFINITY;
	min_x = min_y = math.INFINITY;
	for ( p : points ) {
		if ( max_x < p.x ) { max_x = p.x; }
		if ( min_x > p.x ) { min_x = p.x; }
		if ( max_y < p.y ) { max_y = p.y; }
		if ( min_y > p.y ) { min_y = p.y; }
	}
	scale = math.min( real( W ) / ( max_x - min_x ), real( H ) / ( max_y - min_y ) );
	cx = ( max_x + min_x ) / 2.;
	cy = ( max_y + min_y ) / 2.;
	print( "%!PS-Adobe-3.0\n%%BoundingBox: -5 -5 {} {}\n".format( W + 10, H + 10 ) );
	print(
		"/l {rlineto} def /m {rmoveto} def\n"
		"/c { .25 sub exch .25 sub exch .5 0 360 arc fill } def\n"
		"/s { moveto -2 0 m 2 2 l 2 -2 l -2 -2 l closepath "
		"   gsave 1 setgray fill grestore gsave 3 setlinewidth"
		" 1 setgray stroke grestore 0 setgray stroke }def\n"
	);
	for ( i, cc : algo.enumerate( cluster_centers ) ) {
		print( "{} {} {} setrgbcolor\n".format( colors[i].r, colors[i].g, colors[i].b ) );
		for ( p : points ) {
			if ( p.group != i ) {
				continue;
			}
			print( "{:.3f} {:.3f} c\n".format( ( p.x - cx ) * scale + real( W ) / 2., ( p.y - cy ) * scale + real( H ) / 2. ) );
		}
		print("\n0 setgray {} {} s\n".format( ( cc.x - cx ) * scale + real( W ) / 2., ( cc.y - cy ) * scale + real( H ) / 2. ) );
	}
	print( "\n%%%%EOF\n" );
}


   NB.  Selection of initial centroids, per K-means++
   initialCentroids     =:  (] , randomCentroid)^:(<:@:]`(,:@:[email protected]:[))~
     seedCentroid       =:  {~ [email protected]#
     randomCentroid     =:  [ {~ [: wghtProb [: <./ distance/~
       distance         =:  +/&.:*:@:-"1  NB.  Extra credit #3 (N-dimensional is the same as 2-dimensional in J)
       wghtProb         =:  1&$: : ((%{:)@:(+/\)@:] I. [ [email protected]$ 0:)"0 1 NB.  Due to Roger Hui http://j.mp/lj5Pnt

   NB.  Having selected the initial centroids, the standard K-means algo follows
   centroids            =:  ([ mean/.~ closestCentroid)^:(]`_:`initialCentroids)
     closestCentroid    =:  [: (i.<./)"1 distance/
     mean               =:  +/ % #


import java.util.Random;

public class KMeansWithKpp{
		// Variables Needed
		public Point[] points;
		public Point[] centroids;
		Random rand;
		public int n;
		public int k;

		// hide default constructor
		private KMeansWithKpp(){
		}

		KMeansWithKpp(Point[] p, int clusters){
				points = p;
				n = p.length;
				k = Math.max(1, clusters);
				centroids = new Point[k];
				rand = new Random();
		}

		private static double distance(Point a, Point b){
				return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
		}

		private static int nearest(Point pt, Point[] others, int len){
				double minD = Double.MAX_VALUE;
				int index = pt.group;
				len = Math.min(others.length, len);
				double dist;
				for (int i = 0; i < len; i++) {
						if (minD > (dist = distance(pt, others[i]))) {
								minD = dist;
								index = i;
						}
				}
				return index;
		}

		private static double nearestDistance(Point pt, Point[] others, int len){
				double minD = Double.MAX_VALUE;
				len = Math.min(others.length, len);
				double dist;
				for (int i = 0; i < len; i++) {
						if (minD > (dist = distance(pt, others[i]))) {
								minD = dist;
						}
				}
				return minD;
		}

		private void kpp(){
				centroids[0] = points[rand.nextInt(n)];
				double[] dist = new double[n];
				double sum = 0;
				for (int i = 1; i < k; i++) {
						for (int j = 0; j < n; j++) {
								dist[j] = nearestDistance(points[j], centroids, i);
								sum += dist[j];
						}
						sum = (sum * rand.nextInt(Integer.MAX_VALUE)) / Integer.MAX_VALUE;
						for (int j = 0; j < n; j++) {
								if ((sum -= dist[j]) > 0)
										continue;
								centroids[i].x = points[j].x;
								centroids[i].y = points[j].y;
						}
				}
				for (int i = 0; i < n; i++) {
						points[i].group = nearest(points[i], centroids, k);
				}
		}

		public void kMeans(int maxTimes){
				if (k == 1 || n <= 0) {
						return;
				}
				if(k >= n){
						for(int i =0; i < n; i++){
								points[i].group = i;
						}
						return;
				}
				maxTimes = Math.max(1, maxTimes);
				int changed;
				int bestPercent = n/1000;
				int minIndex;
				kpp();
				do {
						for (Point c : centroids) {
								c.x = 0.0;
								c.y = 0.0;
								c.group = 0;
						}
						for (Point pt : points) {
								if(pt.group < 0 || pt.group > centroids.length){
										pt.group = rand.nextInt(centroids.length);
								}
								centroids[pt.group].x += pt.x;
								centroids[pt.group].y = pt.y;
								centroids[pt.group].group++;
						}
						for (Point c : centroids) {
								c.x /= c.group;
								c.y /= c.group;
						}
						changed = 0;
						for (Point pt : points) {
								minIndex = nearest(pt, centroids, k);
								if (k != pt.group) {
										changed++;
										pt.group = minIndex;
								}
						}
						maxTimes--;
				} while (changed > bestPercent && maxTimes > 0);
		}
}

// A class for point(x,y) in plane

class Point{
		public double x;
		public double y;
		public int group;

		Point(){
				x = y = 0.0;
				group = 0;
		}

		/*
			Generates a random points on 2D Plane within given X-axis and Y-axis
		 */
		public Point[] getRandomPlaneData(double minX, double maxX, double minY, double maxY, int size){
				if (size <= 0)
						return null;
				double xdiff, ydiff;
				xdiff = maxX - minX;
				ydiff = maxY - minY;
				if (minX > maxX) {
						xdiff = minX - maxX;
						minX = maxX;
				}
				if (maxY < minY) {
						ydiff = minY - maxY;
						minY = maxY;
				}
				Point[] data = new Point[size];
				Random rand = new Random();
				for (int i = 0; i < size; i++) {
						data[i].x = minX + (xdiff * rand.nextInt(Integer.MAX_VALUE)) / Integer.MAX_VALUE;
						data[i].y = minY + (ydiff * rand.nextInt(Integer.MAX_VALUE)) / Integer.MAX_VALUE;
				}
				return data;
		}

		/*
	             Generate Random Polar Coordinates within given radius
		 */
		public Point[] getRandomPolarData(double radius, int size){
				if (size <= 0) {
						return null;
				}
				Point[] data = new Point[size];
				double radi, arg;
				Random rand = new Random();
				for (int i = 0; i < size; i++) {
						radi = (radius * rand.nextInt(Integer.MAX_VALUE)) / Integer.MAX_VALUE;
						arg = (2 * Math.PI * rand.nextInt(Integer.MAX_VALUE)) / Integer.MAX_VALUE;
						data[i].x = radi * Math.cos(arg);
						data[i].y = radi * Math.sin(arg);
				}
				return data;
		}

}


divert(-1)

----------------------------------------------------------------------

This is free and unencumbered software released into the public
domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org/>

----------------------------------------------------------------------

Find a Knight's tour, via Warnsdorff's rule.

For very old or 'Heirloom' m4, you may need to increase the sizes of
internal structures, with, say,

    m4 -S 1000 -B 100000 knights_tour.m4

But I would use one of OpenBSD m4, GNU m4, etc., instead.

----------------------------------------------------------------------

dnl  Get a random number from 0 to one less than $1.
dnl  (Note that this is not a very good RNG. Also it writes a file.)
define(`randnum',
  `syscmd(`echo $RANDOM > __random_number__')eval(include(__random_number__) % ( $1 ))')

dnl  The left deconstructors for strings.
define(`string_car',`substr($1,0,1)')
define(`string_cdr',`substr($1,1)')

dnl   Algebraic notation to 'i0j0', with i the ranks and j the files. Bad
dnl   algebraic notation gets tranformed to '99999999'.
define(`alg2ij',
  `ifelse($1,`a1',`1010',$1,`a2',`2010',$1,`a3',`3010',$1,`a4',`4010',
          $1,`a5',`5010',$1,`a6',`6010',$1,`a7',`7010',$1,`a8',`8010',
          $1,`b1',`1020',$1,`b2',`2020',$1,`b3',`3020',$1,`b4',`4020',
          $1,`b5',`5020',$1,`b6',`6020',$1,`b7',`7020',$1,`b8',`8020',
          $1,`c1',`1030',$1,`c2',`2030',$1,`c3',`3030',$1,`c4',`4030',
          $1,`c5',`5030',$1,`c6',`6030',$1,`c7',`7030',$1,`c8',`8030',
          $1,`d1',`1040',$1,`d2',`2040',$1,`d3',`3040',$1,`d4',`4040',
          $1,`d5',`5040',$1,`d6',`6040',$1,`d7',`7040',$1,`d8',`8040',
          $1,`e1',`1050',$1,`e2',`2050',$1,`e3',`3050',$1,`e4',`4050',
          $1,`e5',`5050',$1,`e6',`6050',$1,`e7',`7050',$1,`e8',`8050',
          $1,`f1',`1060',$1,`f2',`2060',$1,`f3',`3060',$1,`f4',`4060',
          $1,`f5',`5060',$1,`f6',`6060',$1,`f7',`7060',$1,`f8',`8060',
          $1,`g1',`1070',$1,`g2',`2070',$1,`g3',`3070',$1,`g4',`4070',
          $1,`g5',`5070',$1,`g6',`6070',$1,`g7',`7070',$1,`g8',`8070',
          $1,`h1',`1080',$1,`h2',`2080',$1,`h3',`3080',$1,`h4',`4080',
          $1,`h5',`5080',$1,`h6',`6080',$1,`h7',`7080',$1,`h8',`8080',
          `99999999')')

dnl   The reverse of alg2ij. Bad 'i0j0' get transformed to 'z0'.
define(`ij2alg',
  `ifelse($1,`1010',`a1',$1,`2010',`a2',$1,`3010',`a3',$1,`4010',`a4',
          $1,`5010',`a5',$1,`6010',`a6',$1,`7010',`a7',$1,`8010',`a8',
          $1,`1020',`b1',$1,`2020',`b2',$1,`3020',`b3',$1,`4020',`b4',
          $1,`5020',`b5',$1,`6020',`b6',$1,`7020',`b7',$1,`8020',`b8',
          $1,`1030',`c1',$1,`2030',`c2',$1,`3030',`c3',$1,`4030',`c4',
          $1,`5030',`c5',$1,`6030',`c6',$1,`7030',`c7',$1,`8030',`c8',
          $1,`1040',`d1',$1,`2040',`d2',$1,`3040',`d3',$1,`4040',`d4',
          $1,`5040',`d5',$1,`6040',`d6',$1,`7040',`d7',$1,`8040',`d8',
          $1,`1050',`e1',$1,`2050',`e2',$1,`3050',`e3',$1,`4050',`e4',
          $1,`5050',`e5',$1,`6050',`e6',$1,`7050',`e7',$1,`8050',`e8',
          $1,`1060',`f1',$1,`2060',`f2',$1,`3060',`f3',$1,`4060',`f4',
          $1,`5060',`f5',$1,`6060',`f6',$1,`7060',`f7',$1,`8060',`f8',
          $1,`1070',`g1',$1,`2070',`g2',$1,`3070',`g3',$1,`4070',`g4',
          $1,`5070',`g5',$1,`6070',`g6',$1,`7070',`g7',$1,`8070',`g8',
          $1,`1080',`h1',$1,`2080',`h2',$1,`3080',`h3',$1,`4080',`h4',
          $1,`5080',`h5',$1,`6080',`h6',$1,`7080',`h7',$1,`8080',`h8',
          `z0')')

dnl   Move a knight from one square to another by an ij-vector. Both input
dnl   and output are algebraic notation. If the move is illegal, it comes
dnl   out as 'z0'.
define(`move_by',`ij2alg(eval(alg2ij($3) + 1000 * ( $1 ) + 10 * ( $2 )))')

dnl  For example, a1d3c5 -> 3
define(`path_length',`eval(len($1) / 2)')

dnl  The left deconstructors for paths.
define(`path_car',`substr($1,0,2)')
define(`path_cdr',`substr($1,2)')

dnl  The right deconstructors for paths.
define(`path_last',`substr($1,eval(len($1) - 2))')
define(`path_drop_last',`substr($1,0,eval(len($1) - 2))')

dnl  Extract the nth position from the path.
define(`path_nth',`substr($1,eval(( $2 ) * 2),2)')

define(`random_move',`path_nth($1,randnum(path_length($1)))')

dnl  Is the position $1 contained in the path $2?
define(`path_contains',`ifelse(index($2,$1),-1,0,1)')

dnl  Find all moves from position $1 that are not already in
dnl  the path $2.
define(`possible_moves',
`ifelse(path_contains(move_by(1,2,$1),$2`'z0),`0',move_by(1,2,$1))`'dnl
ifelse(path_contains(move_by(2,1,$1),$2`'z0),`0',move_by(2,1,$1))`'dnl
ifelse(path_contains(move_by(1,-2,$1),$2`'z0),`0',move_by(1,-2,$1))`'dnl
ifelse(path_contains(move_by(2,-1,$1),$2`'z0),`0',move_by(2,-1,$1))`'dnl
ifelse(path_contains(move_by(-1,2,$1),$2`'z0),`0',move_by(-1,2,$1))`'dnl
ifelse(path_contains(move_by(-2,1,$1),$2`'z0),`0',move_by(-2,1,$1))`'dnl
ifelse(path_contains(move_by(-1,-2,$1),$2`'z0),`0',move_by(-1,-2,$1))`'dnl
ifelse(path_contains(move_by(-2,-1,$1),$2`'z0),`0',move_by(-2,-1,$1))')

dnl  Count how many moves can follow each move in $1.
define(`follows_counts',
  `ifelse($1,`',`',
          `path_length(possible_moves(path_car($1),$2))`'follows_counts(path_cdr($1),$2)')')

dnl  Find the smallest positive digit, or zero.
define(`min_positive',
  `ifelse($1,`',0,
`pushdef(`min1',min_positive(string_cdr($1)))`'dnl
pushdef(`val1',string_car($1))`'dnl
ifelse(min1,0,val1,
       val1,0,min1,
       eval(val1 < min1),1,val1,min1)`'dnl
popdef(`min1',`val1')')')

dnl  Change everything to zero that is not the minimum positive.
define(`apply_warnsdorff',`_$0(min_positive($1),$1)')
define(`_apply_warnsdorff',
  `ifelse($2,`',`',`ifelse(string_car($2),$1,$1,0)`'$0($1,string_cdr($2))')')

dnl  Find potential next moves that satisfy Warnsdorff's rule.
define(`warnsdorff_moves',
`pushdef(`moves',`possible_moves($1,$2)')`'dnl
pushdef(`selections',`apply_warnsdorff(follows_counts(moves))')`'dnl
_$0(moves,selections)`'dnl
popdef(`moves',`selections')')
define(`_warnsdorff_moves',
`ifelse($1,`',`',
`ifelse(string_car($2),0,`$0(path_cdr($1),string_cdr($2))',
        `path_car($1)`'$0(path_cdr($1),string_cdr($2))')')')

dnl  Find potential next moves for the given path.
define(`next_moves',
`ifelse(path_length($1),63,`possible_moves(path_last($1),$1)',
        `warnsdorff_moves(path_last($1),$1)')')

define(`find_tour',
`ifelse($2,`',`find_tour($1,$1)',
        path_length($2),64,$2,
`pushdef(`moves',next_moves($2))`'dnl
ifelse(moves,`',`find_tour($1)',
       `find_tour($1,$2`'random_move(next_moves($2)))')`'dnl
popdef(`moves')')')

divert`'dnl
dnl
find_tour(a1)
find_tour(c5)
find_tour(h8)