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

@ -10,10 +10,12 @@ You can extend the problem to solve the puzzle with a board of size &nbsp; <big>
For the number of solutions for small values of &nbsp; '''N''', &nbsp; see &nbsp; [http://oeis.org/A000170 oeis.org sequence A170].
;See also:
* &nbsp; [[Knight's tour]]
* &nbsp; [[Solve a Hidato puzzle]]
* &nbsp; [[Solve a Holy Knight's tour]]
* &nbsp; [[Solve a Numbrix puzzle]]
* &nbsp; [[Solve a Hopido puzzle]]
;Related tasks:
* [[A* search algorithm]]
* [[Solve a Hidato puzzle]]
* [[Solve a Holy Knight's tour]]
* [[Knight's tour]]
* [[Solve a Hopido puzzle]]
* [[Solve a Numbrix puzzle]]
* [[Solve the no connection puzzle]]
<br><br>

View file

@ -1,5 +1,4 @@
* N-QUEENS PROBLEM 04/09/2015
PRINT NOGEN
MACRO
&LAB XDECO &REG,&TARGET
&LAB B I&SYSNDX branch around work area
@ -12,16 +11,21 @@ I&SYSNDX CVD &REG,P&SYSNDX convert to decimal
MVC 0(1,R1),W&SYSNDX+12 move the sign
MVC &TARGET.(12),W&SYSNDX move to target
MEND
PRINT NOGEN
NQUEENS CSECT
SAVE (14,12) save registers on entry
PRINT NOGEN
BALR R12,0 establish addressability
USING *,R12 set base register
ST R13,SAVEA+4 link mySA->prevSA
LA R11,SAVEA mySA
ST R11,8(R13) link prevSA->mySA
LR R13,R11 set mySA pointer
LA R7,LL l
LA R6,1 i=1
LOOPI LR R1,R6 do i=1 to l
SLA R1,1 i*2
STH R6,A-2(R1) a(i)=i
LA R6,1(R6) i=i+1
BCT R7,LOOPI loop do i
OPENEM OPEN (OUTDCB,OUTPUT) open the printer file
LA R9,1 n=1 start of loop
LOOPN CH R9,L do n=1 to l
@ -126,13 +130,13 @@ ELOOPN CLOSE (OUTDCB) close output
LTORG
SAVEA DS 18F save area for chaining
OUTDCB DCB DSORG=PS,MACRF=PM,DDNAME=OUTDD use OUTDD in jcl
L DC H'13' input value
A DC H'01',H'02',H'03',H'04',H'05',H'06'
DC H'07',H'08',H'09',H'10',H'11',H'12'
U DC 46H'0'
S DS 12H
LL EQU 14 ll<=16
L DC AL2(LL) input value
A DS (LL)H
S DS (LL)H
Z DS H
Y DS H
PG DS CL24 buffer
REGS make sure to incld copybook jcl
U DC (4*LL-2)H'0' stack
REGS make sure to include copybook jcl
END NQUEENS

View file

@ -9,146 +9,156 @@ property Test_Count : 0
property Rotated : {}
on run
local diff
local endTime
local msg
local rows
local startTime
set Patterns to {}
set Solutions to {}
set Rotated to {}
set Test_Count to 0
set rows to Make_Empty_List(Grid_Size)
set startTime to current date
Solve(1, rows)
set endTime to current date
set diff to endTime - startTime
set msg to ("Found " & (count Solutions) & " solutions with " & (count Patterns) & " patterns in " & diff & " seconds.") as text
display alert msg
local diff
local endTime
local msg
local rows
local startTime
set Patterns to {}
set Solutions to {}
set Rotated to {}
set Test_Count to 0
set rows to Make_Empty_List(Grid_Size)
set startTime to current date
Solve(1, rows)
set endTime to current date
set diff to endTime - startTime
set msg to ("Found " & (count Solutions) & " solutions with " & (count Patterns) & " patterns in " & diff & " seconds.") as text
display alert msg
return Solutions
end run
on Solve(row as integer, rows as list)
if row is greater than (count rows) then
Append_Solution(rows)
return
end if
repeat with column from 1 to Grid_Size
set Test_Count to Test_Count + 1
if Place_Queen(column, row, rows) then
Solve(row + 1, rows)
end if
end repeat
if row is greater than (count rows) then
Append_Solution(rows)
return
end if
repeat with column from 1 to Grid_Size
set Test_Count to Test_Count + 1
if Place_Queen(column, row, rows) then
Solve(row + 1, rows)
end if
end repeat
end Solve
on abs(n)
if n < 0 then
-n
else
n
end if
end abs
on Place_Queen(column as integer, row as integer, rows as list)
local colDiff
local previousRow
local rowDiff
local testColumn
repeat with previousRow from 1 to (row - 1)
set testColumn to item previousRow of rows
if testColumn is equal to column then
return false
end if
set colDiff to abs (testColumn - column) as integer
set rowDiff to row - previousRow
if colDiff is equal to rowDiff then
return false
end if
end repeat
set item row of rows to column
return true
local colDiff
local previousRow
local rowDiff
local testColumn
repeat with previousRow from 1 to (row - 1)
set testColumn to item previousRow of rows
if testColumn is equal to column then
return false
end if
set colDiff to abs(testColumn - column) as integer
set rowDiff to row - previousRow
if colDiff is equal to rowDiff then
return false
end if
end repeat
set item row of rows to column
return true
end Place_Queen
on Append_Solution(rows as list)
local column
local rowsCopy
local testReflection
local testReflectionText
local testRotation
local testRotationText
local testRotations
copy rows to rowsCopy
set end of Solutions to rowsCopy
local rowsCopy
copy rows to testRotation
set testRotations to {}
repeat 3 times
set testRotation to Rotate(testRotation)
set testRotationText to testRotation as text
if Rotated contains testRotationText then
return
end if
set end of testRotations to testRotationText
set testReflection to Reflect(testRotation)
set testReflectionText to testReflection as text
if Rotated contains testReflectionText then
return
end if
set end of testRotations to testReflectionText
end repeat
repeat with testRotationText in testRotations
set end of Rotated to (contents of testRotationText)
end repeat
set end of Rotated to (rowsCopy as text)
set end of Rotated to (Reflect(rowsCopy) as text)
set end of Patterns to rowsCopy
local column
local rowsCopy
local testReflection
local testReflectionText
local testRotation
local testRotationText
local testRotations
copy rows to rowsCopy
set end of Solutions to rowsCopy
local rowsCopy
copy rows to testRotation
set testRotations to {}
repeat 3 times
set testRotation to Rotate(testRotation)
set testRotationText to testRotation as text
if Rotated contains testRotationText then
return
end if
set end of testRotations to testRotationText
set testReflection to Reflect(testRotation)
set testReflectionText to testReflection as text
if Rotated contains testReflectionText then
return
end if
set end of testRotations to testReflectionText
end repeat
repeat with testRotationText in testRotations
set end of Rotated to (contents of testRotationText)
end repeat
set end of Rotated to (rowsCopy as text)
set end of Rotated to (Reflect(rowsCopy) as text)
set end of Patterns to rowsCopy
end Append_Solution
on Make_Empty_List(depth as integer)
local i
local emptyList
set emptyList to {}
repeat with i from 1 to depth
set end of emptyList to missing value
end repeat
return emptyList
local i
local emptyList
set emptyList to {}
repeat with i from 1 to depth
set end of emptyList to missing value
end repeat
return emptyList
end Make_Empty_List
on Rotate(rows as list)
local column
local newColumn
local newRow
local newRows
local row
local rowCount
set rowCount to (count rows)
set newRows to Make_Empty_List(rowCount)
repeat with row from 1 to rowCount
set column to (contents of item row of rows)
set newRow to column
set newColumn to rowCount - row + 1
set item newRow of newRows to newColumn
end repeat
return newRows
local column
local newColumn
local newRow
local newRows
local row
local rowCount
set rowCount to (count rows)
set newRows to Make_Empty_List(rowCount)
repeat with row from 1 to rowCount
set column to (contents of item row of rows)
set newRow to column
set newColumn to rowCount - row + 1
set item newRow of newRows to newColumn
end repeat
return newRows
end Rotate
on Reflect(rows as list)
local column
local newRows
set newRows to {}
repeat with column in rows
set end of newRows to (count rows) - column + 1
end repeat
return newRows
local column
local newRows
set newRows to {}
repeat with column in rows
set end of newRows to (count rows) - column + 1
end repeat
return newRows
end Reflect

View file

@ -0,0 +1,42 @@
let rec iterate f value = seq {
yield value
yield! iterate f (f value) }
let up i = i + 1
let right i = i
let down i = i - 1
let noCollisionGivenDir solution number dir =
Seq.forall2 (<>) solution (Seq.skip 1 (iterate dir number))
let goodAddition solution number =
List.forall (noCollisionGivenDir solution number) [ up; right; down ]
let rec extendSolution n ps =
[0..n - 1]
|> List.filter (goodAddition ps)
|> List.map (fun num -> num :: ps)
let allSolutions n =
iterate (List.collect (extendSolution n)) [[]]
// Print one solution for the 8x8 case
let printOneSolution () =
allSolutions 8
|> Seq.item 8
|> Seq.head
|> List.iter (fun rowIndex ->
printf "|"
[0..8] |> List.iter (fun i -> printf (if i = rowIndex then "X|" else " |"))
printfn "")
// Print number of solution for the other cases
let printNumberOfSolutions () =
printfn "Size\tNr of solutions"
[1..11]
|> List.map ((fun i -> Seq.item i (allSolutions i)) >> List.length)
|> List.iteri (fun i cnt -> printfn "%d\t%d" (i+1) cnt)
printOneSolution()
printNumberOfSolutions()

View file

@ -0,0 +1,21 @@
| | | |X| | | | | |
| |X| | | | | | | |
| | | | | | |X| | |
| | |X| | | | | | |
| | | | | |X| | | |
| | | | | | | |X| |
| | | | |X| | | | |
|X| | | | | | | | |
Size Nr of solutions
1 1
2 0
3 0
4 2
5 10
6 4
7 40
8 92
9 352
10 724
11 2680

View file

@ -0,0 +1,56 @@
' version 13-04-2017
' compile with: fbc -s console
Dim Shared As ULong count, c()
Sub n_queens(row As ULong, n As ULong, show As ULong = 0)
Dim As ULong x, y
For x = 1 To n
For y = 1 To row -1
If c(y) = x OrElse ((row - y) - Abs(x - c(y))) = 0 Then
Continue For, For
End If
Next
c(row) = x
If row < n Then
n_queens(row +1 , n, show)
Else
count += 1
If show <> 0 Then
For y = 1 To n
Print Using "###"; c(y);
Next
Print
End If
End If
Next
End Sub
' ------=< MAIN >=------
Dim As ULong n = 5
ReDim c(n)
' n_queens(1, n, show = 0 only show total | show <> 0 show every solution
n_queens(1, n, 1)
Print Using "## x ## board, ##### solutions"; n; n; count
Print
For n = 1 To 14
ReDim c(n)
count = 0
n_queens(1, n)
Print Using "A ## x ## board has ######## solutions"; n; n; count
Next
' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End

View file

@ -0,0 +1,50 @@
import Data.List (transpose, intercalate)
queenPuzzle :: Int -> Int -> [[Int]]
queenPuzzle nRows nCols
| nRows <= 0 = [[]]
| otherwise =
foldr
(\solution a ->
a ++
foldr
(\iCol b ->
if safe (nRows - 1) iCol solution
then b ++ [solution ++ [iCol]]
else b)
[]
[1 .. nCols])
[]
(queenPuzzle (nRows - 1) nCols)
where
safe iRow iCol solution =
True `notElem`
zipWith
(\sc sr ->
(iCol == sc) || (sc + sr == iCol + iRow) || (sc - sr == iCol - iRow))
solution
[0 .. iRow - 1]
-- TEST ------------------------------------------------------------------------
-- 10 columns of solutions for the 7*7 board:
showSolutions :: Int -> Int -> [String]
showSolutions nCols nBoardSize =
unlines <$>
(((intercalate " " <$>) . transpose . (boardLines <$>)) <$>
chunksOf nCols (queenPuzzle nBoardSize nBoardSize))
where
boardLines rows =
(\r -> foldMap (\c -> if_ (c == r) "" ".") [1 .. (length rows)]) <$> rows
chunksOf :: Int -> [a] -> [[a]]
chunksOf i xs = take i <$> ($ (:)) (splits xs) []
where
splits [] _ n = []
splits l c n = l `c` splits (drop i l) c n
if_ :: Bool -> a -> a -> a
if_ True x _ = x
if_ False _ y = y
main :: IO ()
main = mapM_ putStrLn $ showSolutions 10 7

View file

@ -0,0 +1,33 @@
function queenPuzzle(rows, columns) {
if (rows <= 0) {
return [[]];
} else {
return addQueen(rows - 1, columns);
}
}
function addQueen(newRow, columns, prevSolution) {
var newSolutions = [];
var prev = queenPuzzle(newRow, columns);
for (var i = 0; i < prev.length; i++) {
var solution = prev[i];
for (var newColumn = 0; newColumn < columns; newColumn++) {
if (!hasConflict(newRow, newColumn, solution))
newSolutions.push(solution.concat([newColumn]))
}
}
return newSolutions;
}
function hasConflict(newRow, newColumn, solution) {
for (var i = 0; i < newRow; i++) {
if (solution[i] == newColumn ||
solution[i] + i == newColumn + newRow ||
solution[i] - i == newColumn - newRow) {
return true;
}
}
return false;
}
console.log(queenPuzzle(8,8));

View file

@ -0,0 +1,101 @@
(() => {
'use strict';
// N QUEENS PROBLEM ------------------------------------------------------
// queenPuzzle :: Int -> Int -> [[Int]]
const queenPuzzle = (nRows, nCols) =>
nRows <= 0 ? [
[]
] : queenPuzzle(nRows - 1, nCols)
.reduce((a, solution) =>
append(a, enumFromTo(0, nCols - 1)
.reduce((b, iCol) =>
safe(nRows - 1, iCol, solution) ? (
b.concat([solution.concat(iCol)])
) : b, [])
), []);
// safe : Int -> Int -> [Int] -> Bool
const safe = (iRow, iCol, solution) => !any(
([sc, sr]) =>
(iCol === sc) || (sc + sr === iCol + iRow) || (sc - sr === iCol - iRow),
zip(solution, enumFromTo(0, iRow - 1))
);
// GENERIC FUNCTIONS -----------------------------------------------------
// abs :: Num a => a -> a
const abs = Math.abs
// any :: (a -> Bool) -> [a] -> Bool
const any = (f, xs) => xs.some(f);
// (++) :: [a] -> [a] -> [a]
const append = (xs, ys) => xs.concat(ys);
// chunksOf :: Int -> [a] -> [[a]]
const chunksOf = (n, xs) =>
xs.reduce((a, _, i, xs) =>
i % n ? a : a.concat([xs.slice(i, i + n)]), []);
// concat :: [[a]] -> [a] | [String] -> String
const concat = xs => {
if (xs.length > 0) {
const unit = typeof xs[0] === 'string' ? '' : [];
return unit.concat.apply(unit, xs);
} else return [];
};
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat.apply([], xs.map(f));
// 2 or more arguments
// curry :: Function -> Function
const curry = (f, ...args) => {
const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :
function () {
return go(xs.concat([].slice.apply(arguments)));
};
return go([].slice.call(args, 1));
};
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = (m, n) =>
Array.from({
length: Math.floor(n - m) + 1
}, (_, i) => m + i);
// intercalate :: String -> [a] -> String
const intercalate = curry((s, xs) => xs.join(s));
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f)
// transpose :: [[a]] -> [[a]]
const transpose = xs =>
xs[0].map((_, iCol) => xs.map(row => row[iCol]));
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// zip :: [a] -> [b] -> [(a,b)]
const zip = (xs, ys) =>
xs.slice(0, Math.min(xs.length, ys.length))
.map((x, i) => [x, ys[i]]);
// TEST ------------------------------------------------------------------
// Ten columns of solutions to the 7*7 board
// showSolutions :: Int -> Int -> String
const showSolutions = (nCols, nBoardSize) =>
intercalate('\n\n', map(unlines,
map(col => map(intercalate(" "), transpose(map(rows =>
map(r => concat(concatMap(c =>
c === r ? '♛' : '.',
enumFromTo(1, rows.length))), rows), col))),
chunksOf(nCols, queenPuzzle(nBoardSize, nBoardSize))
)));
return showSolutions(10, 7);
})();

View file

@ -0,0 +1,30 @@
// version 1.1.3
var count = 0
var c = IntArray(0)
var f = ""
fun nQueens(row: Int, n: Int) {
outer@ for (x in 1..n) {
for (y in 1..row - 1) {
if (c[y] == x) continue@outer
if (row - y == Math.abs(x - c[y])) continue@outer
}
c[row] = x
if (row < n) nQueens(row + 1, n)
else if (++count == 1) f = c.drop(1).map { it - 1 }.toString()
}
}
fun main(args: Array<String>) {
for (n in 1..14) {
count = 0
c = IntArray(n + 1)
f = ""
nQueens(1, n)
println("For a $n x $n board:")
println(" Solutions = $count")
if (count > 0) println(" First is $f")
println()
}
}

View file

@ -0,0 +1,54 @@
--
-- demo\rosetta\n_queens.exw
-- =========================
--
sequence co, -- columns occupied
-- (ro is implicit)
fd, -- forward diagonals
bd, -- backward diagonals
board
atom count
procedure solve(integer row, integer N, integer show)
for col=1 to N do
if not co[col] then
integer fdi = col+row-1,
bdi = row-col+N
if not fd[fdi]
and not bd[bdi] then
board[row][col] = 'Q'
co[col] = 1
fd[fdi] = 1
bd[bdi] = 1
if row=N then
if show then
puts(1,join(board,"\n")&"\n")
puts(1,repeat('=',N)&"\n")
end if
count += 1
else
solve(row+1,N,show)
end if
board[row][col] = '.'
co[col] = 0
fd[fdi] = 0
bd[bdi] = 0
end if
end if
end for
end procedure
procedure n_queens(integer N=8, integer show=1)
co = repeat(0,N)
fd = repeat(0,N*2-1)
bd = repeat(0,N*2-1)
board = repeat(repeat('.',N),N)
count = 0
solve(1,N,show)
printf(1,"%d queens: %d solutions\n",{N,count})
end procedure
for N=1 to 14 do
n_queens(N,N<5)
end for

View file

@ -0,0 +1,19 @@
/*
n-queens.pure
Tectonics:
pure -c queens.pure -o queens
or
pure -q -i queens.pure
*/
using system;
queens n = search n 1 [] with
search n i p = [reverse p] if i>n;
= cat [search n (i+1) ((i,j):p) | j = 1..n; safe (i,j) p];
safe (i,j) p = ~any (check (i,j)) p;
check (i1,j1) (i2,j2)
= i1==i2 || j1==j2 || i1+j1==i2+j2 || i1-j1==i2-j2;
end;
compiling || (puts("queens 4: " + str(queens 4)) $$
puts("Solutions to queens 7: " + str(#queens 7)));

View file

@ -1,49 +1,48 @@
/*REXX program places N queens on an NxN chessboard (the eight queens problem). */
parse arg N . /*obtain optional argument from the CL.*/
if N=='' | N=="," then N=8 /*Not specified: Then use the default.*/
if N<1 then call noSol /*display a message, the board is bad. */
if N<1 then signal nOK /*display a message, the board is bad. */
rank=1; file=1; #=0 /*starting rank&file; #≡number queens.*/
@.=0; pad=left('', 9* (N<18)) /*define empty board; set indentation.*/
do while #<N; @.file.rank=1 /*keep placing queens until we're done.*/
if ok(file,rank) then do; #=#+1 /*Queen not being attacked? Then eureka*/
file=1 /*use another attempt at another file. */
rank=rank+1 /*and also bump the rank counter. */
iterate /*go and try another queen placement. */
end /* [↑] found a good queen placement. */
/* [↓] rank&file ≡ chessboard row&cols*/
do while #<N; @.file.rank=1 /*keep placing queens until we're done.*/
if ok(file, rank) then do; #=#+1; rank=rank+1 /*Queen not being attacked? Then eureka*/
file=1 /*use another attempt at another file. */
iterate /*go and try another queen placement. */
end /* [↑] found a good queen placement. */
@.file.rank=0 /*It isn't safe. So remove this queen.*/
file=file+1 /*So, try the next (higher) file. */
do while file>N; rank=rank-1; if rank==0 then call noSol
do j=1 for N; if \@.j.rank then iterate /*occupied?*/
file=j; @.file.rank=0; #=#-1; file=j+1; leave /*j*/
file=file+1 /*So, try the next (higher) chess file.*/
do while file>N; rank=rank-1; if rank==0 then call nOK
do j=1 for N; if \@.j.rank then iterate /*¿ocupado?*/
@.j.rank=0; #=#-1; file=j+1; leave
end /*j*/
end /*while file>N*/
end /*while #<N*/
say 'A solution for' N "queens:"; a = substr( copies("┼───", N) ,2); say
say pad translate(''a"", '', "") /*display the top rank (of the board).*/
line = ''a""; dither='' /*define a line (bar) for cell boundry.*/
bar = '' ; queen='Q' /*kinds: horizontal, vertical, salad. */
Bqueen = dither || queen || dither /*glyph befitting a black-square queen.*/
Wqueen = ' 'queen" " /* " " " white-square " */
say 'A solution for ' N " queens:"; g=substr( copies("╬═══", N) ,2); say
say pad translate(''g"", '', "") /*display the top rank (of the board).*/
line = ''g""; dither='' /*define a line (bar) for cell boundry.*/
bar = '' ; queen='Q' /*kinds: horizontal, vertical, salad. */
Bqueen = dither || queen || dither /*glyph befitting a blacksquare queen.*/
Wqueen = ' 'queen" " /* " " " whitesquare " */
do rank=1 for N; if rank\==1 then say pad line; _= /*display sep for rank.*/
do file=1 for N; B=(file+rank)//2 /*is the square black? */
Qgylph=Wqueen; if B then Qgylph=Bqueen /*use a dithered queen.*/
if @.file.rank then _=_ || bar || Qgylph /*3-char queen symbol. */
do rank=1 for N; if rank\==1 then say pad line; _= /*display sep for rank.*/
do file=1 for N; B = (file+rank) // 2 /*is the square black? */
Qgylph=Wqueen; if B then Qgylph=Bqueen /*use a dithered queen.*/
if @.file.rank then _=_ || bar || Qgylph /*3char queen symbol. */
else if B then _=_ || bar || copies(dither,3) /*use dithering for sq.*/
else _=_ || bar || copies(' ' ,3) /* " 3 blanks " " */
end /*file*/ /* [↑] preserve square-ish chessboard.*/
end /*file*/ /* [↑] preserve squareish chessboard.*/
say pad _ || bar /*show a single rank of the chessboard.*/
end /*rank*/ /*80 cols can view a 19x19 chessboard.*/
say pad translate(''a"", '', "") /*display the last rank (of the board).*/
say pad translate(''g"", '', "") /*display the last rank (of the board).*/
exit 1 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
noSol: say; say "No solution for" N 'queens.'; say; exit 0
nOK: say; say "No solution for" N 'queens.'; say; exit 0
/*──────────────────────────────────────────────────────────────────────────────────────*/
ok: parse arg f,r; rm=r-1; fm=f-1; fp=f+1
do k=1 for rm; if @.f.k then return 0; end
f=fm; do k=rm by -1 for rm while f\==0; if @.f.k then return 0; f=f-1; end
f=fp; do k=rm by -1 for rm while f <=N; if @.f.k then return 0; f=f+1; end
return 1 /* ↑↑↑↑↑↑↑↑ is queen under attack?*/
ok: parse arg f,r; fp=f+1; rm=r-1 /*if return≡0, then queen isn't safe. */
do k=1 for rm; if @.f.k then return 0; end
f=f-1; do k=rm by -1 for rm while f\==0; if @.f.k then return 0; f=f-1; end
f=fp; do k=rm by -1 for rm while f <=N; if @.f.k then return 0; f=f+1; end
return 1 /*1≡queen is safe. */ /* ↑↑↑↑↑↑↑↑ is queen under attack? */

View file

@ -0,0 +1,5 @@
for(v<-(0 to 7).permutations.filter(v=>(0 to 7).forall(i=>(i+1 to 7).
forall(j=>j-i!=Math.abs(v(i)-v(j)))))){
println("_"*15)
v.map(i=>println("_|"*i+"Q"+"|_"*(7-i)))
}

View file

@ -0,0 +1,74 @@
(import (scheme base)
(scheme write)
(srfi 1))
;; return list of solutions to n-queens problem
(define (n-queens n) ; breadth-first solution
(define (place-initial-row) ; puts a queen on each column of row 0
(list-tabulate n (lambda (col) (list (cons 0 col)))))
(define (place-on-row soln-so-far row)
(define (invalid? col)
(any (lambda (posn)
(or (= col (cdr posn)) ; on same column
(= (abs (- row (car posn))) ; on same diagonal
(abs (- col (cdr posn))))))
soln-so-far))
;
(do ((col 0 (+ 1 col))
(res '() (if (invalid? col)
res
(cons (cons (cons row col) soln-so-far)
res))))
((= col n) res)))
;
(do ((res (place-initial-row)
(apply append
(map (lambda (soln-so-far) (place-on-row soln-so-far row))
res)))
(row 1 (+ 1 row)))
((= row n) res)))
;; display solutions in 2-d array form
(define (pretty-print solutions n)
(define (posn->index posn)
(+ (* n (cdr posn))
(car posn)))
(define (pp solution)
(let ((board (make-vector (square n) ".")))
(for-each (lambda (queen) (vector-set! board
(posn->index queen)
"Q"))
solution)
(let loop ((row 0)
(col 0))
(cond ((= row n)
(newline))
((= col n)
(newline)
(loop (+ 1 row) 0))
(else
(display (vector-ref board (posn->index (cons row col))))
(loop row (+ 1 col)))))))
;
(display (string-append "Found "
(number->string (length solutions))
" solutions for n="
(number->string n)
"\n\n"))
(for-each pp solutions))
;; create table of number of solutions
(do ((n 1 (+ 1 n)))
((> n 10) )
(display n)
(display " ")
(display (length (n-queens n)))
(newline))
;; show some examples
(pretty-print (n-queens 1) 1)
(pretty-print (n-queens 2) 2)
(pretty-print (n-queens 3) 3)
(pretty-print (n-queens 4) 4)
(pretty-print (n-queens 5) 5)
(pretty-print (n-queens 8) 8)

View file

@ -0,0 +1,142 @@
//Length of board side
Board_size = 8;
function flag_out = no_attack(side, board, pos)
//Evaluates (pos(1),pos(2)) in board if it's not on any queen attacking range
//side (scalar): board's side length
//board (sidexside matrix): matrix of 0s and 1s representing queens on a board
//pos (1x2 matrix): postition on board to be evaluated
//flag_out (bool): %T if position is available, and %F otherwise
//Counting queens on rows and columns
row_col = sum(board(pos(1),:)) + sum(board(:,pos(2)));
//Counting queens on first diagonal
diag_1 = sum(...
diag(board, 0 +...
(pos(2)>pos(1))*(pos(2)-pos(1)) +...
(pos(1)>pos(2))*(pos(2)-pos(1))...
)...
);
//Counting queens on second diagonal
a = pos(1) + pos(2);
if a<=side+1 then
rows = [1:a-1]
cols = a - rows;
else
d = 2*(side+1)-a-1;
rows = [side:-1:side-d+1]
cols = a - rows;
end
diag_2 = 0;
for i = 1:length(rows)
diag_2 = diag_2 + board(rows(i),cols(i));
end
//Check if there's any queen
flag_out = ( ~(row_col | diag_1 | diag_2) );
endfunction
//Solution counter
Sol_count = 0;
//"Soltion found" flag
Sol_found = %F;
//Empty board
Board = zeros(Board_size,Board_size);
//Matrix for backtracking
Queens= zeros(Board_size,2);
//Queens counter
N_queens = Board_size;
//Row and column counters
i = 1; j = 1;
//Start counting time
tic();
//Begin search
while i <= Board_size
while j <= Board_size
//Availability flag: check position (i,j)
flag = %F;
if (0 < i & 0 < j) & (i <= Board_size & j <= Board_size) then
flag = no_attack(Board_size,Board,[i j]);
end
//Reset solution flag
Sol_found = %F;
if flag then
//Put a queen on the board if position is available
Board(i,j) = 1;
//Update number of remaining queens
N_queens = N_queens - 1;
//Keep track of queens positions
Queens(Board_size - N_queens,:) = [i j];
//Jump to next row end of line is reached
if i+1<=Board_size
i = i + 1;
end
//Start over from the begining of new line
j = 0;
//Count and flag a solution if all queens have
//been placed on the board
if N_queens == 0 then
Sol_count = Sol_count + 1;
Sol_found = %T;
break
end
end
//Increment column number
j = j + 1;
end
//Increment row number and start from first column
if ~Sol_found then
i = i + 1;
j = 1;
//Limiting placement of the first queen to the first row
//Stop searching solutions if columns of first row
//have been tested
if i == 2 & j == 1 & sum(Board) == 0 then
break
end
end
//Backtracking: if (i,j) reaches the and of the board
//and there are queens left to be placed on it
if ~Sol_found & i == Board_size + 1 & j == 1 then
ind = Board_size - N_queens;
if ind > 0 then
//Recover last queen's position
i = Queens(ind,1);
j = Queens(ind,2);
//Remove it from the board and from the counter
Board(i,j) = 0;
Queens(ind,:) = [0 0];
N_queens = N_queens + 1;
//Move to next column
j = j + 1;
end
end
end
//Printing result on console
disp("There are "+string(Sol_count)+" solutions for a "+...
string(Board_size)+"x"+string(Board_size)+" board.");
//Time elapsed
disp("Time: "+string(toc())+"s.");

View file

@ -0,0 +1,60 @@
mata
real matrix queens(real scalar n) {
real scalar i, j, k, p, q
real rowvector a, s, u, v
real matrix m
m = J(0, n, .)
a = 1..n
s = J(1, n, 0)
u = J(1, 2*n-1, 1)
v = J(1, 2*n-1, 1)
i = j = 1
L1: k = a[j]
a[j] = a[i]
a[i] = k
p = i-k+n
q = i+k-1
if (u[p] & v[q]) {
s[i++] = j
u[p] = v[q] = 0
if (i > n) {
m = m\a
goto L3
}
j = i
goto L1
}
L2: if (++j <= n) goto L1
while (--j > i) {
k = a[i]
a[i] = a[j]
a[j] = k
}
L3: if (--i == 0) return(m)
p = i-a[i]+n
q = i+a[i]-1
j = s[i]
u[p] = v[q] = 1
goto L2
}
a = queens(8)
e = I(8)
1:/e[a[1,.],.]
1 2 3 4 5 6 7 8
+---------------------------------+
1 | 1 . . . . . . . |
2 | . . . . 1 . . . |
3 | . . . . . . . 1 |
4 | . . . . . 1 . . |
5 | . . 1 . . . . . |
6 | . . . . . . 1 . |
7 | . 1 . . . . . . |
8 | . . . 1 . . . . |
+---------------------------------+
rows(a)
92
end

View file

@ -0,0 +1,4 @@
clear
mata: a=queens(8)
getmata (a*)=a
save queens, replace

View file

@ -0,0 +1,58 @@
mata
real matrix queens(real scalar n) {
real rowvector a, u, v
real matrix m
a = 1..n
u = J(1, 2*n-1, 1)
v = J(1, 2*n-1, 1)
m = J(0, n, .)
queens_aux(n, 1, a, u, v, m)
return(m)
}
void queens_aux(real scalar n, real scalar i, real rowvector a,
real rowvector u, real rowvector v, real matrix m) {
real scalar j, k, s
if (i > n) {
m = m\a
} else {
for (k = i; k <= n; k++) {
j = a[k]
p = i+j-1
q = i-j+n
if (u[p] & v[q]) {
u[p] = v[q] = 0
s = a[i]
a[i] = a[k]
a[k] = s
queens_aux(n, i+1, a, u, v, m)
u[p] = v[q] = 1
s = a[i]
a[i] = a[k]
a[k] = s
}
}
}
}
a = queens(8)
e = I(8)
1:/e[a[1,.],.]
1 2 3 4 5 6 7 8
+---------------------------------+
1 | 1 . . . . . . . |
2 | . . . . 1 . . . |
3 | . . . . . . . 1 |
4 | . . . . . 1 . . |
5 | . . 1 . . . . . |
6 | . . . . . . 1 . |
7 | . 1 . . . . . . |
8 | . . . 1 . . . . |
+---------------------------------+
rows(a)
92
end

View file

@ -0,0 +1,58 @@
'N-queens problem - non recursive & structured - vba - 26/02/2017
Sub n_queens()
Const l = 15 'number of queens
Const b = False 'print option
Dim a(l), s(l), u(4 * l - 2)
Dim n, m, i, j, p, q, r, k, t, z
For i = 1 To UBound(a): a(i) = i: Next i
For n = 1 To l
m = 0
i = 1
j = 0
r = 2 * n - 1
Do
i = i - 1
j = j + 1
p = 0
q = -r
Do
i = i + 1
u(p) = 1
u(q + r) = 1
z = a(j): a(j) = a(i): a(i) = z 'Swap a(i), a(j)
p = i - a(i) + n
q = i + a(i) - 1
s(i) = j
j = i + 1
Loop Until j > n Or u(p) Or u(q + r)
If u(p) = 0 Then
If u(q + r) = 0 Then
m = m + 1 'm: number of solutions
If b Then
Debug.Print "n="; n; "m="; m
For k = 1 To n
For t = 1 To n
Debug.Print IIf(a(n - k + 1) = t, "Q", ".");
Next t
Debug.Print
Next k
End If
End If
End If
j = s(i)
Do While j >= n And i <> 0
Do
z = a(j): a(j) = a(i): a(i) = z 'Swap a(i), a(j)
j = j - 1
Loop Until j < i
i = i - 1
p = i - a(i) + n
q = i + a(i) - 1
j = s(i)
u(p) = 0
u(q + r) = 0
Loop
Loop Until i = 0
Debug.Print n, m 'number of queens, number of solutions
Next n
End Sub 'n_queens

View file

@ -0,0 +1,46 @@
'N-queens problem - non recursive & structured - vbs - 24/02/2017
const l=15
dim a(),s(),u(): redim a(l),s(l),u(4*l-2)
for i=1 to l: a(i)=i: next
for n=1 to l
m=0
i=1
j=0
r=2*n-1
Do
i=i-1
j=j+1
p=0
q=-r
Do
i=i+1
u(p)=1
u(q+r)=1
z=a(j): a(j)=a(i): a(i)=z 'swap a(i),a(j)
p=i-a(i)+n
q=i+a(i)-1
s(i)=j
j=i+1
Loop Until j>n Or u(p)<>0 Or u(q+r)<>0
If u(p)=0 Then
If u(q+r)=0 Then
m=m+1 'm: number of solutions
'x="": for k=1 to n: x=x&" "&a(k): next: msgbox x,,m
End If
End If
j=s(i)
Do While j>=n And i<>0
Do
z=a(j): a(j)=a(i): a(i)=z 'swap a(i),a(j)
j=j-1
Loop Until j<i
i=i-1
p=i-a(i)+n
q=i+a(i)-1
j=s(i)
u(p)=0
u(q+r)=0
Loop
Loop Until i=0
wscript.echo n &":"& m
next 'n

View file

@ -0,0 +1,61 @@
'N-queens problem - non recursive & structured - vb.net - 26/02/2017
Module Mod_n_queens
Sub n_queens()
Const l = 15 'number of queens
Const b = False 'print option
Dim a(l), s(l), u(4 * l - 2)
Dim n, m, i, j, p, q, r, k, t, z
Dim w As String
For i = 1 To UBound(a) : a(i) = i : Next i
For n = 1 To l
m = 0
i = 1
j = 0
r = 2 * n - 1
Do
i = i - 1
j = j + 1
p = 0
q = -r
Do
i = i + 1
u(p) = 1
u(q + r) = 1
z = a(j) : a(j) = a(i) : a(i) = z 'Swap a(i), a(j)
p = i - a(i) + n
q = i + a(i) - 1
s(i) = j
j = i + 1
Loop Until j > n Or u(p) Or u(q + r)
If u(p) = 0 Then
If u(q + r) = 0 Then
m = m + 1 'm: number of solutions
If b Then
Debug.Print("n=" & n & " m=" & m) : w = ""
For k = 1 To n
For t = 1 To n
w = w & If(a(n - k + 1) = t, "Q", ".")
Next t
Debug.Print(w)
Next k
End If
End If
End If
j = s(i)
Do While j >= n And i <> 0
Do
z = a(j) : a(j) = a(i) : a(i) = z 'Swap a(i), a(j)
j = j - 1
Loop Until j < i
i = i - 1
p = i - a(i) + n
q = i + a(i) - 1
j = s(i)
u(p) = 0
u(q + r) = 0
Loop
Loop Until i = 0
Debug.Print(n & vbTab & m) 'number of queens, number of solutions
Next n
End Sub 'n_queens
End Module

View file

@ -0,0 +1,58 @@
'N-queens problem - non recursive & structured - vb6 - 25/02/2017
Sub n_queens()
Const l = 15 'number of queens
Const b = False 'print option
Dim a(l), s(l), u(4 * l - 2)
Dim n, m, i, j, p, q, r, k, t, z
For i = 1 To UBound(a): a(i) = i: Next i
For n = 1 To l
m = 0
i = 1
j = 0
r = 2 * n - 1
Do
i = i - 1
j = j + 1
p = 0
q = -r
Do
i = i + 1
u(p) = 1
u(q + r) = 1
z = a(j): a(j) = a(i): a(i) = z 'Swap a(i), a(j)
p = i - a(i) + n
q = i + a(i) - 1
s(i) = j
j = i + 1
Loop Until j > n Or u(p) Or u(q + r)
If u(p) = 0 Then
If u(q + r) = 0 Then
m = m + 1 'm: number of solutions
If b Then
Debug.Print "n="; n; "m="; m
For k = 1 To n
For t = 1 To n
Debug.Print IIf(a(n - k + 1) = t, "Q", ".");
Next t
Debug.Print
Next k
End If
End If
End If
j = s(i)
Do While j >= n And i <> 0
Do
z = a(j): a(j) = a(i): a(i) = z 'Swap a(i), a(j)
j = j - 1
Loop Until j < i
i = i - 1
p = i - a(i) + n
q = i + a(i) - 1
j = s(i)
u(p) = 0
u(q + r) = 0
Loop
Loop Until i = 0
Debug.Print n, m 'number of queens, number of solutions
Next n
End Sub 'n_queens

View file

@ -0,0 +1,9 @@
fcn isAttacked([(x,y)],a,b) // explode list (x,y) into args x & y
{ (x==a or y==b or x+y==a+b or x-y==a-b) }
fcn isSafe(a,b,qs){(not qs.filter1(isAttacked,a,b))} // stop at first attack
fcn queensN(N=8,row=1,queens=T){ // T is read only list
qs := [1..N].filter(isSafe.fpM("101",row,queens)) // fpM makes r&q first & third args
.apply(fcn(c,r,qs){qs+T(r,c)},row,queens);
if (row == N) return(qs);
return(qs.apply(self.fcn.fp(N,row+1)).flatten()); // recurse
}

View file

@ -0,0 +1,6 @@
queens := queensN(4);
println(queens.len()," solution(s):");
queens.apply2(Console.println);
--> 2 solution(s):
L(L(1,2),L(2,4),L(3,1),L(4,3))
L(L(1,3),L(2,1),L(3,4),L(4,2))