# Project  : Kernighans large earthquake problem

load "stdlib.ring"
nr = 0
equake = list(3)
fn = "equake.txt"
fp = fopen(fn,"r")

while not feof(fp)
         nr = nr + 1
         equake[nr] = readline(fp)
end
fclose(fp)
for n = 1 to len(equake)
     for m = 1 to len(equake[n])
          if equake[n][m] = " "
             sp = m
          ok
     next
     sptemp = right(equake[n],len(equake[n])-sp)
     sptemo = number(sptemp)
     if sptemp > 6
        see equake[n] + nl
     ok
next


ruby -nae "$F[2].to_f > 6 && print" data.txt


fn main() -> Result<(), Box<dyn std::error::Error>> {
    use std::io::{BufRead, BufReader};

    for line in BufReader::new(std::fs::OpenOptions::new().read(true).open("data.txt")?).lines() {
        let line = line?;

        let magnitude = line
            .split_whitespace()
            .nth(2)
            .and_then(|it| it.parse::<f32>().ok())
            .ok_or_else(|| format!("Could not parse scale: {}", line))?;

        if magnitude > 6.0 {
            println!("{}", line);
        }
    }

    Ok(())
}


scala.io.Source.fromFile("data.txt").getLines
  .map("\\s+".r.split(_))
  .filter(_(2).toDouble > 6.0)
  .map(_.mkString("\t"))
  .foreach(println)


        input(.quake, 1,, 'data.txt')       :f(err)
        num = '.0123456789'

line    test = quake                        :f(end)
        test span(num) . magnitude rpos(0)  :f(line)
        output = gt(magnitude,6) test       :(line)

err     output = 'Error!'
end


import Foundation

guard let path = Array(CommandLine.arguments.dropFirst()).first else {
  fatalError()
}

let fileData = FileManager.default.contents(atPath: path)!
let eventData = String(data: fileData, encoding: .utf8)!

for line in eventData.components(separatedBy: "\n") {
  guard let lastSpace = line.lastIndex(of: " "), // Get index of last space
        line.index(after: lastSpace) != line.endIndex, // make sure the last space isn't the end of the line
        let magnitude = Double(String(line[line.index(after: lastSpace)])),
        magnitude > 6 else { // Finally check the magnitude
    continue
  }

  print(line)
}


catch {console show}          ;## show console when running from tclwish
catch {wm withdraw .}

set filename "data.txt"
set fh [open $filename]
set NR 0                ;# number-of-record, means linenumber

while {[gets $fh line]>=0} {        ;# gets returns length of line, -1 means eof
    incr NR
    set  line2 [regexp -all -inline {\S+} $line]  ;# reduce multiple whitespace
    set  fld   [split $line2]   ;# split line into fields, at whitespace
    set  f3    [lindex $fld 2]  ;# zero-based
   #set  NF    [llength $fld]       ;# number-of-fields

    if {$f3 > 6} { puts "$line" }
}
close $fh


Imports System.IO

Module Module1

    Function LargeEarthquakes(filename As String, limit As Double) As IEnumerable(Of String())
        Return From line In File.ReadLines(filename)
               Let parts = line.Split(CType(Nothing, Char()), StringSplitOptions.RemoveEmptyEntries)
               Where Double.Parse(parts(2)) > limit
               Select parts
    End Function

    Sub Main()
        For Each earthquake In LargeEarthquakes("data.txt", 6)
            Console.WriteLine(String.Join(" ", earthquake))
        Next
    End Sub

End Module


import os
fn main() {
    lines := os.read_lines('data.txt')?
    println('Those earthquakes with a magnitude > 6.0 are:\n')
    for line in lines {
        fields := line.fields()
        mag := fields[2].f64()
        if mag > 6.0 {
            println(line)
        }
    }
}


import "io" for File
import "os" for Process
import "/pattern" for Pattern

var args = Process.arguments
if (args.count != 1) Fiber.abort("Please pass just the name of the date file.")
var fileName = args[0]
var lines = File.read(fileName).split("\n").map { |l| l.trim() }.where { |l| l != "" }
var p = Pattern.new("+1/s")
System.print("The earthquakes from '%(fileName)' with a magnitude of greater than 6 are:\n")
for (line in lines) {
    var data = p.splitAll(line)
    if (data.count != 3) Fiber.abort("Invalid line : %(line)")
    var mag = Num.fromString(data[2])
    if (mag > 6) System.print(line)
}


int C;
[loop   [OpenO(8);              \get line from input file
        repeat  C:= ChIn(1);
                ChOut(8, C);    \save it in buffer device 8
                if C = $1A\EOF\ then quit;
        until   C = $0A\LF\;
        OpenI(8);
        repeat until ChIn(8) <= $20\space\;
        repeat until ChIn(8) >  $20\space\;
        repeat until ChIn(8) <= $20\space\;
        if RlIn(8) > 6.0 then
            [OpenI(8);          \output saved line to console
            repeat  C:= ChIn(8);
                    ChOut(0, C);
            until   C = $0A\LF\;
            ];
        ];
]


if peek("argument") then
    filename$ = peek$("argument")
else
    filename$ = "data.txt"
end if

dim tok$(1)
a = open(filename$)
if not a error "Could not open '" + filename$ + "' for reading"
while(not eof(a))
  line input #a a$
  void = token(a$, tok$())
  if val(tok$(3)) > 6 print a$
wend
close a


fcn equake(data,out=Console){
   data.pump(out,fcn(line){ 6.0line.split()[-1] },Void.Filter)
}


V _kmoves = [(2, 1), (1, 2), (-1, 2), (-2, 1), (-2, -1), (-1, -2), (1, -2), (2, -1)]

F chess2index(=chess, boardsize)
   ‘Convert Algebraic chess notation to internal index format’
   chess = chess.lowercase()
   V x = chess[0].code - ‘a’.code
   V y = boardsize - Int(chess[1..])
   R (x, y)

F boardstring(board, boardsize)
   V r = 0 .< boardsize
   V lines = ‘’
   L(y) r
      lines ‘’= "\n"r.map(x -> (I @board[(x, @y)] {‘#2’.format(@board[(x, @y)])} E ‘  ’)).join(‘,’)
   R lines

F knightmoves(board, P, boardsize)
   V (Px, Py) = P
   V kmoves = Set(:_kmoves.map((x, y) -> (@Px + x, @Py + y)))
   kmoves = Set(Array(kmoves).filter((x, y) -> x C 0 .< @boardsize & y C 0 .< @boardsize & [email protected][(x, y)]))
   R kmoves

F accessibility(board, P, boardsize)
   [(Int, (Int, Int))] access
   V brd = copy(board)
   L(pos) knightmoves(board, P, boardsize' boardsize)
      brd[pos] = -1
      access.append((knightmoves(brd, pos, boardsize' boardsize).len, pos))
      brd[pos] = 0
   R access

F knights_tour(start, boardsize, _debug = 0B)
   [(Int, Int) = Int] board
   L(x) 0 .< boardsize
      L(y) 0 .< boardsize
         board[(x, y)] = 0
   V move = 1
   V P = chess2index(start, boardsize)
   board[P] = move
   move++
   I _debug
      print(boardstring(board, boardsize' boardsize))
   L move <= board.len
      P = min(accessibility(board, P, boardsize))[1]
      board[P] = move
      move++
      I _debug
         print(boardstring(board, boardsize' boardsize))
         input("\n#2 next: ".format(move))
   R board

L(boardsize, start) [(5, ‘c3’), (8, ‘h8’), (10, ‘e6’)]
   print(‘boardsize: ’boardsize)
   print(‘Start position: ’start)
   V board = knights_tour(start, boardsize)
   print(boardstring(board, boardsize' boardsize))
   print()


*        Knight's tour             20/03/2017
KNIGHT   CSECT
         USING  KNIGHT,R13         base registers
         B      72(R15)            skip savearea
         DC     17F'0'             savearea
         STM    R14,R12,12(R13)    save previous context
         ST     R13,4(R15)         link backward
         ST     R15,8(R13)         link forward
         LR     R13,R15            set addressability
         MVC    PG(20),=CL20'Knight''s tour ..x..'
         L      R1,NN              n
         XDECO  R1,XDEC            edit
         MVC    PG+14(2),XDEC+10   n
         MVC    PG+17(2),XDEC+10   n
         XPRNT  PG,L'PG            print buffer
         LA     R0,1               1
         ST     R0,X               x=1
         ST     R0,Y               y=1
         SR     R0,R0              0
         ST     R0,TOTAL           total=0
LOOP     EQU    *                  do loop
         L      R1,X                 x
         BCTR   R1,0                 -1
         MH     R1,NNH               *n
         L      R0,Y                 y
         BCTR   R0,0                 -1
         AR     R1,R0                (x-1)*n+y-1
         SLA    R1,1                 ((x-1)*n+y-1)*2
         LA     R0,1                 1
         STH    R0,BOARD(R1)         board(x,y)=1
         L      R2,TOTAL             total
         LA     R2,1(R2)             total+1
         STH    R2,DISP(R1)          disp(x,y)=total+1
         ST     R2,TOTAL             total=total+1
         L      R1,X                 x
         L      R2,Y                 y
         BAL    R14,CHOOSEMV         call choosemv(x,y)
         C      R0,=F'0'           until(choosemv(x,y)=0)
         BNE    LOOP               loop
         LA     R2,KN*KN           n*n
       IF C,R2,NE,TOTAL THEN       if total<>n*n then
         XPRNT  =C'error!!',7        print error
       ENDIF    ,                  endif
         LA     R6,1               i=1
       DO WHILE=(C,R6,LE,NN)       do i=1 to n
         MVC    PG,=CL128' '         init buffer
         LA     R10,PG               pgi=0
         LA     R7,1                 j=1
       DO WHILE=(C,R7,LE,NN)         do j=1 to n
         LR     R1,R6                  i
         BCTR   R1,0                   -1
         MH     R1,NNH                 *n
         LR     R0,R7                  j
         BCTR   R0,0                   -1
         AR     R1,R0                  (i-1)*n+j-1
         SLA    R1,1                   ((i-1)*n+j-1)*2
         LH     R2,DISP(R1)            disp(i,j)
         XDECO  R2,XDEC                edit
         MVC    0(4,R10),XDEC+8        output
         LA     R10,4(R10)             pgi+=4
         LA     R7,1(R7)               j++
       ENDDO    ,                    enddo j
         XPRNT  PG,L'PG              print buffer
         LA     R6,1(R6)             i++
       ENDDO    ,                  enddo i
         L      R13,4(0,R13)       restore previous savearea pointer
         LM     R14,R12,12(R13)    restore previous context
         XR     R15,R15            return_code=0
         BR     R14                exit
*------- ----   ----------------------------------------
CHOOSEMV EQU    *                  choosemv(xc,yc)
         ST     R14,SAVEACMV       save return point
         ST     R1,XC              store xc
         ST     R2,YC              store yc
         MVC    MM,=F'9'           m=9
         L      R1,XC              xc
         LA     R1,1(R1)
         L      R2,YC              yc
         LA     R2,2(R2)
         BAL    R14,TRYMV          call trymv(xc+1,yc+2)
         L      R1,XC              xc
         LA     R1,1(R1)
         L      R2,YC              yc
         SH     R2,=H'2'
         BAL    R14,TRYMV          call trymv(xc+1,yc-2)
         L      R1,XC              xc
         BCTR   R1,0
         L      R2,YC              yc
         LA     R2,2(R2)
         BAL    R14,TRYMV          call trymv(xc-1,yc+2)
         L      R1,XC              xc
         BCTR   R1,0
         L      R2,YC              yc
         SH     R2,=H'2'
         BAL    R14,TRYMV          call trymv(xc-1,yc-2)
         L      R1,XC              xc
         LA     R1,2(R1)
         L      R2,YC              yc
         LA     R2,1(R2)
         BAL    R14,TRYMV          call trymv(xc+2,yc+1)
         L      R1,XC              xc
         LA     R1,2(R1)
         L      R2,YC              yc
         BCTR   R2,0
         BAL    R14,TRYMV          call trymv(xc+2,yc-1)
         L      R1,XC              xc
         SH     R1,=H'2'
         L      R2,YC              yc
         LA     R2,1(R2)
         BAL    R14,TRYMV          call trymv(xc-2,yc+1)
         L      R1,XC              xc
         SH     R1,=H'2'
         L      R2,YC              yc
         BCTR   R2,0
         BAL    R14,TRYMV          call trymv(xc-2,yc-1)
         L      R4,MM              m
       IF C,R4,EQ,=F'9' THEN       if m=9 then
         LA     R0,0                 return(0)
       ELSE     ,                  else
         MVC    X,NEWX               x=newx
         MVC    Y,NEWY               y=newy
         LA     R0,1                 return(1)
       ENDIF    ,                  endif
         L      R14,SAVEACMV       restore return point
         BR     R14                return
SAVEACMV DS     A                  return point
*------- ----   ----------------------------------------
TRYMV    EQU    *                  trymv(xt,yt)
         ST     R14,SAVEATMV       save return point
         ST     R1,XT              store xt
         ST     R2,YT              store yt
         SR     R10,R10            n=0
         BAL    R14,VALIDMV
       IF LTR,R0,Z,R0 THEN         if validmv(xt,yt)=0 then
         LA     R0,0                 return(0)
         B      RETURTMV
       ENDIF    ,                  endif
         L      R1,XT
         LA     R1,1(R1)           xt+1
         L      R2,YT
         LA     R2,2(R2)           yt+2
         BAL    R14,VALIDMV
       IF C,R0,EQ,=F'1' THEN       if validmv(xt+1,yt+2)=1 then
         LA     R10,1(R10)           n=n+1;
       ENDIF    ,                  endif
         L      R1,XT
         LA     R1,1(R1)           xt+1
         L      R2,YT
         SH     R2,=H'2'           yt-2
         BAL    R14,VALIDMV
       IF C,R0,EQ,=F'1' THEN       if validmv(xt+1,yt-2)=1 then
         LA     R10,1(R10)           n=n+1;
       ENDIF    ,                  endif
         L      R1,XT
         BCTR   R1,0               xt-1
         L      R2,YT
         LA     R2,2(R2)           yt+2
         BAL    R14,VALIDMV
       IF C,R0,EQ,=F'1' THEN       if validmv(xt-1,yt+2)=1 then
         LA     R10,1(R10)           n=n+1;
       ENDIF    ,                  endif
         L      R1,XT
         BCTR   R1,0               xt-1
         L      R2,YT
         SH     R2,=H'2'           yt-2
         BAL    R14,VALIDMV
       IF C,R0,EQ,=F'1' THEN       if validmv(xt-1,yt-2)=1 then
         LA     R10,1(R10)           n=n+1;
       ENDIF    ,                  endif
         L      R1,XT
         LA     R1,2(R1)           xt+2
         L      R2,YT
         LA     R2,1(R2)           yt+1
         BAL    R14,VALIDMV
       IF C,R0,EQ,=F'1' THEN       if validmv(xt+2,yt+1)=1 then
         LA     R10,1(R10)           n=n+1;
       ENDIF    ,                  endif
         L      R1,XT
         LA     R1,2(R1)           xt+2
         L      R2,YT
         BCTR   R2,0               yt-1
         BAL    R14,VALIDMV
       IF C,R0,EQ,=F'1' THEN       if validmv(xt+2,yt-1)=1 then
         LA     R10,1(R10)           n=n+1;
       ENDIF    ,                  endif
         L      R1,XT
         SH     R1,=H'2'           xt-2
         L      R2,YT
         LA     R2,1(R2)           yt+1
         BAL    R14,VALIDMV
       IF C,R0,EQ,=F'1' THEN       if validmv(xt-2,yt+1)=1 then
         LA     R10,1(R10)           n=n+1;
       ENDIF    ,                  endif
         L      R1,XT
         SH     R1,=H'2'           xt-2
         L      R2,YT
         BCTR   R2,0               yt-1
         BAL    R14,VALIDMV
       IF C,R0,EQ,=F'1' THEN       if validmv(xt-2,yt-1)=1 then
         LA     R10,1(R10)           n=n+1;
       ENDIF    ,                  endif
       IF C,R10,LT,MM THEN         if n<m then
         ST     R10,MM               m=n
         MVC    NEWX,XT              newx=xt
         MVC    NEWY,YT              newy=yt
       ENDIF    ,                  endif
RETURTMV L      R14,SAVEATMV       restore return point
         BR     R14                return
SAVEATMV DS     A                  return point
*------- ----   ----------------------------------------
VALIDMV  EQU    *                  validmv(xv,yv)
         C      R1,=F'1'           if xv<1  then
         BL     RET0
         C      R1,NN              if xv>nn then
         BH     RET0
         C      R2,=F'1'           if yv<1  then
         BL     RET0
         C      R2,NN              if yv>nn then
         BNH    OK
RET0     SR     R0,R0              return(0)
         B      RETURVMV
OK       LR     R3,R1              xv
         BCTR   R3,0
         MH     R3,NNH             *n
         LR     R0,R2              yv
         BCTR   R0,0
         AR     R3,R0
         SLA    R3,1
         LH     R4,BOARD(R3)       board(xv,yv)
       IF LTR,R4,Z,R4 THEN         if board(xv,yv)=0 then
         LA     R0,1                 return(1)
       ELSE     ,                  else
         SR     R0,R0                return(0)
       ENDIF    ,                  endif
RETURVMV BR     R14                return
*        ----   ----------------------------------------
KN       EQU    8                  n  compile-time
NN       DC     A(KN)              n  fullword
NNH      DC     AL2(KN)            n  halfword
BOARD    DC     (KN*KN)H'0'        dim board(n,n) init 0
DISP     DC     (KN*KN)H'0'        dim  disp(n,n) init 0
X        DS     F
Y        DS     F
TOTAL    DS     F
XC       DS     F
YC       DS     F
MM       DS     F
NEWX     DS     F
NEWY     DS     F
XT       DS     F
YT       DS     F
XDEC     DS     CL12
PG       DC     CL128' '           buffer
         YREGS
         END    KNIGHT


generic
   Size: Integer;
package Knights_Tour is

   subtype Index is Integer range 1 .. Size;
   type Tour is array  (Index, Index) of Natural;
   Empty: Tour := (others => (others => 0));

   function Get_Tour(Start_X, Start_Y: Index; Scene: Tour := Empty) return Tour;
   -- finds tour via backtracking
   -- either no tour has been found, i.e., Get_Tour returns Scene
   -- or the Result(X,Y)=K if and only if I,J is visited at the K-th move
   -- for all X, Y, Scene(X,Y) must be either 0 or Natural'Last,
   --   where Scene(X,Y)=Natural'Last means "don't visit coordiates (X,Y)!"

   function Count_Moves(Board: Tour) return Natural;
   -- counts the number of possible moves, i.e., the number of 0's on the board

   procedure Tour_IO(The_Tour: Tour; Width: Natural := 4);
   -- writes The_Tour to the output using Ada.Text_IO;

end Knights_Tour;


# Non-recursive Knight's Tour with Warnsdorff's algorithm                #
# If there are multiple choices, backtrack if the first choice doesn't   #
# find a solution                                                        #

# the size of the board                                                  #
INT board size = 8;

# directions for moves #
INT nne = 1, nee = 2, see = 3, sse = 4, ssw = 5, sww = 6, nww = 7, nnw = 8;

INT lowest move  = nne;
INT highest move = nnw;

# the vertical position changes of the moves                             #
#                  nne, nee, see, sse, ssw, sww, nww, nnw                #
[]INT offset v = (  -2,  -1,   1,   2,   2,   1,  -1,  -2 );
# the horizontal position changes of the moves                           #
#                  nne, nee, see, sse, ssw, sww, nww, nnw                #
[]INT offset h = (   1,   2,   2,   1,  -1,  -2,  -2,  -1 );

MODE SQUARE = STRUCT( INT move      # the number of the move that caused #
                                    # the knight to reach this square    #
                    , INT direction # the direction of the move that     #
                                    # brought the knight here - one of   #
                                    # nne, nee, see, sse, ssw, sww, nww  #
                                    # or nnw - used for backtracking     #
                                    # zero for the first move            #
                    );

# the board #
[ board size, board size ]SQUARE board;

# initialises the board so there are no used squares #
PROC initialise board = VOID:
    FOR row FROM 1 LWB board TO 1 UPB board
    DO
        FOR col FROM 2 LWB board TO 2 UPB board
        DO
            board[ row, col ] := ( 0, 0 )
        OD
    OD; # initialise board #

INT iterations := 0;
INT backtracks := 0;

# prints the board #
PROC print tour = VOID:
BEGIN

    print( ( "       a   b   c   d   e   f   g   h", newline ) );
    print( ( "   +--------------------------------", newline ) );

    FOR row FROM 1 UPB board BY -1 TO 1 LWB board
    DO
        print( ( whole( row, -3 ) ) );
        print( ( "|" ) );

        FOR col FROM 2 LWB board TO 2 UPB board
        DO
            print( ( " " ) );
            print( ( whole( move OF board[ row, col ], -3 ) ) )
        OD;
        print( ( newline ) )
    OD

END; # print tour #

# determines whether a move to the specified row and column is possible #
PROC can move to = ( INT row, INT col )BOOL:
    IF row > 1 UPB board
    OR row < 1 LWB board
    OR col > 2 UPB board
    OR col < 2 LWB board
    THEN
        # the position is not on the board                              #
        FALSE
    ELSE
        # the move is legal, check the square is unoccupied             #
        move OF board[ row, col ] = 0
    FI;

# used to hold counts of the number of moves that could be made in each #
# direction from the current square                                     #
[ lowest move : highest move ]INT possible move count;

# sets the elements of possible move count to the number of moves that  #
# could be made in each direction from the specified row and col        #
PROC count moves in each direction from = ( INT row, INT col )VOID:
    FOR move direction FROM lowest move TO highest move
    DO

        INT new row = row + offset v[ move direction ];
        INT new col = col + offset h[ move direction ];

        IF NOT can move to( new row, new col )
        THEN
            # can't move to this square #
            possible move count[ move direction ] := -1
        ELSE
            # a move in this direction is possible #
            # - count the number of moves that could be made from it #

            possible move count[ move direction ] := 0;

            FOR subsequent move FROM lowest move TO highest move
            DO
                IF can move to( new row + offset v[ subsequent move ]
                              , new col + offset h[ subsequent move ]
                              )
                THEN
                    # have a possible subsequent move #
                    possible move count[ move direction ] +:= 1
                FI
            OD
        FI

    OD;

# update the board to the first knight's tour found starting from       #
# "start row" and "start col".                                          #
# return TRUE if one was found, FALSE otherwise                         #
PROC find tour = ( INT start row, INT start col )BOOL:
BEGIN

    initialise board;

    BOOL result := TRUE;

    INT  move number  := 1;
    INT  row          := start row;
    INT  col          := start col;

    # the tour will be complete when we have made as many moves            #
    # as there squares on the board                                        #
    INT  final move    = ( ( ( 1 UPB board ) + 1 ) - 1 LWB board )
                       * ( ( ( 2 UPB board ) + 1 ) - 2 LWB board )
                       ;

    # the first move is to place the knight on the starting square         #
    board[ row, col ]  := ( move number, lowest move - 1 );
    # start off with an unknown direction for the best move                #
    INT best direction := lowest move - 1;

    # attempt to find a sequence of moves that will reach each square once #
    WHILE
        move number < final move AND result
    DO

        iterations +:= 1;

        # count the number of moves possible from each possible move       #
        # from this square                                                 #
        count moves in each direction from( row, col );

        # find the direction with the lowest number of subsequent moves    #

        IF best direction < lowest move
        THEN
            # must find the best direction to move in                      #

            INT lowest move count := highest move + 1;

            FOR move direction FROM lowest move TO highest move
            DO
                IF  possible move count[ move direction ] >= 0
                AND possible move count[ move direction ] <  lowest move count
                THEN
                    # have a move with fewer possible subsequent moves     #
                    best direction    := move direction;
                    lowest move count := possible move count[ move direction ]
                FI
            OD

        ELSE
            # following a backtrack - find an alternative with the same    #
            # lowest number of possible moves - if there are any           #
            # if there aren't, we will backtrack again                     #

            INT lowest move count := possible move count[ best direction ];

            WHILE
                best direction +:= 1;
                IF best direction > highest move
                THEN
                    # no more possible moves with the lowest number of     #
                    # subsequent moves                                     #
                    FALSE
                ELSE
                    # keep looking if the number of moves from this square #
                    # isn't the lowest                                     #
                    possible move count[ best direction ] /= lowest move count
                FI
            DO
                SKIP
            OD

        FI;

        IF best direction  <= highest move
        AND best direction >= lowest move
        THEN
            # we found a best possible move #

            INT new row = row + offset v[ best direction ];
            INT new col = col + offset h[ best direction ];

            row               := new row;
            col               := new col;
            move number      +:= 1;
            board[ row, col ] := ( move number, best direction );

            best direction    := lowest move - 1

        ELSE
            # no more moves from this position - backtrack #

            IF move number = 1
            THEN
                # at the starting position - no solution #
                result := FALSE

            ELSE
                # not at the starting position - undo the latest move #

                backtracks  +:= 1;

                move number -:= 1;

                INT curr row := row;
                INT curr col := col;

                best direction := direction OF board[ curr row, curr col ];

                row -:= offset v[ best direction ];
                col -:= offset h[ best direction ];

                # reset the square we just backtracked from #
                board[ curr row, curr col ] := ( 0, 0 )

            FI

        FI

    OD;

    result
END; # find tour #

main:(

    # get the starting position #

    CHAR  row;
    CHAR  col;

    WHILE
        print( ( "Enter starting row(1-8) and col(a-h): " ) );
        read ( ( row, col, newline ) );
        row < "1" OR row > "8" OR col < "a" OR col > "h"
    DO
        SKIP
    OD;

    # calculate the tour from that position, if possible #

    IF find tour( ABS row - ABS "0", ( ABS col - ABS "a" ) + 1 )
    THEN
        # found a solution #
        print tour
    ELSE
        # couldn't find a solution #
        print( ( "Solution not found - iterations: ", iterations
               , ", backtracks: ", backtracks
               , newline
               )
             )
    FI

)


100 DECLARE EXTERNAL FUNCTION choosemove
110 !
120 RANDOMIZE
130 PUBLIC NUMERIC X, Y, TRUE, FALSE
140 LET TRUE = -1
150 LET FALSE = 0
160 !
170 SET WINDOW 1,512,1,512
180 SET AREA COLOR "black"
190 FOR x=0 TO 512-128 STEP 128
200    FOR y=0 TO 512-128 STEP 128
210       PLOT AREA:x+64,y;x+128,y;x+128,y+64;x+64,y+64
220       PLOT AREA:x,y+64;x+64,y+64;x+64,y+128;x,y+128
230    NEXT y
240 NEXT x
250 !
260 SET LINE COLOR "red"
270 SET LINE WIDTH 6
280 !
290 PUBLIC NUMERIC Board(0 TO 7,0 TO 7)
300 LET X = 0
310 LET Y = 0
320 LET Total = 0
330 DO
340    LET Board(X,Y) = TRUE
350    PLOT LINES: X*64+32,Y*64+32;
360    LET Total = Total + 1
370 LOOP UNTIL choosemove(X, Y) = FALSE
380 IF Total <> 64 THEN STOP
390 END
400 !
410 EXTERNAL FUNCTION choosemove(X1, Y1)
420 DECLARE EXTERNAL SUB trymove
430 LET M = 9
440 CALL trymove(X1+1, Y1+2, M, newx, newy)
450 CALL trymove(X1+1, Y1-2, M, newx, newy)
460 CALL trymove(X1-1, Y1+2, M, newx, newy)
470 CALL trymove(X1-1, Y1-2, M, newx, newy)
480 CALL trymove(X1+2, Y1+1, M, newx, newy)
490 CALL trymove(X1+2, Y1-1, M, newx, newy)
500 CALL trymove(X1-2, Y1+1, M, newx, newy)
510 CALL trymove(X1-2, Y1-1, M, newx, newy)
520 IF M=9 THEN
530    LET choosemove = FALSE
540    EXIT FUNCTION
550 END IF
560 LET X = newx
570 LET Y = newy
580 LET choosemove = TRUE
590 END FUNCTION
600 !
610 EXTERNAL SUB trymove(X, Y, M, newx, newy)
620 !
630 DECLARE EXTERNAL FUNCTION validmove
640 IF validmove(X,Y) = 0 THEN EXIT SUB
650 IF validmove(X+1,Y+2) <> 0 THEN LET N = N + 1
660 IF validmove(X+1,Y-2) <> 0 THEN LET N = N + 1
670 IF validmove(X-1,Y+2) <> 0 THEN LET N = N + 1
680 IF validmove(X-1,Y-2) <> 0 THEN LET N = N + 1
690 IF validmove(X+2,Y+1) <> 0 THEN LET N = N + 1
700 IF validmove(X+2,Y-1) <> 0 THEN LET N = N + 1
710 IF validmove(X-2,Y+1) <> 0 THEN LET N = N + 1
720 IF validmove(X-2,Y-1) <> 0 THEN LET N = N + 1
730 IF N>M THEN EXIT SUB
740 IF N=M AND RND<.5 THEN EXIT SUB
750 LET M = N
760 LET newx = X
770 LET newy = Y
780 END SUB
790 !
800 EXTERNAL FUNCTION validmove(X,Y)
810 LET validmove = FALSE
820 IF X<0 OR X>7 OR Y<0 OR Y>7 THEN EXIT FUNCTION
830 IF Board(X,Y)=FALSE THEN LET validmove = TRUE
840 END FUNCTION


(*
  Find Knight’s Tours.

  Using Warnsdorff’s heuristic, find multiple solutions.
  Optionally accept only closed tours.

  Compile with:
      patscc -O3 -DATS_MEMALLOC_GCBDW -o knights_tour knights_tour.dats -lgc

  Usage: ./knights_tour [START_POSITION [MAX_TOURS [closed]]]
  Examples:
      ./knights_tour     (prints one tour starting from a1)
      ./knights_tour c5
      ./knights_tour c5 2000
      ./knights_tour c5 2000 closed
*)

#define ATS_DYNLOADFLAG 0       (* No initialization is needed. *)

#include "share/atspre_define.hats"
#include "share/atspre_staload.hats"

#define EMPTY_SQUARE ~1
macdef nil_move = @(~1, ~1)

fn
int_right_justified
          {i : int}
          {n : int | 0 <= n; n < 100}
          (i : int i,
           n : int n) :
    string =
  let
    var buffer : @[char][100] = @[char][100] ('\0')
    val _ = $extfcall (int, "snprintf", buffer, 100, "%*i", n, i)
  in
    strnptr2string (string1_copy ($UNSAFE.cast{string n} buffer))
  end

typedef move_t (i : int,
                j : int) =
  @(int i, int j)
typedef move_t =
  [i, j : int]
  move_t (i, j)

fn
move_t_is_nil (move : move_t) :<>
    bool =
  let
    val @(i, j) = move
    val @(i_nil, j_nil) = nil_move
  in
    (i = i_nil && j = j_nil)
  end

fn
move_t_fprint (f    : FILEref,
               move : move_t) :
    void =
  let
    val @(i, j) = move
    val letter = char2i 'a' + j - 1
    val digit = char2i '0' + i
  in
    fileref_putc (f, letter);
    fileref_putc (f, digit);
  end

vtypedef chessboard_vt (t       : [email protected],
                        n_ranks : int,
                        n_files : int,
                        p       : addr) =
  @{
    pf_board = @[t][n_ranks * n_files] @ p |
    n_ranks = uint n_ranks,
    n_files = uint n_files,
    n_squares = uint (n_ranks * n_files),
    p_board = ptr p
  }
vtypedef chessboard_vt (t       : [email protected],
                        n_ranks : int,
                        n_files : int) =
  [p : addr]
  chessboard_vt (t, n_ranks, n_files, p)
vtypedef chessboard_vt (t : [email protected]) =
  [n_ranks, n_files : int]
  chessboard_vt (t, n_ranks, n_files)

fn {t : [email protected]}
chessboard_vt_make
          {n_ranks, n_files : pos}
          (n_ranks : uint n_ranks,
           n_files : uint n_files,
           fill    : t) :
    chessboard_vt (t, n_ranks, n_files) =
  let
    val size = u2sz (n_ranks * n_files)
    val @(pf, pfgc | p) = array_ptr_alloc<t> (size)
    val _ = array_initize_elt<t> (!p, size, fill)
    prval _ = mfree_gc_v_elim pfgc (* Let the memory leak. *)
  in
    @{
      pf_board = pf |
      n_ranks = n_ranks,
      n_files = n_files,
      n_squares = n_ranks * n_files,
      p_board = p
    }
  end

fn {t : [email protected]}
chessboard_vt_get
          {n_ranks, n_files : pos}
          {i, j       : int}
          (chessboard : !chessboard_vt (t, n_ranks, n_files),
           i          : int i,
           j          : int j) :
    t =
  let
    val index = (i - 1) + (u2i (chessboard.n_ranks) * (j - 1))
    val _ = assertloc (0 <= index)
    val _ = assertloc (index < u2i (chessboard.n_squares))
  in
    array_get_at (!(chessboard.p_board), index)
  end

fn {t : [email protected]}
chessboard_vt_set
          {n_ranks, n_files : pos}
          {i, j       : int}
          (chessboard : !chessboard_vt (t, n_ranks, n_files),
           i          : int i,
           j          : int j,
           value      : t) :
    void =
  let
    val index = (i - 1) + (u2i (chessboard.n_ranks) * (j - 1))
    val _ = assertloc (0 <= index)
    val _ = assertloc (index < u2i (chessboard.n_squares))
  in
    array_set_at (!(chessboard.p_board), index, value)
  end

extern fn {t : [email protected]}
find_nth_position$equal (x : t,
                         y : t) :
    bool

fn {t : [email protected]}
find_nth_position
          {n_ranks, n_files : pos}
          (chessboard : !chessboard_vt (t, n_ranks, n_files),
           n          : t) :
    [i, j : int]
    move_t (i, j) =
  let
    val n_ranks = chessboard.n_ranks
    val n_files = chessboard.n_files

    fun
    outer_loop {i : pos | i <= n_ranks + 1} .<n_ranks + 1 - i>.
               (chessboard : !chessboard_vt (t, n_ranks, n_files),
                i : int i) :
        [i, j : int]
        move_t (i, j) =
      let
        fun
        inner_loop {j : pos | j <= n_files + 1} .<n_files + 1 - j>.
                   (chessboard : !chessboard_vt (t, n_ranks, n_files),
                    j : int j) :
            [j : int]
            int j =
          if u2i n_files < j then
            j
          else
            let
              val v = chessboard_vt_get<t> (chessboard, i, j)
            in
              if find_nth_position$equal<t> (n, v) then
                j
              else
                inner_loop (chessboard, succ j)
            end
      in
        if u2i n_ranks < i then
          nil_move
        else
          let
            val j = inner_loop (chessboard, 1)
          in
            if j <= u2i n_files then
              @(i, j)
            else
              outer_loop (chessboard, succ i)
          end
      end
  in
    outer_loop (chessboard, 1)
  end

implement
find_nth_position$equal<int> (x, y) =
  x = y

fn
knights_tour_is_closed
          {n_ranks, n_files : pos}
          (chessboard : !chessboard_vt (int, n_ranks, n_files)) :
    bool =
  let
    val n_squares = chessboard.n_squares
    val @(i1, j1) = find_nth_position<int> (chessboard, 1)
    val @(i2, j2) = find_nth_position<int> (chessboard, u2i n_squares)
    val i_diff = abs (i1 - i2)
    val j_diff = abs (j1 - j2)
  in
    (i_diff = 1 && j_diff = 2) || (i_diff = 2 && j_diff = 1)
  end

fn
knights_tour_board_fprint
          {n_ranks, n_files : pos}
          (f          : FILEref,
           chessboard : !chessboard_vt (int, n_ranks, n_files)) :
    void =
  {
    val n_ranks = chessboard.n_ranks
    val n_files = chessboard.n_files

    fun
    outer_loop {i : int | 0 <= i; i <= n_ranks} .<i>.
               (chessboard : !chessboard_vt (int, n_ranks, n_files),
                i : int i) :
        void =
      if 0 < i then
        {
          val _ = fileref_puts (f, "    ")
          val _ =
            let
              var j : [j : int] int j
            in
              for (j := 1; j <= u2i n_files; j := succ j)
                fileref_puts (f, "+----")
            end
          val _ = fileref_puts (f, "+\n")
          val _ = fileref_puts (f, int_right_justified (i, 2))
          val _ = fileref_puts (f, " ")

          fun
          inner_loop {j : int | 1 <= j; j <= n_files + 1}
                     (chessboard : !chessboard_vt (int, n_ranks,
                                                   n_files),
                      j : int j) :
              void =
            if j <= u2i n_files then
              {
                val v = chessboard_vt_get<int> (chessboard, i, j)
                val v = g1ofg0 v
                val _ = fileref_puts (f, " | ")
                val _ =
                  if v = EMPTY_SQUARE then
                    fileref_puts (f, "  ")
                  else
                    fileref_puts (f, int_right_justified (g1ofg0 v, 2))
                val _ = inner_loop (chessboard, succ j)
              }

          val _ = inner_loop (chessboard, 1)
          val _ = fileref_puts (f, " |\n")

          val _ = outer_loop (chessboard, pred i)
        }

    val _ = outer_loop (chessboard, u2i n_ranks)
    val _ = fileref_puts (f, "    ")
    val _ =
      let
        var j : [j : int] int j
      in
        for (j := 1; j <= u2i n_files; j := succ j)
          fileref_puts (f, "+----")
      end
    val _ = fileref_puts (f, "+\n")
    val _ = fileref_puts (f, "   ")
    val _ =
      let
        var j : [j : int] int j
      in
        for (j := 1; j <= u2i n_files; j := succ j)
          let
            val letter = char2i 'a' + j - 1
          in
            fileref_puts (f, "    ");
            fileref_putc (f, letter)
          end
      end
  }

fn
knights_tour_moves_fprint
          {n_ranks, n_files : pos}
          (f          : FILEref,
           chessboard : !chessboard_vt (int, n_ranks, n_files)) :
    void =
  {
    prval _ = mul_pos_pos_pos (mul_make {n_ranks, n_files} ())

    val n_ranks = chessboard.n_ranks
    val n_files = chessboard.n_files
    val n_squares = chessboard.n_squares

    val @(pf, pfgc | p_positions) =
      array_ptr_alloc<move_t> (u2sz n_squares)
    val _ = array_initize_elt<move_t> (!p_positions, u2sz n_squares,
                                       nil_move)

    macdef positions = !p_positions

    fun
    loop {k : int | 0 <= k; k <= n_ranks * n_files}
         .<n_ranks * n_files - k>.
         (positions  : &(@[move_t][n_ranks * n_files]),
          chessboard : !chessboard_vt (int, n_ranks, n_files),
          k          : int k) :
        void =
      if k < u2i n_squares then
        {
          val i = u2i ((i2u k) mod n_ranks) + 1
          val j = u2i ((i2u k) / n_ranks) + 1
          val v = chessboard_vt_get<int> (chessboard, i, j)
          val v = g1ofg0 v
          val _ = assertloc (1 <= v)
          val _ = assertloc (v <= u2i n_squares)
          val _ = positions[v - 1] := @(i, j)
          val _ = loop (positions, chessboard, succ k)
        }
    val _ = loop (positions, chessboard, 0)

    fun
    loop {k : int | 0 <= k; k < n_ranks * n_files}
         .<n_ranks * n_files - k>.
         (positions : &(@[move_t][n_ranks * n_files]),
          k         : int k) :
        void =
      if k < u2i (pred n_squares) then
        {
          val _ = move_t_fprint (f, positions[k])
          val line_end = (((i2u (k + 1)) mod n_files) = 0U)
          val _ =
            fileref_puts (f, (if line_end then " ->\n" else " -> "))
          val _ = loop (positions, succ k)
        }
    val _ = loop (positions, 0)
    val _ = move_t_fprint (f, positions[pred n_squares])
    val _ =
      if knights_tour_is_closed (chessboard) then
        fileref_puts (f, " -> cycle")

    val _ = array_ptr_free (pf, pfgc | p_positions)
  }

typedef knights_moves_t =
  @(move_t, move_t, move_t, move_t,
    move_t, move_t, move_t, move_t)

fn
possible_moves {n_ranks, n_files : pos}
               {i, j       : int}
               (chessboard : !chessboard_vt (int, n_ranks, n_files),
                i          : int i,
                j          : int j) :
    knights_moves_t =
  let
    fn
    try_move {istride, jstride : int}
             (chessboard : !chessboard_vt (int, n_ranks, n_files),
              istride    : int istride,
              jstride    : int jstride) :
        move_t =
      let
        val i1 = i + istride
        val j1 = j + jstride
      in
        if i1 < 1 then
          nil_move
        else if u2i (chessboard.n_ranks) < i1 then
          nil_move
        else if j1 < 1 then
          nil_move
        else if u2i (chessboard.n_files) < j1 then
          nil_move
        else
          let
            val v = chessboard_vt_get (chessboard, i1, j1) : int
          in
            if v <> EMPTY_SQUARE then
              nil_move
            else
              @(i1, j1)
          end
      end

    val move0 = try_move (chessboard, 1, 2)
    val move1 = try_move (chessboard, 2, 1)
    val move2 = try_move (chessboard, 1, ~2)
    val move3 = try_move (chessboard, 2, ~1)
    val move4 = try_move (chessboard, ~1, 2)
    val move5 = try_move (chessboard, ~2, 1)
    val move6 = try_move (chessboard, ~1, ~2)
    val move7 = try_move (chessboard, ~2, ~1)
  in
    @(move0, move1, move2, move3, move4, move5, move6, move7)
  end

fn
count_following_moves
          {n_ranks, n_files : pos}
          {i, j       : int}
          {n_position : int}
          (chessboard : !chessboard_vt (int, n_ranks, n_files),
           move       : move_t (i, j),
           n_position : int n_position) :
    uint =
  if move_t_is_nil move then
    0U
  else
    let
      fn
      succ_if_move_is_not_nil
                {i, j : int}
                (w    : uint,
                 move : move_t (i, j)) :<>
          uint =
        if move_t_is_nil move then
          w
        else
          succ w

      val @(i, j) = move
      val _ = chessboard_vt_set<int> (chessboard, i, j,
                                      succ n_position)
      val following_moves = possible_moves (chessboard, i, j)

      val w = 0U
      val w = succ_if_move_is_not_nil (w, following_moves.0)
      val w = succ_if_move_is_not_nil (w, following_moves.1)
      val w = succ_if_move_is_not_nil (w, following_moves.2)
      val w = succ_if_move_is_not_nil (w, following_moves.3)
      val w = succ_if_move_is_not_nil (w, following_moves.4)
      val w = succ_if_move_is_not_nil (w, following_moves.5)
      val w = succ_if_move_is_not_nil (w, following_moves.6)
      val w = succ_if_move_is_not_nil (w, following_moves.7)

      val _ = chessboard_vt_set<int> (chessboard, i, j, EMPTY_SQUARE)
    in
      w
    end

fn
pick_w (w0 : uint,
        w1 : uint,
        w2 : uint,
        w3 : uint,
        w4 : uint,
        w5 : uint,
        w6 : uint,
        w7 : uint) :<>
    uint =
  let
    fn
    next_pick (u : uint,
               v : uint) :<>
        uint =
      if v = 0U then
        u
      else if u = 0U then
        v
      else
        min (u, v)

    val w = 0U
    val w = next_pick (w, w0)
    val w = next_pick (w, w1)
    val w = next_pick (w, w2)
    val w = next_pick (w, w3)
    val w = next_pick (w, w4)
    val w = next_pick (w, w5)
    val w = next_pick (w, w6)
    val w = next_pick (w, w7)
  in
    w
  end

fn
next_moves {n_ranks, n_files : pos}
           {i, j       : int}
           {n_position : int}
           (chessboard : !chessboard_vt (int, n_ranks, n_files),
            i          : int i,
            j          : int j,
            n_position : int n_position) :
    knights_moves_t =
  (* Prune and sort the moves according to Warnsdorff’s heuristic,
     keeping only moves that have the minimum number of legal
     following moves. *)
  let
    val moves = possible_moves (chessboard, i, j)
    val w0 = count_following_moves (chessboard, moves.0, n_position)
    val w1 = count_following_moves (chessboard, moves.1, n_position)
    val w2 = count_following_moves (chessboard, moves.2, n_position)
    val w3 = count_following_moves (chessboard, moves.3, n_position)
    val w4 = count_following_moves (chessboard, moves.4, n_position)
    val w5 = count_following_moves (chessboard, moves.5, n_position)
    val w6 = count_following_moves (chessboard, moves.6, n_position)
    val w7 = count_following_moves (chessboard, moves.7, n_position)
    val w = pick_w (w0, w1, w2, w3, w4, w5, w6, w7)
  in
    if w = 0U then
      @(nil_move, nil_move, nil_move, nil_move,
        nil_move, nil_move, nil_move, nil_move)
    else
      @(if w0 = w then moves.0 else nil_move,
        if w1 = w then moves.1 else nil_move,
        if w2 = w then moves.2 else nil_move,
        if w3 = w then moves.3 else nil_move,
        if w4 = w then moves.4 else nil_move,
        if w5 = w then moves.5 else nil_move,
        if w6 = w then moves.6 else nil_move,
        if w7 = w then moves.7 else nil_move)
  end

fn
make_and_fprint_tours
          {n_ranks, n_files : int}
          {i, j        : int}
          {max_tours   : int}
          (f           : FILEref,
           n_ranks     : int n_ranks,
           n_files     : int n_files,
           i           : int i,
           j           : int j,
           max_tours   : int max_tours,
           closed_only : bool) :
    void =
  {
    val n_ranks = max (1, n_ranks)
    val n_files = max (1, n_files)
    val i = max (1, min (n_ranks, i))
    val j = max (1, min (n_files, j))
    val max_tours = max (1, max_tours)

    val n_ranks = i2u n_ranks
    val n_files = i2u n_files

    val i_start = i
    val j_start = j

    var tours_printed : int = 0

    val chessboard =
      chessboard_vt_make<int> (n_ranks, n_files, g1ofg0 EMPTY_SQUARE)

    fun
    explore {n_ranks, n_files : pos}
            {i, j          : int}
            {n_position    : int}
            (chessboard    : !chessboard_vt (int, n_ranks, n_files),
             i             : int i,
             j             : int j,
             n_position    : int n_position,
             tours_printed : &int) :
        void =
      if tours_printed < max_tours then
        let
          fn
          print_board {i1, j1 : int}
                      (chessboard    : !chessboard_vt (int, n_ranks,
                                                        n_files),
                       tours_printed : &int) :
              void =
            begin
              tours_printed := succ tours_printed;
              fprintln! (f, "Tour number ", tours_printed);
              knights_tour_moves_fprint (f, chessboard);
              fprintln! (f);
              knights_tour_board_fprint (f, chessboard);
              fprintln! (f);
              fprintln! (f)
            end

          fn
          satisfies_closedness
                    {i1, j1 : int}
                    (move : move_t (i1, j1)) :
              bool =
            if closed_only then
              let
                val @(i1, j1) = move
                val i_diff = abs (i1 - i_start)
                val j_diff = abs (j1 - j_start)
              in
                (i_diff = 1 && j_diff = 2)
                  || (i_diff = 2 && j_diff = 1)
              end
            else
              true

          fn
          try_last_move
                    {i1, j1 : int}
                    (chessboard    : !chessboard_vt (int, n_ranks,
                                                     n_files),
                     move          : move_t (i1, j1),
                     tours_printed : &int) :
              void =
            if ~move_t_is_nil move && satisfies_closedness move then
              let
                val @(i1, j1) = move
              in
                chessboard_vt_set<int> (chessboard, i1, j1,
                                        n_position + 1);
                print_board (chessboard, tours_printed);
                chessboard_vt_set<int> (chessboard, i1, j1,
                                        EMPTY_SQUARE)
              end

          fun
          explore_inner (chessboard : !chessboard_vt (int, n_ranks,
                                                      n_files),
                         tours_printed : &int) :
              void =
            if u2i (chessboard.n_squares) - n_position = 1 then
              (* Is the last move possible? If so, make it and print
                 the board. (Only zero or one of the moves can be
                 non-nil.) *)
              let
                val moves = possible_moves (chessboard, i, j)
              in
                try_last_move (chessboard, moves.0, tours_printed);
                try_last_move (chessboard, moves.1, tours_printed);
                try_last_move (chessboard, moves.2, tours_printed);
                try_last_move (chessboard, moves.3, tours_printed);
                try_last_move (chessboard, moves.4, tours_printed);
                try_last_move (chessboard, moves.5, tours_printed);
                try_last_move (chessboard, moves.6, tours_printed);
                try_last_move (chessboard, moves.7, tours_printed)
              end
            else
              let
                val moves = next_moves (chessboard, i, j, n_position)
                macdef explore_move (move) =
                  begin
                    if ~move_t_is_nil ,(move) then
                      explore (chessboard, (,(move)).0, (,(move)).1,
                               succ n_position, tours_printed)
                  end
              in
                explore_move (moves.0);
                explore_move (moves.1);
                explore_move (moves.2);
                explore_move (moves.3);
                explore_move (moves.4);
                explore_move (moves.5);
                explore_move (moves.6);
                explore_move (moves.7)
              end
        in
          chessboard_vt_set<int> (chessboard, i, j, n_position);
          explore_inner (chessboard, tours_printed);
          chessboard_vt_set<int> (chessboard, i, j, EMPTY_SQUARE)
        end

    val _ = explore (chessboard, i, j, 1, tours_printed)

    val _ = $UNSAFE.castvwtp0{void} chessboard
  }

fn
algebraic_notation_to_move (s : string) :
    move_t =
  let
    val s = g1ofg0 s
    val n = string_length s
  in
    if n = 2 then
      let
        val i = g1ofg0 (char2i (s[1]) - char2i ('0'))
        val j = g1ofg0 (char2i (s[0]) - char2i ('a') + 1)
      in
        @(i, j)
      end
    else
      @(1, 1)
  end

implement
main0 (argc, argv) =
  {
    val @(i, j) =
      begin
        if 2 <= argc then
          algebraic_notation_to_move (argv[1])
        else
          @(1, 1)
      end : move_t

    val max_tours =
      begin
        if 3 <= argc then
          $extfcall (int, "atoi", argv[2])
        else
          1
      end : int
    val max_tours = g1ofg0 max_tours

    val closed_only =
      begin
        if 4 <= argc then
          argv[3] = "closed"
        else
          false
      end : bool

    val _ = make_and_fprint_tours (stdout_ref, 8, 8, i, j, max_tours,
                                   closed_only)
  }


#SingleInstance, Force
#NoEnv
SetBatchLines, -1
; Uncomment if Gdip.ahk is not in your standard library
;#Include, Gdip.ahk
If !pToken := Gdip_Startup(){
   MsgBox, 48, Gdiplus error!, Gdiplus failed to start. Please ensure you have Gdiplus on your system.
   ExitApp
}
; I've added a simple new function here, just to ensure if anyone is having any problems then to make sure they are using the correct library version
if (Gdip_LibraryVersion() < 1.30)
{
	MsgBox, 48, Version error!, Please download the latest version of the gdi+ library
	ExitApp
}
OnExit, Exit
tour := "a1 b3 d2 c4 a5 b7 d8 e6 d4 b5 c7 a8 b6 c8 a7 c6 b8 a6 b4 d5 e3 d1 b2 a4 c5 d7 f8 h7 f6 g8 h6 f7 h8 g6 e7 f5 h4 g2 e1 d3 e5 g4 f2 h1 g3 f1 h2 f3 g1 h3 g5 e4 d6 e8 g7 h5 f4 e2 c1 a2 c3 b1 a3 c2 "
; Knight's tour with maximum symmetry by George Jelliss, http://www.mayhematics.com/t/8f.htm
; I know, I know, but I followed the task outline to the letter! Besides, this path is the prettiest.

; Input: starting square
InputBox, start, Knight's Tour Start, Enter Knight's starting location in algebraic notation:, , , , , , , , b3
i := InStr(tour, start)
If i=0
{
	Msgbox Error, please try again.
	Reload
}
; Output: move sequence
Msgbox % tour := SubStr(tour, i) . SubStr(tour, 1, i-1)

; Animation
tour .= SubStr(tour, 1, 3)
, CellSize := 30 ; pixels
, Width := Height := 9*CellSize
, TopLeftX := (A_ScreenWidth - Width) // 2
, TopLeftY := (A_ScreenHeight - Height) // 2
Gui, -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
Gui, Show, NA ; show board (currently transparent)
hwnd1 := WinExist() ; required for Gdip
OnMessage(0x201, "WM_LBUTTONDOWN")
, hbm := CreateDIBSection(Width, Height)
, hdc := CreateCompatibleDC()
, obm := SelectObject(hdc, hbm)
, G := Gdip_GraphicsFromHDC(hdc)
, Gdip_SetSmoothingMode(G, 4)

Loop 1 ; remove '1' and uncomment next line to loop infinitely
{
;Gdip_GraphicsClear(G) ; uncomment to loop infinitely
cOdd := "0xFFFFCE9E" ; create brushes
, cEven := "0xFFD18B47"
, pBrushOdd := Gdip_BrushCreateSolid(cOdd)
, pBrushEven := Gdip_BrushCreateSolid(cEven)

Loop 64 ; layout board
{
	Row := mod(A_Index-1,8)+1
	, Col := (A_Index-1)//8+1
	, Gdip_FillRectangle(G, mod(Row+Col,2) ? pBrushOdd : pBrushEven, Col * CellSize + 1, Row * CellSize + 1, CellSize - 2, CellSize - 2)
}
Gdip_DeleteBrush(pBrushOdd) ; cleanup memory
, Gdip_DeleteBrush(pBrushEven)
, UpdateLayeredWindow(hwnd1, hdc, TopLeftX, TopLeftY, Width, Height) ; update board

, pPen := Gdip_CreatePen(0x66FF0000, CellSize/10) ; create pen
, Algebraic := SubStr(tour,1,2) ; get starting coordinates
, x := (Asc(SubStr(Algebraic, 1, 1))-96+0.5)*CellSize
, y := (9.5-SubStr(Algebraic, 2, 1))*CellSize

Loop 64 ; trace path
{
	Sleep, 0.5*1000
	xold := x, yold := y ; a line has start and end points
	, Algebraic := SubStr(tour,(A_Index)*3+1,2) ; get new coordinates
	, x := (Asc(SubStr(Algebraic, 1, 1))-96+0.5)*CellSize
	, y := (9.5-SubStr(Algebraic, 2, 1))*CellSize
	, Gdip_DrawLine(G, pPen, xold, yold, x, y)
	, UpdateLayeredWindow(hwnd1, hdc, TopLeftX, TopLeftY, Width, Height) ; update board
}
Gdip_DeletePen(pPen)
}
Return

GuiEscape:
	ExitApp

Exit:
	Gdip_Shutdown(pToken)
	ExitApp

WM_LBUTTONDOWN()
{
	If (A_Gui = 1)
	PostMessage, 0xA1, 2
}


# syntax: GAWK -f KNIGHTS_TOUR.AWK [-v sr=x] [-v sc=x]
#
# examples:
#   GAWK -f KNIGHTS_TOUR.AWK                   (default)
#   GAWK -f KNIGHTS_TOUR.AWK -v sr=1 -v sc=1   start at top left (default)
#   GAWK -f KNIGHTS_TOUR.AWK -v sr=1 -v sc=8   start at top right
#   GAWK -f KNIGHTS_TOUR.AWK -v sr=8 -v sc=8   start at bottom right
#   GAWK -f KNIGHTS_TOUR.AWK -v sr=8 -v sc=1   start at bottom left
#
BEGIN {
    N = 8 # board size
    if (sr == "") { sr = 1 } # starting row
    if (sc == "") { sc = 1 } # starting column
    split("2  2 -2 -2 1  1 -1 -1",X," ")
    split("1 -1  1 -1 2 -2  2 -2",Y," ")
    printf("\n%dx%d board: starting row=%d col=%d\n",N,N,sr,sc)
    move(sr,sc,0)
    exit(1)
}
function move(x,y,m) {
    if (cantMove(x,y)) {
      return(0)
    }
    P[x,y] = ++m
    if (m == N ^ 2) {
      printBoard()
      exit(0)
    }
    tryBestMove(x,y,m)
}
function cantMove(x,y) {
    return( P[x,y] || x<1 || x>N || y<1 || y>N )
}
function tryBestMove(x,y,m,  i) {
    i = bestMove(x,y)
    move(x+X[i],y+Y[i],m)
}
function bestMove(x,y,  arg1,arg2,c,i,min,out) {
# Warnsdorff's rule: go to where there are fewest next moves
    min = N ^ 2 + 1
    for (i in X) {
      arg1 = x + X[i]
      arg2 = y + Y[i]
      if (!cantMove(arg1,arg2)) {
        c = countNext(arg1,arg2)
        if (c < min) {
          min = c
          out = i
        }
      }
    }
    return(out)
}
function countNext(x,y,  i,out) {
    for (i in X) {
      out += (!cantMove(x+X[i],y+Y[i]))
    }
    return(out)
}
function printBoard(  i,j,leng) {
    leng = length(N*N)
    for (i=1; i<=N; i++) {
      for (j=1; j<=N; j++) {
        printf(" %*d",leng,P[i,j])
      }
      printf("\n")
    }
}


      VDU 23,22,256;256;16,16,16,128
      VDU 23,23,4;0;0;0;
      OFF
      GCOL 4,15
      FOR x% = 0 TO 512-128 STEP 128
        RECTANGLE FILL x%,0,64,512
      NEXT
      FOR y% = 0 TO 512-128 STEP 128
        RECTANGLE FILL 0,y%,512,64
      NEXT
      GCOL 9

      DIM Board%(7,7)
      X% = 0
      Y% = 0
      Total% = 0
      REPEAT
        Board%(X%,Y%) = TRUE
        IF Total% DRAW X%*64+32,Y%*64+32 ELSE MOVE X%*64+32,Y%*64+32
        Total% += 1
      UNTIL NOT FNchoosemove(X%, Y%)
      IF Total%<>64 STOP
      REPEAT WAIT 1 : UNTIL FALSE
      END

      DEF FNchoosemove(RETURN X%, RETURN Y%)
      LOCAL M%, newx%, newy%
      M% = 9
      PROCtrymove(X%+1, Y%+2, M%, newx%, newy%)
      PROCtrymove(X%+1, Y%-2, M%, newx%, newy%)
      PROCtrymove(X%-1, Y%+2, M%, newx%, newy%)
      PROCtrymove(X%-1, Y%-2, M%, newx%, newy%)
      PROCtrymove(X%+2, Y%+1, M%, newx%, newy%)
      PROCtrymove(X%+2, Y%-1, M%, newx%, newy%)
      PROCtrymove(X%-2, Y%+1, M%, newx%, newy%)
      PROCtrymove(X%-2, Y%-1, M%, newx%, newy%)
      IF M%=9 THEN = FALSE
      X% = newx% : Y% = newy%
      = TRUE

      DEF PROCtrymove(X%, Y%, RETURN M%, RETURN newx%, RETURN newy%)
      LOCAL N%
      IF NOT FNvalidmove(X%,Y%) THEN ENDPROC
      IF FNvalidmove(X%+1,Y%+2) N% += 1
      IF FNvalidmove(X%+1,Y%-2) N% += 1
      IF FNvalidmove(X%-1,Y%+2) N% += 1
      IF FNvalidmove(X%-1,Y%-2) N% += 1
      IF FNvalidmove(X%+2,Y%+1) N% += 1
      IF FNvalidmove(X%+2,Y%-1) N% += 1
      IF FNvalidmove(X%-2,Y%+1) N% += 1
      IF FNvalidmove(X%-2,Y%-1) N% += 1
      IF N%>M% THEN ENDPROC
      IF N%=M% IF RND(2)=1 THEN ENDPROC
      M% = N%
      newx% = X% : newy% = Y%
      ENDPROC

      DEF FNvalidmove(X%,Y%)
      IF X%<0 OR X%>7 OR Y%<0 OR Y%>7 THEN = FALSE
      = NOT(Board%(X%,Y%))


  ( knightsTour
  =     validmoves WarnsdorffSort algebraicNotation init solve
      , x y fieldsToVisit
    .   ~
      |   ( validmoves
          =   x y jumps moves
            .   !arg:(?x.?y)
              & :?moves
              & ( jumps
                =   dx dy Fs fxs fys fx fy
                  .   !arg:(?dx.?dy)
                    & 1 -1:?Fs
                    & !Fs:?fxs
                    &   whl
                      ' ( !fxs:%?fx ?fxs
                        & !Fs:?fys
                        &   whl
                          ' ( !fys:%?fy ?fys
                            &     (   (!x+!fx*!dx.!y+!fy*!dy)
                                    : (>0:<9.>0:<9)
                                  |
                                  )
                                  !moves
                              : ?moves
                            )
                        )
                )
              & jumps$(1.2)
              & jumps$(2.1)
              & !moves
          )
        & ( init
          =   fields x y
            .   :?fields
              & 0:?x
              &   whl
                ' ( 1+!x:<9:?x
                  & 0:?y
                  &   whl
                    ' ( 1+!y:<9:?y
                      & (!x.!y) !fields:?fields
                      )
                  )
              & !fields
          )
        & init$:?fieldsToVisit
        & ( WarnsdorffSort
          =   sum moves elm weightedTerms
            .   ( weightedTerms
                =   pos alts fieldsToVisit moves move weight
                  .     !arg:(%?pos ?alts.?fieldsToVisit)
                      &   (   !fieldsToVisit:!pos
                            & (0.!pos)
                          |   !fieldsToVisit:? !pos ?
                            & validmoves$!pos:?moves
                            & 0:?weight
                            &   whl
                              ' ( !moves:%?move ?moves
                                & (   !fieldsToVisit:? !move ?
                                    & !weight+1:?weight
                                  |
                                  )
                                )
                            & (!weight.!pos)
                          | 0
                          )
                        + weightedTerms$(!alts.!fieldsToVisit)
                    | 0
                )
              & weightedTerms$!arg:?sum
              & :?moves
              &   whl
                ' ( !sum:(#.?elm)+?sum
                  & !moves !elm:?moves
                  )
              & !moves
          )
        & ( solve
          =   pos alts fieldsToVisit A Z tailOfSolution
            .   !arg:(%?pos ?alts.?fieldsToVisit)
              &   (   !fieldsToVisit:?A !pos ?Z
                    & ( !A !Z:&
                      |   solve
                        $ ( WarnsdorffSort$(validmoves$!pos.!A !Z)
                          . !A !Z
                          )
                      )
                  | solve$(!alts.!fieldsToVisit)
                  )
                : ?tailOfSolution
              & !pos !tailOfSolution
          )
        & ( algebraicNotation
          =   x y
            .     !arg:(?x.?y) ?arg
                &   str$(chr$(asc$a+!x+-1) !y " ")
                    algebraicNotation$!arg
              |
          )
        & @(!arg:?x #?y)
        & asc$!x+-1*asc$a+1:?x
        &   str
          $ (algebraicNotation$(solve$((!x.!y).!fieldsToVisit)))
  )
& out$(knightsTour$a1);


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

typedef unsigned char cell;
int dx[] = { -2, -2, -1, 1, 2,  2,  1, -1 };
int dy[] = { -1,  1,  2, 2, 1, -1, -2, -2 };

void init_board(int w, int h, cell **a, cell **b)
{
	int i, j, k, x, y, p = w + 4, q = h + 4;
	/* b is board; a is board with 2 rows padded at each side */
	a[0] = (cell*)(a + q);
	b[0] = a[0] + 2;

	for (i = 1; i < q; i++) {
		a[i] = a[i-1] + p;
		b[i] = a[i] + 2;
	}

	memset(a[0], 255, p * q);
	for (i = 0; i < h; i++) {
		for (j = 0; j < w; j++) {
			for (k = 0; k < 8; k++) {
				x = j + dx[k], y = i + dy[k];
				if (b[i+2][j] == 255) b[i+2][j] = 0;
				b[i+2][j] += x >= 0 && x < w && y >= 0 && y < h;
			}
		}
	}
}

#define E "\033["
int walk_board(int w, int h, int x, int y, cell **b)
{
	int i, nx, ny, least;
	int steps = 0;
	printf(E"H"E"J"E"%d;%dH"E"32m[]"E"m", y + 1, 1 + 2 * x);

	while (1) {
		/* occupy cell */
		b[y][x] = 255;

		/* reduce all neighbors' neighbor count */
		for (i = 0; i < 8; i++)
			b[ y + dy[i] ][ x + dx[i] ]--;

		/* find neighbor with lowest neighbor count */
		least = 255;
		for (i = 0; i < 8; i++) {
			if (b[ y + dy[i] ][ x + dx[i] ] < least) {
				nx = x + dx[i];
				ny = y + dy[i];
				least = b[ny][nx];
			}
		}

		if (least > 7) {
			printf(E"%dH", h + 2);
			return steps == w * h - 1;
		}

		if (steps++) printf(E"%d;%dH[]", y + 1, 1 + 2 * x);
		x = nx, y = ny;
		printf(E"%d;%dH"E"31m[]"E"m", y + 1, 1 + 2 * x);
		fflush(stdout);
		usleep(120000);
	}
}

int solve(int w, int h)
{
	int x = 0, y = 0;
	cell **a, **b;
	a = malloc((w + 4) * (h + 4) + sizeof(cell*) * (h + 4));
	b = malloc((h + 4) * sizeof(cell*));

	while (1) {
		init_board(w, h, a, b);
		if (walk_board(w, h, x, y, b + 2)) {
			printf("Success!\n");
			return 1;
		}
		if (++x >= w) x = 0, y++;
		if (y >= h) {
			printf("Failed to find a solution\n");
			return 0;
		}
		printf("Any key to try next start position");
		getchar();
	}
}

int main(int c, char **v)
{
	int w, h;
	if (c < 2 || (w = atoi(v[1])) <= 0) w = 8;
	if (c < 3 || (h = atoi(v[2])) <= 0) h = w;
	solve(w, h);

	return 0;
}


using System;
using System.Collections.Generic;

namespace prog
{
	class MainClass
	{
		const int N = 8;

		readonly static int[,] moves = { {+1,-2},{+2,-1},{+2,+1},{+1,+2},
			                         {-1,+2},{-2,+1},{-2,-1},{-1,-2} };
		struct ListMoves
		{
			public int x, y;
			public ListMoves( int _x, int _y ) { x = _x; y = _y; }
		}

		public static void Main (string[] args)
		{
			int[,] board = new int[N,N];
			board.Initialize();

			int x = 0,						// starting position
			    y = 0;

			List<ListMoves> list = new List<ListMoves>(N*N);
			list.Add( new ListMoves(x,y) );

			do
			{
				if ( Move_Possible( board, x, y ) )
				{
					int move = board[x,y];
					board[x,y]++;
					x += moves[move,0];
					y += moves[move,1];
					list.Add( new ListMoves(x,y) );
				}
				else
				{
					if ( board[x,y] >= 8 )
					{
						board[x,y] = 0;
						list.RemoveAt(list.Count-1);
						if ( list.Count == 0 )
						{
							Console.WriteLine( "No solution found." );
							return;
						}
						x = list[list.Count-1].x;
						y = list[list.Count-1].y;
					}
					board[x,y]++;
				}
			}
			while( list.Count < N*N );

			int last_x = list[0].x,
			    last_y = list[0].y;
			string letters = "ABCDEFGH";
			for( int i=1; i<list.Count; i++ )
			{
				Console.WriteLine( string.Format("{0,2}:  ", i) + letters[last_x] + (last_y+1) + " - " + letters[list[i].x] + (list[i].y+1) );

				last_x = list[i].x;
				last_y = list[i].y;
			}
		}

		static bool Move_Possible( int[,] board, int cur_x, int cur_y )
		{
			if ( board[cur_x,cur_y] >= 8 )
				return false;

			int new_x = cur_x + moves[board[cur_x,cur_y],0],
			    new_y = cur_y + moves[board[cur_x,cur_y],1];

			if ( new_x >= 0 && new_x < N && new_y >= 0 && new_y < N && board[new_x,new_y] == 0 )
				return true;

			return false;
		}
	}
}


#include <iostream>
#include <iomanip>
#include <array>
#include <string>
#include <tuple>
#include <algorithm>
using namespace std;

template<int N = 8>
class Board
{
public:
    array<pair<int, int>, 8> moves;
    array<array<int, N>, N> data;

    Board()
    {
        moves[0] = make_pair(2, 1);
        moves[1] = make_pair(1, 2);
        moves[2] = make_pair(-1, 2);
        moves[3] = make_pair(-2, 1);
        moves[4] = make_pair(-2, -1);
        moves[5] = make_pair(-1, -2);
        moves[6] = make_pair(1, -2);
        moves[7] = make_pair(2, -1);
    }

    array<int, 8> sortMoves(int x, int y) const
    {
        array<tuple<int, int>, 8> counts;
        for(int i = 0; i < 8; ++i)
        {
            int dx = get<0>(moves[i]);
            int dy = get<1>(moves[i]);

            int c = 0;
            for(int j = 0; j < 8; ++j)
            {
                int x2 = x + dx + get<0>(moves[j]);
                int y2 = y + dy + get<1>(moves[j]);

                if (x2 < 0 || x2 >= N || y2 < 0 || y2 >= N)
                    continue;
                if(data[y2][x2] != 0)
                    continue;

                c++;
            }

            counts[i] = make_tuple(c, i);
        }

        // Shuffle to randomly break ties
        random_shuffle(counts.begin(), counts.end());

        // Lexicographic sort
        sort(counts.begin(), counts.end());

        array<int, 8> out;
        for(int i = 0; i < 8; ++i)
            out[i] = get<1>(counts[i]);
        return out;
    }

    void solve(string start)
    {
        for(int v = 0; v < N; ++v)
            for(int u = 0; u < N; ++u)
                data[v][u] = 0;

        int x0 = start[0] - 'a';
        int y0 = N - (start[1] - '0');
        data[y0][x0] = 1;

        array<tuple<int, int, int, array<int, 8>>, N*N> order;
        order[0] = make_tuple(x0, y0, 0, sortMoves(x0, y0));

        int n = 0;
        while(n < N*N-1)
        {
            int x = get<0>(order[n]);
            int y = get<1>(order[n]);

            bool ok = false;
            for(int i = get<2>(order[n]); i < 8; ++i)
            {
                int dx = moves[get<3>(order[n])[i]].first;
                int dy = moves[get<3>(order[n])[i]].second;

                if(x+dx < 0 || x+dx >= N || y+dy < 0 || y+dy >= N)
                    continue;
                if(data[y + dy][x + dx] != 0)
                    continue;

                get<2>(order[n]) = i + 1;
                ++n;
                data[y+dy][x+dx] = n + 1;
                order[n] = make_tuple(x+dx, y+dy, 0, sortMoves(x+dx, y+dy));
                ok = true;
                break;
            }

            if(!ok) // Failed. Backtrack.
            {
                data[y][x] = 0;
                --n;
            }
        }
    }

    template<int N>
    friend ostream& operator<<(ostream &out, const Board<N> &b);
};

template<int N>
ostream& operator<<(ostream &out, const Board<N> &b)
{
    for (int v = 0; v < N; ++v)
    {
        for (int u = 0; u < N; ++u)
        {
            if (u != 0) out << ",";
            out << setw(3) << b.data[v][u];
        }
        out << endl;
    }
    return out;
}

int main()
{
    Board<5> b1;
    b1.solve("c3");
    cout << b1 << endl;

    Board<8> b2;
    b2.solve("b5");
    cout << b2 << endl;

    Board<31> b3; // Max size for <1000 squares
    b3.solve("a1");
    cout << b3 << endl;
    return 0;
}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;   Solving the knight's tour.                     ;;;
;;;   Warnsdorff's rule with random tie break.       ;;;
;;;   Optionally outputs a closed tour.              ;;;
;;;   Options from interactive prompt.               ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defparameter *side* 8)

(defun generate-chessboard (n)
  (loop for i below n append
    (loop for j below n collect (complex i j))))

(defparameter *chessboard*
  (generate-chessboard *side*))

(defun complex->algebraic (n)
;; returns a string like "b2"
  (concatenate 'string
    ;; 'a' is char #97: add it to the offset
    (string (character  (+ 97 (realpart n))))
    ;; indices start at 0, but algebraic starts at 1
    (string (digit-char (+ 1  (imagpart n))))))

(defun algebraic->complex (string)
;; takes a string like "e4"
  (let ((row (char string 0))
        (col (char string 1)))
    (complex (- (char-code row) 97)
             (- (digit-char-p col) 1))))

(defconstant *knight-directions*
  (list
    (complex  1  2)
    (complex  2  1)
    (complex  1 -2)
    (complex  2 -1)
    (complex -1  2)
    (complex -2  1)
    (complex -1 -2)
    (complex -2 -1)))

(defun find-legal-moves (moves-list)
  ;; 2. the move must not be on a case already visited
  (remove-if (lambda (m) (member m moves-list))
    ;; 1. the move must be within the chessboard
    (intersection
      (mapcar (lambda (i) (+ (car moves-list) i)) *knight-directions*)
      *chessboard*)))

;; Select between two moves by Warnsdorff's rule:
;; pick the one with the lowest index or else
;; randomly break the tie.
;; Takes a cons in the form (n . #C(x y)).
;; This will be the sorting rule for picking the next move.
(defun w-rule (a b)
 (cond ((< (car a) (car b)) t)
       ((> (car a) (car b)) nil)
       ((= (car a) (car b))
         (zerop (random 2)))))

;; For every legal move in a given position,
;; look forward one move and return a cons
;; in the form (n . #C(x y)) where n is
;; how many next free moves follow the first move.
(defun return-weighted-moves (moves)
  (let ((candidates (find-legal-moves moves)))
    (loop for mv in candidates collect
      (cons
        (list-length (find-legal-moves (cons mv moves)))
        mv))))

;; Given a list of weighted moves (as above),
;; pick one according to the w-rule
(defun pick-among-weighted-moves (moves)
  ;; prune dead ends one move early
  (let ((possible-moves
          (remove-if (lambda(m) (zerop (car m))) moves)))
    (cdar (sort possible-moves #'w-rule))))

(defun make-move (moves-list)
    (let ((next-move
            (if (< (list-length moves-list) (1- (list-length *chessboard*)))
              (pick-among-weighted-moves (return-weighted-moves moves-list))
              (car (find-legal-moves moves-list)))))
      (cons next-move moves-list)))

(defun make-tour (moves-list)
;; takes a list of moves as an argument
  (if (null (car moves-list)) ; last move not found: start over
    (make-tour (last moves-list))
    (if (= (list-length moves-list) (list-length *chessboard*))
      moves-list
      (make-tour (make-move moves-list)))))

(defun make-closed-tour (moves-list)
  (let ((tour (make-tour moves-list)))
    (if (tour-closed-p tour)
      tour
      (make-closed-tour moves-list))))

(defun tour-closed-p (tour)
;; takes a full tour as an argument
  (let ((start (car (last tour)))
        (end (car tour)))
    ;; is the first position a legal move, when
    ;; viewed from the last move?
    (if (member start (find-legal-moves (list end))) ; find-legal-moves takes a list
      t nil)))

(defun print-tour-linear (tour)
;; takes a tour (moves list) with the last move first
;; and prints it nicely in algebraic notation
  (let ((moves (mapcar #'complex->algebraic (reverse tour))))
    (format t "~{~A~^ -> ~}" moves)))

(defun tour->matrix (tour)
;; takes a tour and makes a row-by-row 2D matrix
;; from top to bottom (for further formatting & printing)
  (flet ((index-tour (tour) ; 1st local function
           (loop for i below (length tour)
             ;; starting from index 1, not 0, so add 1;
             ;; reverse because the last move is still in the car
             collect (cons (nth i (reverse tour)) (1+ i))))
         (get-row (n tour)  ; 2nd local function
           ;; in every row, the imaginary part (vertical offset) stays the same
           (remove-if-not (lambda (e) (= n (imagpart (car e)))) tour)))
    (let* ((indexed-tour (index-tour tour))
           (ordered-indexed-tour
           ;; make a list of ordered rows
             (loop for i from (1- *side*) downto 0 collect
               (sort (get-row i indexed-tour)
                     (lambda (a b) (< (realpart (car a)) (realpart (car b))))))))
      ;; clean up, leaving only the indices
      (mapcar (lambda (e) (mapcar #'cdr e)) ordered-indexed-tour))))

(defun print-tour-matrix (tour)
  (mapcar (lambda (row)
    (format t "~{~3d~}~&" row)) (tour->matrix tour)))

;;; Handling options

(defstruct options
           closed
           start
           grid)

(defparameter *opts* (make-options))

;;; Interactive part

(defun prompt()
  (format t "Starting case (leave blank for random)? ")
  (let ((start (string (read-line))))
    (if (member start (mapcar #'complex->algebraic *chessboard*) :test #'equal)
      (setf (options-start *opts*) start))
  (format t "Require a closed tour (yes or default to no)? ")
  (let ((closed (read-line)))
    (if (or (equal closed "y") (equal closed "yes"))
      (setf (options-closed *opts*) t)))))

(defun main ()
  (let* ((start
           (if (options-start *opts*)
             (algebraic->complex (options-start *opts*))
             (complex (random *side*) (random *side*))))
         (closed (options-closed *opts*))
         (tour
           (if closed
             (make-closed-tour (list start))
             (make-tour (list start)))))
    (fresh-line)
    (if closed (princ "Closed "))
    (princ "Knight's tour")
    (if (options-start *opts*)
      (princ ":")
      (princ " (starting on a random case):"))
    (fresh-line)
    (print-tour-linear tour)
    (princ #\newline)
    (princ #\newline)
    (print-tour-matrix tour)))

;;; Good to go: invocation!

(prompt)
(main)


(defn isin? [x li]
  (not= [] (filter #(= x %) li)))

(defn options [movements pmoves n]
  (let [x (first (last movements)) y (second (last movements))
        op (vec (map #(vector (+ x (first %)) (+ y (second %))) pmoves))
        vop (filter #(and (>= (first %) 0) (>= (last %) 0)) op)
        vop1 (filter #(and (< (first %) n) (< (last %) n)) vop)]
    (vec (filter #(not (isin? % movements)) vop1))))

(defn next-move [movements pmoves n]
  (let [op (options movements pmoves n)
        sp (map #(vector % (count (options (conj movements %) pmoves n))) op)
        m (apply min (map last sp))]
    (first (rand-nth (filter #(= m (last %)) sp)))))

(defn jumps [n pos]
  (let [movements (vector pos)
        pmoves [[1 2] [1 -2] [2 1] [2 -1]
                [-1 2] [-1 -2] [-2 -1] [-2 1]]]
    (loop [mov movements x 1]
      (if (= x (* n n))
        mov
        (let [np (next-move mov pmoves n)]
          (recur (conj mov np) (inc x)))))))


graph_tours = (graph, max_num_solutions) ->
  # graph is an array of arrays
  # graph[3] = [4, 5] means nodes 4 and 5 are reachable from node 3
  #
  # Returns an array of tours (up to max_num_solutions in size), where
  # each tour is an array of nodes visited in order, and where each
  # tour visits every node in the graph exactly once.
  #
  complete_tours = []
  visited = (false for node in graph)
  dead_ends = ({} for node in graph)
  tour = [0]

  valid_neighbors = (i) ->
    arr = []
    for neighbor in graph[i]
      continue if visited[neighbor]
      continue if dead_ends[i][neighbor]
      arr.push neighbor
    arr

  next_square_to_visit = (i) ->
    arr = valid_neighbors i
    return null if arr.length == 0

    # We traverse to our neighbor who has the fewest neighbors itself.
    fewest_neighbors = valid_neighbors(arr[0]).length
    neighbor = arr[0]
    for i in [1...arr.length]
      n = valid_neighbors(arr[i]).length
      if n < fewest_neighbors
        fewest_neighbors = n
        neighbor = arr[i]
    neighbor

  while tour.length > 0
    current_square = tour[tour.length - 1]
    visited[current_square] = true
    next_square = next_square_to_visit current_square
    if next_square?
      tour.push next_square
      if tour.length == graph.length
        complete_tours.push (n for n in tour) # clone
        break if complete_tours.length == max_num_solutions
      # pessimistically call this a dead end
      dead_ends[current_square][next_square] = true
      current_square = next_square
    else
      # we backtrack
      doomed_square = tour.pop()
      dead_ends[doomed_square] = {}
      visited[doomed_square] = false
  complete_tours

knight_graph = (board_width) ->
  # Turn the Knight's Tour into a pure graph-traversal problem
  # by precomputing all the legal moves.  Returns an array of arrays,
  # where each element in any subarray is the index of a reachable node.
  index = (i, j) ->
    # index squares from 0 to n*n - 1
    board_width * i + j

  reachable_squares = (i, j) ->
    deltas = [
      [ 1,  2]
      [ 1, -2]
      [ 2,  1]
      [ 2, -1]
      [-1,  2]
      [-1, -2]
      [-2,  1]
      [-2, -1]
    ]
    neighbors = []
    for delta in deltas
      [di, dj] = delta
      ii = i + di
      jj = j + dj
      if 0 <= ii < board_width
        if 0 <= jj < board_width
          neighbors.push index(ii, jj)
    neighbors

  graph = []
  for i in [0...board_width]
    for j in [0...board_width]
      graph[index(i, j)] = reachable_squares i, j
  graph

illustrate_knights_tour = (tour, board_width) ->
  pad = (n) ->
    return " _" if !n?
    return " " + n if n < 10
    "#{n}"

  console.log "\n------"
  moves = {}
  for square, i in tour
    moves[square] = i + 1
  for i in [0...board_width]
    s = ''
    for j in [0...board_width]
      s += "  " + pad moves[i*board_width + j]
    console.log s

BOARD_WIDTH = 8
MAX_NUM_SOLUTIONS = 100000

graph = knight_graph BOARD_WIDTH
tours = graph_tours graph, MAX_NUM_SOLUTIONS
console.log "#{tours.length} tours found (showing first and last)"
illustrate_knights_tour tours[0], BOARD_WIDTH
illustrate_knights_tour tours.pop(), BOARD_WIDTH


import std.stdio, std.algorithm, std.random, std.range,
       std.conv, std.typecons, std.typetuple;

int[N][N] knightTour(size_t N=8)(in string start)
in {
    assert(start.length >= 2);
} body {
    static struct P { int x, y; }

    immutable P[8] moves = [P(2,1), P(1,2), P(-1,2), P(-2,1),
                            P(-2,-1), P(-1,-2), P(1,-2), P(2,-1)];
    int[N][N] data;

    int[8] sortMoves(in int x, in int y) {
        int[2][8] counts;
        foreach (immutable i, immutable ref d1; moves) {
            int c = 0;
            foreach (immutable ref d2; moves) {
                immutable p = P(x + d1.x + d2.x, y + d1.y + d2.y);
                if (p.x >= 0 && p.x < N && p.y >= 0 && p.y < N &&
                    data[p.y][p.x] == 0)
                    c++;
            }
            counts[i] = [c, i];
        }

        counts[].randomShuffle; // Shuffle to randomly break ties.
        counts[].sort(); // Lexicographic sort.

        int[8] result = void;
        transversal(counts[], 1).copy(result[]);
        return result;
    }

    immutable p0 = P(start[0] - 'a', N - to!int(start[1 .. $]));
    data[p0.y][p0.x] = 1;

    Tuple!(int, int, int, int[8])[N * N] order;
    order[0] = tuple(p0.x, p0.y, 0, sortMoves(p0.x, p0.y));

    int n = 0;
    while (n < (N * N - 1)) {
        immutable int x = order[n][0];
        immutable int y = order[n][1];
        bool ok = false;
        foreach (immutable i; order[n][2] .. 8) {
            immutable P d = moves[order[n][3][i]];
            if (x+d.x < 0 || x+d.x >= N || y+d.y < 0 || y+d.y >= N)
                continue;

            if (data[y + d.y][x + d.x] == 0) {
                order[n][2] = i + 1;
                n++;
                data[y + d.y][x + d.x] = n + 1;
                order[n] = tuple(x+d.x,y+d.y,0,sortMoves(x+d.x,y+d.y));
                ok = true;
                break;
            }
        }

        if (!ok) { // Failed. Backtrack.
            data[y][x] = 0;
            n--;
        }
    }

    return data;
}

void main() {
    foreach (immutable i, side; TypeTuple!(5, 8, 31, 101)) {
        immutable form = "%(%" ~ text(side ^^ 2).length.text ~ "d %)";
        foreach (ref row; ["c3", "b5", "a1", "a1"][i].knightTour!side)
            writefln(form, row);
        writeln();
    }
}


(require 'plot)
(define *knight-moves*
	'((2 . 1)(2 . -1 ) (1 . -2) (-1 . -2  )(-2 . -1) (-2 . 1) (-1 . 2) (1 . 2)))
(define *hit-squares* null)
(define *legal-moves* null)
(define *tries* 0)

(define (square x y n ) (+ y (* x n)))
(define (dim n) (1- (* n n))) ; n^2 - 1

;; check legal knight move from sq
;; return null or (list destination-square)

(define (legal-disp n sq k-move)
 (let ((x (+ (quotient sq n) (first k-move)))
 	   (y (+  (modulo sq n)  (rest k-move))))
 	   (if (and (>= x 0) (< x n) (>= y 0) (< y n))
 	       (list (square x y n))  null)))

 ;; list of legal destination squares from sq
 (define (legal-moves  sq  k-moves n )
           (if (null? k-moves) null
           (append (legal-moves sq (rest k-moves) n) (legal-disp n sq (first k-moves)))))

;; square freedom = number of destination squares not already reached
(define (freedom sq)
		(for/sum ((dest (vector-ref *legal-moves* sq)))
				(if (vector-ref *hit-squares* dest) 0 1)))

;; The chess adage" A knight on the rim is dim" is false here :
;; choose to move to square with smallest freedom : Warnsdorf's rule
(define (square-sort a b)
	(< (freedom a) (freedom b)))

;; knight tour engine
(define (play sq step starter last-one wants-open)
(set! *tries* (1+ *tries*))
		(vector-set! *hit-squares* sq step) ;; flag used square
		(if (= step last-one) (throw 'HIT last-one)) ;; stop on first path found

		(when (or wants-open ;; cut search iff closed path
		(and  (< step last-one) (> (freedom starter) 0))) ;; this ensures a closed path

		(for ((target (list-sort square-sort (vector-ref *legal-moves* sq))))
			 (unless (vector-ref *hit-squares* target)
			         (play target (1+ step)  starter last-one wants-open))))
		(vector-set! *hit-squares* sq #f)) ;; unflag used square

(define (show-steps n wants-open)
	(string-delimiter "")
	(if wants-open
		(printf "♘-tour: %d tries."  *tries*)
		(printf "♞-closed-tour: %d tries."  *tries*))
	(for ((x n))
		(writeln)
		(for((y n))
        	(write (string-pad-right (vector-ref *hit-squares*  (square x y n)) 4)))))

(define (k-tour (n  8) (starter 0) (wants-open #t))
(set! *hit-squares* (make-vector (* n n) #f))
;; build vector of legal moves for squares 0..n^2-1
(set! *legal-moves*
		(build-vector (* n n) (lambda(sq) (legal-moves sq *knight-moves* n))))
(set! *tries* 0) ; counter
	(try
		(play starter 0 starter (dim n) wants-open)
		(catch (hit mess) (show-steps n wants-open))))


defmodule Board do
  import Integer, only: [is_odd: 1]

  defmodule Cell do
    defstruct [:value, :adj]
  end

  @adjacent  [[-1,-2],[-2,-1],[-2,1],[-1,2],[1,2],[2,1],[2,-1],[1,-2]]

  defp initialize(rows, cols) do
    board = for i <- 1..rows, j <- 1..cols, into: %{}, do: {{i,j}, true}
    for i <- 1..rows, j <- 1..cols, into: %{} do
      adj = for [di,dj] <- @adjacent, board[{i+di, j+dj}], do: {i+di, j+dj}
      {{i,j}, %Cell{value: 0, adj: adj}}
    end
  end

  defp solve(board, ij, num, goal) do
    board = Map.update!(board, ij, fn cell -> %{cell | value: num} end)
    if num == goal do
      throw({:ok, board})
    else
      wdof(board, ij)
      |> Enum.each(fn k -> solve(board, k, num+1, goal) end)
    end
  end

  defp wdof(board, ij) do               # Warnsdorf's rule
    board[ij].adj
    |> Enum.filter(fn k -> board[k].value == 0 end)
    |> Enum.sort_by(fn k ->
         Enum.count(board[k].adj, fn x -> board[x].value == 0 end)
       end)
  end

  defp to_string(board, rows, cols) do
    width = to_string(rows * cols) |> String.length
    format = String.duplicate("~#{width}w ", cols)
    Enum.map_join(1..rows, "\n", fn i ->
      :io_lib.fwrite format, (for j <- 1..cols, do: board[{i,j}].value)
    end)
  end

  def knight_tour(rows, cols, sx, sy) do
    IO.puts "\nBoard (#{rows} x #{cols}), Start: [#{sx}, #{sy}]"
    if is_odd(rows*cols) and is_odd(sx+sy) do
      IO.puts "No solution"
    else
      try do
        initialize(rows, cols)
        |> solve({sx,sy}, 1, rows*cols)
        IO.puts "No solution"
      catch
        {:ok, board} -> IO.puts to_string(board, rows, cols)
      end
    end
  end
end

Board.knight_tour(8,8,4,2)
Board.knight_tour(5,5,3,3)
Board.knight_tour(4,9,1,1)
Board.knight_tour(5,5,1,2)
Board.knight_tour(12,12,2,2)


module Main exposing (main)

import Browser exposing (element)
import Html as H
import Html.Attributes as HA
import List exposing (filter, head, length, map, map2, member, tail)
import List.Extra exposing (andThen, minimumBy)
import String exposing (join)
import Svg exposing (g, line, rect, svg)
import Svg.Attributes exposing (fill, height, style, version, viewBox, width, x, x1, x2, y, y1, y2)
import Svg.Events exposing (onClick)
import Time exposing (every)
import Tuple

type alias Cell =
    ( Int, Int )

type alias BoardSize =
    ( Int, Int )

type alias Model =
    { path : List Cell
    , board : List Cell
    , pause_ms : Float
    , size : BoardSize
    }

type Msg
    = Tick Time.Posix
    | SetStart Cell
    | SetSize BoardSize
    | SetPause Float

boardsize_width: BoardSize -> Int
boardsize_width bs =
    Tuple.second bs

boardsize_height: BoardSize -> Int
boardsize_height bs =
    Tuple.first bs

boardsize_dec: Int -> Int
boardsize_dec n =
    let
        minimum_size = 3
    in
        if n <= minimum_size then
            minimum_size
        else
            n - 1
boardsize_inc: Int -> Int
boardsize_inc n =
    let
        maximum_size = 40
    in
        if n >= maximum_size then
            maximum_size
        else
            n + 1

pause_inc: Float -> Float
pause_inc n =
    n + 10

-- decreasing pause time (ms) increases speed
pause_dec: Float -> Float
pause_dec n =
    let
        minimum_pause = 0
    in
        if n <= minimum_pause then
            minimum_pause
        else
            n - 10

board_init : BoardSize -> List Cell
board_init board_size =
            List.range 0 (boardsize_height board_size - 1)
                |> andThen
                    (\r ->
                        List.range 0 (boardsize_width board_size - 1)
                            |> andThen
                                (\c ->
                                    [ ( r, c ) ]
                                )
                    )

nextMoves : Model -> Cell -> List Cell
nextMoves model ( stRow, stCol ) =
    let
        c =
            [ 1, 2, -1, -2 ]

        km =
            c
                |> andThen
                    (\cRow ->
                        c
                            |> andThen
                                (\cCol ->
                                    if abs cRow == abs cCol then
                                        []

                                    else
                                        [ ( cRow, cCol ) ]
                                )
                    )

        jumps =
            List.map (\( kmRow, kmCol ) -> ( kmRow + stRow, kmCol + stCol )) km
    in
    List.filter (\j -> List.member j model.board && not (List.member j model.path)) jumps

bestMove : Model -> Maybe Cell
bestMove model =
    case List.head model.path of
        Just mph ->
            minimumBy (List.length << nextMoves model) (nextMoves model mph)
        _ ->
            Nothing

-- Initialize the application - https://guide.elm-lang.org/effects/
init : () -> ( Model, Cmd Msg )
init _ =
    let
        -- Initial board height and width
        initial_size =
            8

        -- Initial chess board
        initial_board =
            board_init (initial_size, initial_size)

        initial_path =
            []
        initial_pause =
            10
    in
    ( Model initial_path initial_board initial_pause (initial_size, initial_size), Cmd.none )

-- View the model - https://guide.elm-lang.org/effects/
view : Model -> H.Html Msg
view model =
    let
        showChecker row col =
            rect
                [ x <| String.fromInt col
                , y <| String.fromInt row
                , width "1"
                , height "1"
                , fill <|
                    if modBy 2 (row + col) == 0 then
                        "blue"

                    else
                        "grey"
                , onClick <| SetStart ( row, col )
                ]
                []

        showMove ( row0, col0 ) ( row1, col1 ) =
            line
                [ x1 <| String.fromFloat (toFloat col0 + 0.5)
                , y1 <| String.fromFloat (toFloat row0 + 0.5)
                , x2 <| String.fromFloat (toFloat col1 + 0.5)
                , y2 <| String.fromFloat (toFloat row1 + 0.5)
                , style "stroke:yellow;stroke-width:0.05"
                ]
                []

        render mdl =
            let
                checkers =
                    mdl.board
                        |> andThen
                            (\( r, c ) ->
                                [ showChecker r c ]
                            )

                moves =
                    case List.tail mdl.path of
                        Nothing ->
                            []

                        Just tl ->
                            List.map2 showMove mdl.path tl
            in
            checkers ++ moves

        unvisited =
            length model.board - length model.path

        center =
            [ HA.style "text-align" "center" ]

        table =
            [ HA.style "text-align" "center", HA.style "display" "table", HA.style "width" "auto", HA.style "margin" "auto" ]
        table_row =
            [ HA.style "display" "table-row", HA.style "width" "auto" ]

        table_cell =
            [ HA.style "display" "table-cell", HA.style "width" "auto", HA.style "padding" "1px 3px" ]
        rows =
            boardsize_height model.size

        cols =
            boardsize_width model.size
    in
    H.div
        []
        [ H.h1 center [ H.text "Knight's Tour" ]
        -- controls
        , H.div
            table
            [ H.div -- labels
                table_row
                [ H.div
                    table_cell
                    [ H.text "Rows"]
                , H.div
                    table_cell
                    [ H.text "Columns"]
                , H.div
                    table_cell
                    [ H.text ""]
                , H.div
                    table_cell
                    [ H.text "Pause (ms)"]
                ]
            , H.div
                table_row
                [ H.div -- Increase
                    table_cell
                    [ H.button [onClick <| SetSize ( boardsize_inc rows, cols )] [ H.text "▲"] ]
                , H.div
                    table_cell
                    [ H.button [onClick <| SetSize ( rows, boardsize_inc cols )] [ H.text "▲"] ]
                , H.div
                    table_cell
                    [ H.text ""]
                , H.div
                    table_cell
                    [ H.button [onClick <| SetPause ( pause_inc model.pause_ms )] [ H.text "▲"] ]
                ]
            , H.div
                table_row
                [ H.div -- Value
                    table_cell
                    [ H.text <| String.fromInt rows ]
                , H.div
                    table_cell
                    [ H.text <| String.fromInt cols]
                , H.div
                    table_cell
                    [ H.text ""]
                , H.div
                    table_cell
                    [ H.text <| String.fromFloat model.pause_ms]
                ]
            , H.div
                table_row
                [ H.div -- Decrease
                    table_cell
                    [ H.button [onClick <| SetSize ( boardsize_dec rows, cols )] [ H.text "▼"] ]
                , H.div
                    table_cell
                    [ H.button [onClick <| SetSize ( rows, boardsize_dec cols )] [ H.text "▼"] ]
                , H.div
                    table_cell
                    [ H.text ""]
                , H.div
                    table_cell
                    [ H.button [onClick <| SetPause ( pause_dec model.pause_ms )] [ H.text "▼"] ]
                ]
            ]
        , H.h2 center [ H.text "(pick a square)" ]
        , H.div -- chess board
            center
            [ svg
                [ version "1.1"
                , width (String.fromInt (25 * cols))
                , height (String.fromInt (25 * rows))
                , viewBox
                    (join " "
                        [ String.fromInt 0
                        , String.fromInt 0
                        , String.fromInt cols
                        , String.fromInt rows
                        ]
                    )
                ]
                [ g [] <| render model ]
            ]
        , H.h3 center [ H.text <| "Unvisited count : " ++ String.fromInt unvisited ]
        ]

-- Update the model - https://guide.elm-lang.org/effects/
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    let
        mo =
            case msg of
                SetPause pause ->
                    { model | pause_ms = pause }

                SetSize board_size ->
                    { model | board = board_init board_size, path = [], size = board_size }

                SetStart start ->
                    { model | path = [ start ] }

                Tick _ ->
                    case model.path of
                        [] ->
                            model

                        _ ->
                            case bestMove model of
                                Nothing ->
                                    model

                                Just best ->
                                    { model | path = best :: model.path }
    in
    ( mo, Cmd.none )

-- Subscribe to https://guide.elm-lang.org/effects/
subscriptions : Model -> Sub Msg
subscriptions model =
    Time.every model.pause_ms Tick

-- Application entry point
main: Program () Model Msg
main =
    element -- https://package.elm-lang.org/packages/elm/browser/latest/Browser#element
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


-module( knights_tour ).

-export( [display/1, solve/1, task/0] ).

display( Moves ) ->
	%% The knigh walks the moves {Position, Step_nr} order.
	%% Top left corner is {$a, 8}, Bottom right is {$h, 1}.
	io:fwrite( "Moves:" ),
	lists:foldl( fun display_moves/2, erlang:length(Moves), lists:keysort(2, Moves) ),
	io:nl(),
	[display_row(Y, Moves) || Y <- lists:seq(8, 1, -1)].

solve( First_square ) ->
    try
    bt_loop( 1, next_moves(First_square), [{First_square, 1}] )

    catch
    _:{ok, Moves} -> Moves

    end.

task() ->
	io:fwrite( "Starting {a, 1}~n" ),
	Moves = solve( {$a, 1} ),
	display( Moves ).

bt( N, Move, Moves ) -> bt_reject( is_not_allowed_knight_move(Move, Moves), N, Move, [{Move, N} | Moves] ).

bt_accept( true, _N, _Move, Moves ) -> erlang:throw( {ok, Moves} );
bt_accept( false, N, Move, Moves ) -> bt_loop( N, next_moves(Move), Moves ).

bt_loop( N, New_moves, Moves ) -> [bt( N+1, X, Moves ) || X <- New_moves].

bt_reject( true, _N, _Move, _Moves ) -> backtrack;
bt_reject( false, N, Move, Moves ) -> bt_accept( is_all_knights(Moves), N, Move, Moves ).

display_moves( {{X, Y}, 1}, Max ) ->
	io:fwrite(" ~p. N~c~p", [1, X, Y]),
	Max;
display_moves( {{X, Y}, Max}, Max ) ->
	io:fwrite(" N~c~p~n", [X, Y]),
	Max;
display_moves( {{X, Y}, Step_nr}, Max ) when Step_nr rem 8 =:= 0 ->
	io:fwrite(" N~c~p~n~p. N~c~p", [X, Y, Step_nr, X, Y]),
	Max;
display_moves( {{X, Y}, Step_nr}, Max ) ->
	io:fwrite(" N~c~p ~p. N~c~p", [X, Y, Step_nr, X, Y]),
	Max.

display_row( Row, Moves ) ->
	[io:fwrite(" ~2b", [proplists:get_value({X, Row}, Moves)]) || X <- [$a, $b, $c, $d, $e, $f, $g, $h]],
	io:nl().

is_all_knights( Moves ) when erlang:length(Moves) =:= 64 -> true;
is_all_knights( _Moves ) -> false.

is_asymetric( Start_column, Start_row, Stop_column, Stop_row ) ->
	erlang:abs( Start_column - Stop_column ) =/= erlang:abs( Start_row - Stop_row ).

is_not_allowed_knight_move( Move, Moves ) ->
	no_such_move =/= proplists:get_value( Move, Moves, no_such_move ).

next_moves( {Column, Row} ) ->
	[{X, Y} || X <- next_moves_column(Column), Y <- next_moves_row(Row), is_asymetric(Column, Row, X, Y)].

next_moves_column( $a ) -> [$b, $c];
next_moves_column( $b ) -> [$a, $c, $d];
next_moves_column( $g ) -> [$e, $f, $h];
next_moves_column( $h ) -> [$g, $f];
next_moves_column( C ) -> [C - 2, C - 1, C + 1, C + 2].

next_moves_row( 1 ) -> [2, 3];
next_moves_row( 2 ) -> [1, 3, 4];
next_moves_row( 7 ) -> [5, 6, 8];
next_moves_row( 8 ) -> [6, 7];
next_moves_row( N ) -> [N - 2, N - 1, N + 1, N + 2].


Dim Shared As Integer tamano, xc, yc, nm
Dim As Integer f, qm, nmov, n = 0
Dim As String posini

Cls : Color 11
Input "Tamaño tablero:  ", tamano
Input "Posicion inicial: ", posini

Dim As Integer x = Asc(Mid(posini,1,1))-96
Dim As Integer y = Val(Mid(posini,2,1))
Dim Shared As Integer tablero(tamano,tamano), dx(8), dy(8)
For f = 1 To 8 : Read dx(f), dy(f) : Next f
Data 2,1,1,2,-1,2,-2,1,-2,-1,-1,-2,1,-2,2,-1

Sub FindMoves()
    Dim As Integer i, xt, yt
    If xc < 1 Or yc < 1 Or xc > tamano Or yc > tamano Then nm = 1000: Return
    If tablero(xc,yc) Then nm = 2000: Return
    nm = 0
    For i = 1 To 8
        xt = xc+dx(i)
        yt = yc+dy(i)
        If xt < 1 Or yt < 1 Or xt > tamano Or yt > tamano Then 'Salta este movimiento
        Elseif tablero(xt,yt) Then 'Salta este movimiento
        Else
            nm += 1
        End If
    Next i
End Sub

Color 4, 7 'Pinta tablero
For f = 1 To tamano
    Locate 15-tamano, 3*f: Print "  "; Chr(96+f); " ";
    Locate 17-f, 3*(tamano+1)+1: Print Using "##"; f;
Next f

Color 15, 0
Do
    n += 1
    tablero(x,y) = n
    Locate 17-y, 3*x: Print Using "###"; n;
    If n = tamano*tamano Then Exit Do
    nmov = 100
    For f = 1 To 8
        xc = x+dx(f)
        yc = y+dy(f)
        FindMoves()
        If nm < nmov Then nmov = nm: qm = f
    Next f
    x = x+dx(qm)
    y = y+dy(qm)
    Sleep 1
Loop
Color 14 : Locate Csrlin+tamano, 1
Print " Pulsa cualquier tecla para finalizar..."
Sleep
End