September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -1,4 +1,4 @@
[[File:Knight's_tour_7x7.png|200px||right]]
[[File:Knight's_tour_7x7.png|400px||right]]
;Task
[[wp:Knight%27s_tour|Problem]]: you have a standard 8x8 chessboard, empty but for a single knight on some square. Your task is to emit a series of legal knight moves that result in the knight visiting every square on the chessboard exactly once. Note that it is ''not'' a requirement that the tour be "closed"; that is, the knight need not end within a single move of its start position.
@ -11,6 +11,7 @@ Output: move sequence
;Related tasks
* [[A* search algorithm]]
* [[N-queens problem]]
* [[Solve a Hidato puzzle]]
* [[Solve a Holy Knight's tour]]

View file

@ -0,0 +1,255 @@
* 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

View file

@ -0,0 +1,25 @@
(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)))))))

View file

@ -1,33 +1,48 @@
import System (getArgs)
import Data.Char (ord, chr)
import Data.List (minimumBy, (\\), intercalate, sort)
import Data.Ord (comparing)
import Data.List (minimumBy, (\\), intercalate, sort)
type Square = (Int, Int)
board :: [Square]
board = [ (x,y) | x <- [1..8], y <- [1..8] ]
board =
[ (x, y)
| x <- [1 .. 8]
, y <- [1 .. 8] ]
knightMoves :: Square -> [Square]
knightMoves (x,y) = filter (flip elem board) jumps
where jumps = [ (x+i,y+j) | i <- jv, j <- jv, abs i /= abs j ]
jv = [1,-1,2,-2]
knightMoves (x, y) = filter (`elem` board) jumps
where
jumps =
[ (x + i, y + j)
| i <- jv
, j <- jv
, abs i /= abs j ]
jv = [1, -1, 2, -2]
knightTour :: [Square] -> [Square]
knightTour moves
| candMoves == [] = reverse moves
| otherwise = knightTour $ newSquare : moves
where newSquare = minimumBy (comparing (length . findMoves)) candMoves
candMoves = findMoves $ head moves
findMoves sq = knightMoves sq \\ moves
| null candMoves = reverse moves
| otherwise = knightTour $ newSquare : moves
where
newSquare = minimumBy (comparing (length . findMoves)) candMoves
candMoves = findMoves $ head moves
findMoves = (\\ moves) . knightMoves
toSq :: String -> (Int, Int)
toSq [x, y] = (ord x - 96, ord y - 48)
toAlg :: (Int, Int) -> String
toAlg (x, y) = [chr (x + 96), chr (y + 48)]
-- TEST -----------------------------------------------------------------------
sq :: (Int, Int)
sq = toSq "e5" -- Input: starting position on the board, e.g. (5, 5) as "e5"
main :: IO ()
main = do
sq <- fmap (toSq . head) getArgs
printTour $ map toAlg $ knightTour [sq]
where toAlg (x,y) = [chr (x + 96), chr (y + 48)]
toSq [x,y] = ((ord x) - 96, (ord y) - 48)
printTour [] = return ()
printTour tour = do
putStrLn $ intercalate " -> " $ take 8 tour
printTour $ drop 8 tour
main = printTour $ toAlg <$> knightTour [sq]
where
printTour [] = return ()
printTour tour = do
putStrLn $ intercalate " -> " $ take 8 tour
printTour $ drop 8 tour

View file

@ -1,34 +1,28 @@
import java.util.ArrayList
data class Square(val x : Int, val y : Int)
class Square(val x : Int, val y : Int) {
fun equals(s : Square) : Boolean = s.x == x && s.y == y
}
val board = Array(8 * 8, { Square(it / 8 + 1, it % 8 + 1) })
val axisMoves = arrayOf(1, 2, -1, -2)
class Pair<T>(val a : T, val b : T)
val board = Array<Square>(8 * 8, {Square(it / 8 + 1, it % 8 + 1)})
val axisMoves = array(1, 2, -1, -2)
fun allPairs<T>(a : Array<T>) = a flatMap {i -> a map {j -> Pair(i, j)}}
fun <T> allPairs(a: Array<T>) = a.flatMap { i -> a.map { j -> Pair(i, j) } }
fun knightMoves(s : Square) : List<Square> {
val moves = allPairs(axisMoves) filter {Math.abs(it.a) != Math.abs(it.b)}
fun onBoard(s : Square) = board.any {it equals s}
return moves map {Square(s.x + it.a, s.y + it.b)} filter {onBoard(it)}
val moves = allPairs(axisMoves).filter{ Math.abs(it.first) != Math.abs(it.second) }
fun onBoard(s : Square) = board.any {it == s}
return moves.map { Square(s.x + it.first, s.y + it.second) }.filter(::onBoard)
}
fun knightTour(moves : List<Square>) : List<Square> {
fun findMoves(s : Square) = knightMoves(s) filterNot {m -> moves any {it equals m}}
val newSquare = findMoves(moves.last()) minBy {findMoves(it).size}
fun findMoves(s: Square) = knightMoves(s).filterNot { m -> moves.any { it == m } }
val newSquare = findMoves(moves.last()).minBy { findMoves(it).size }
return if (newSquare == null) moves else knightTour(moves + newSquare)
}
fun knightTourFrom(start : Square) = knightTour(array(start).toList())
fun knightTourFrom(start : Square) = knightTour(listOf(start))
fun main(args : Array<String>) {
var col = 0
for (move in knightTourFrom(Square(1, 1))) {
System.out.print("${move.x},${move.y}")
for ((x, y) in knightTourFrom(Square(1, 1))) {
System.out.print("$x,$y")
System.out.print(if (col == 7) "\n" else " ")
col = (col + 1) % 8
}

View file

@ -3,22 +3,23 @@ parse arg N sRank sFile . /*obtain optional arguments fro
if N=='' | N=="," then N=8 /*No boardsize specified? Use default.*/
if sRank=='' | sRank=="," then sRank=N /*No starting rank given? " " */
if sFile=='' | sFile=="," then sFile=1 /* " " file " " " */
NN=N**2; NxN='a ' N"x"N ' chessboard' /*file [↓] [↓] r=rank */
NN=N**2; NxN='a ' N"x"N ' chessboard' /*file [↓] [↓] r=rank */
@.=; do r=1 for N; do f=1 for N; @.r.f=.; end /*f*/; end /*r*/
beg='-1-' /*[↑] create an empty NxN chessboard.*/
Kr = '2 1 -1 -2 -2 -1 1 2' /*the legal "rank" moves for a knight.*/
Kf = '1 2 2 1 -1 -2 -2 -1' /* " " "file" " " " " */
parse var Kr Kr.1 Kr.2 Kr.3 Kr.4 Kr.5 Kr.6 Kr.7 Kr.8 /*parse the legal moves by hand.*/
parse var Kf Kf.1 Kf.2 Kf.3 Kf.4 Kf.5 Kf.6 Kf.7 Kf.8 /* " " " " " " */
beg= '-1-' /*[↑] create an empty NxN chessboard.*/
Kr = '2 1 -1 -2 -2 -1 1 2' /*the legal "rank" moves for a knight.*/
Kf = '1 2 2 1 -1 -2 -2 -1' /* " " "file" " " " " */
kr.M=words(Kr) /*number of possible moves for a Knight*/
parse var Kr Kr.1 Kr.2 Kr.3 Kr.4 Kr.5 Kr.6 Kr.7 Kr.8 /*parse the legal moves by hand*/
parse var Kf Kf.1 Kf.2 Kf.3 Kf.4 Kf.5 Kf.6 Kf.7 Kf.8 /* " " " " " " */
@.sRank.sFile= beg /*the knight's starting position. */
@kt= "knight's tour" /*a handy-dandy literal for the SAYs. */
if \move(2,sRank,sFile) & \(N==1) then say 'No' @kt "solution for" NxN'.'
else say 'A solution for the' @kt "on" NxN':'
!=left('', 9*(n<18)) /*used for indentation of chessboard. */
_=substr(copies("┼───",N),2); say; say ! translate(''_"", '', "") /*a square*/
if \move(2, sRank, sFile) & \(N==1) then say 'No' @kt "solution for" NxN'.'
else say 'A solution for the' @kt "on" NxN':'
!=left('', 9 * (n<18) ) /*used for indentation of chessboard. */
_=substr(copies("┼───",N),2); say; say ! translate(''_"", '', "") /*a square.*/
/* [↓] build a display for chessboard.*/
do r=N for N by -1; if r\==N then say ! ''_""; L=@.
do f=1 for N; ?=@.r.f; if ?==NN then ?='end'; L=L''center(?,3) /*is "end"? */
do r=N for N by -1; if r\==N then say ! ''_""; L=@.
do f=1 for N; ?=@.r.f; if ?==NN then ?='end'; L=L''center(?, 3) /*is "end"?*/
end /*f*/ /*done with rank of the chessboard.*/
say ! translate(L'', , .) /*display a " " " " */
end /*r*/ /*19x19 chessboard can be shown 80 cols*/
@ -26,12 +27,12 @@ _=substr(copies("┼───",N),2); say; say ! translate('┌'_"┐", '
say ! translate(''_"", '', "") /*show the last rank of the chessboard.*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
move: procedure expose @. Kr. Kf. NN; parse arg #,rank,file /*obtain move,rank,file.*/
do t=1 for 8; nr=rank+Kr.t; nf=file+Kf.t /*position of the knight*/
move: procedure expose @. Kr. Kf. NN; parse arg #,rank,file /*obtain move,rank,file.*/
do t=1 for Kr.M; nr=rank+Kr.t; nf=file+Kf.t /*position of the knight*/
if @.nr.nf==. then do; @.nr.nf=# /*Empty? Knight can move*/
if #==NN then return 1 /*is this the last move?*/
if move(#+1,nr,nf) then return 1 /* " " " " " */
@.nr.nf=. /*undo the above move. */
end /*try different move. */
end /*t*/ /* [↑] all moves tried.*/
return 0 /*tour is not possible. */
return 0 /*tour is not possible. */

View file

@ -0,0 +1,3 @@
val b=Seq.tabulate(8,8,8,8)((x,y,z,t)=>(1L<<(x*8+y),1L<<(z*8+t),f"${97+z}%c${49+t}%c",(x-z)*(x-z)+(y-t)*(y-t)==5)).flatten.flatten.flatten.filter(_._4).groupBy(_._1)
def f(p:Long,s:Long,v:Any){if(-1L!=s)b(p).foreach(x=>if((s&x._2)==0)f(x._2,s|x._2,v+x._3))else println(v)}
f(1,1,"a1")

View file

@ -0,0 +1,50 @@
import <Utilities/Sequence.sl>;
import <Utilities/Conversion.sl>;
main(args(2)) :=
let
N := stringToInt(args[1]) when size(args) > 0 else 8;
M := stringToInt(args[2]) when size(args) > 1 else N;
startX := stringToInt(args[3]) when size(args) > 2 else 1;
startY := stringToInt(args[4]) when size(args) > 3 else 1;
board[i,j] := 0 foreach i within 1 ... N, j within 1 ... M;
spacing := size(toString(N*M)) + 1;
in
join(printRow(
tour(setBoard(board, startX, startX, 1), [startX,startY], 2),
spacing));
potentialMoves := [[2,1], [2,-1], [1,2], [1,-2], [-1,2], [-1,-2], [-2,1], [-2,-1]];
printRow(row(1), spacing) := join(printSquare(row, spacing)) ++ "\n";
printSquare(val, spacing) :=
let
str := toString(val);
in
duplicate(' ', spacing - size(str)) ++ str;
tour(board(2), current(1), move) :=
let
validMoves := validMove(board, current + potentialMoves);
numMoves[i] := size(validMove(board, validMoves[i] + potentialMoves));
chosenMove := minPosition(numMoves);
in
board when move > size(board) * size(board[1]) else
[] when size(validMoves) = 0 else
[] when move < size(board) * size(board[1]) and numMoves[chosenMove] = 0 else
tour(setBoard(board, validMoves[chosenMove][1], validMoves[chosenMove][2], move), validMoves[chosenMove], move + 1);
validMove(board(2), position(1)) :=
(position when board[position[1], position[2]] = 0)
when position[1] >= 1 and position[1] <= size(board) and position[2] >= 1 and position[2] <= size(board);
minPosition(x(1)) := minPositionHelper(x, 2, 1, x[1]);
minPositionHelper(x(1), i, minPos, minVal) :=
minPos when i > size(x) else
minPositionHelper(x, i + 1, minPos, minVal) when x[i] > minVal else
minPositionHelper(x, i + 1, i, x[i]);
setBoard(board(2), x, y, value)[i,j] :=
value when x = i and y = j else
board[i,j] foreach i within 1 ... size(board), j within 1 ... size(board[1]);

View file

@ -0,0 +1,48 @@
// Use Warnsdorff's rule to perform a knights tour of a 8x8 board in
// linear time.
// See Pohl, Ira (July 1967),
// "A method for finding Hamilton paths and Knight's tours"
// http://portal.acm.org/citation.cfm?id=363463
// Uses back tracking as a tie breaker (for the few cases in a 8x8 tour)
class Board{
var[const]deltas=[[(dx,dy); T(-2,2); T(-1,1); _]].extend(
[[(dx,dy); T(-1,1); T(-2,2); _]]);
fcn init{
var board=L();
(0).pump(64,board.append.fpM("1-",Void)); // fill board with Void
}
fcn idx(x,y) { x*8+y }
fcn isMoveOK(x,y){ (0<=x<8) and (0<=y<8) and Void==board[idx(x,y)] }
fcn gyrate(x,y,f){ // walk all legal moves from (a,b)
deltas.pump(List,'wrap([(dx,dy)]){
x+=dx; y+=dy; if(isMoveOK(x,y)) f(x,y); else Void.Skip
});
}
fcn count(x,y){ n:=Ref(0); gyrate(x,y,n.inc); n.value }
fcn moves(x,y){ gyrate(x,y,fcn(x,y){ T(x,y,count(x,y)) })}
fcn knightsTour(x=0,y=0,n=1){ // using Warnsdorff's rule
board[idx(x,y)]=n;
while(m:=moves(x,y)){
min:=m.reduce('wrap(pc,[(_,_,c)]){ (pc<c) and pc or c },9);
m=m.filter('wrap([(_,_,c)]){ c==min }); // moves with same min moves
if(m.len()>1){ // tie breaker time, may need to backtrack
bs:=board.copy();
if (64==m.pump(Void,'wrap([(a,b)]){
board[idx(a,b)]=n;
n2:=knightsTour(a,b,n+1);
if (n2==64) return(Void.Stop,n2); // found a solution
board=bs.copy();
})) return(64);
return(0);
}
else{
x,y=m[0]; n+=1;
board[idx(x,y)]=n;
}
} //while
return(n);
}
fcn toString{ board.pump(String,T(Void.Read,7),
fcn(ns){ vm.arglist.apply("%2s".fmt).concat(",")+"\n" });
}
}

View file

@ -0,0 +1,2 @@
b:=Board(); b.knightsTour(3,3);
b.println();

View file

@ -0,0 +1,2 @@
[[(x,y); [0..7]; [0..7];
{ b:=Board(); n:=b.knightsTour(x,y); if(n!=64) b.println(">>>",x,",",y) } ]];