Jump to content

N-queens minimum and knights and bishops: Difference between revisions

→‎{{header|Wren}}: Improvements in line with Go example.
m (→‎{{header|Go}}: Moved some code.)
(→‎{{header|Wren}}: Improvements in line with Go example.)
Line 1,619:
=={{header|Wren}}==
{{libheader|Wren-fmt}}
It'sThis was oringinally based on the Java code [https://www.geeksforgeeks.org/minimum-queens-required-to-cover-all-the-squares-of-a-chess-board/ here] which uses a backtracking algorithm and which I extended to deal with bishops and knights as well as queens when translating to Wren. I've then used the more efficient way for checking the diagonals described [https://www.geeksforgeeks.org/n-queen-problem-using-branch-and-bound/ here] and have now incorporated the improvements made to the Go version.
Although this seems to work and give the correct answers, it's very slow taking about 23.5 minutes to run even when the board sizes are limited to 6 x 6 (bishops) and 5 x 5 (knights).
 
Although far quicker than it was originally (it now gets to 7 knights in less than a minute), it struggles after that and needs north of 26 minutes to get to 10.
It's based on the Java code [https://www.geeksforgeeks.org/minimum-queens-required-to-cover-all-the-squares-of-a-chess-board/ here] which uses a backtracking algorithm and which I extended to deal with bishops and knights as well as queens when translating to Wren. I've used the more efficient way for checking the diagonals described [https://www.geeksforgeeks.org/n-queen-problem-using-branch-and-bound/ here].
<lang ecmascript>import "./fmt" for Fmt
 
Line 1,632:
var minCount
var layout
 
var isAttacked = Fn.new { |piece, row, col|
if (piece == "Q") {
Line 1,641:
diag2Lookup[diag2[row][col]]) return true
} else if (piece == "B") {
if (board[row][col]) return true
if (diag1Lookup[diag1[row][col]] ||
diag2Lookup[diag2[row][col]]) return true
Line 1,656 ⟶ 1,655:
}
return false
}
 
var attacks = Fn.new { |piece, row, col, trow, tcol|
if (piece == "Q") {
return row == trow || col == tcol || (row-trow).abs == (col-tcol).abs
} else if (piece == "B") {
return (row-trow).abs == (col-tcol).abs
} else { // piece == "K"
var rd = (trow - row).abs
var cd = (tcol - col).abs
return (rd == 1 && cd == 2) || (rd == 2 && cd == 1)
}
}
 
Line 1,668 ⟶ 1,679:
 
var placePiece // recursive function
placePiece = Fn.new { |piece, countSoFar, maxCount|
if (countSoFar >= minCount) return
var allAttacked = true
var ti = 0
var tj = 0
for (i in 0...n) {
for (j in 0...n) {
if (!isAttacked.call(piece, i, j)) {
allAttacked = false
ti = i
tj = j
break
}
Line 1,685 ⟶ 1,700:
return
}
forif (icountSoFar in<= 0...nmaxCount) {
forvar si = (jpiece in== 0...n"K") {? 0 : ti
var sj if= (!isAttacked.call(piece, i,== j)"K") {? 0 : tj
for (i in si...n) board[i][j] = true{
for diag1Lookup[diag1[i][(j]] =in truesj...n) {
diag2Lookup[diag2[if (!isAttacked.call(piece, i][j]], =j)) true{
placePiece if ((i == ti && j == tj) || attacks.call(piece, countSoFari, +j, 1ti, tj)) {
board[i][j] = falsetrue
diag1Lookup[diag1[i][j]] if (piece != false"K") {
diag2Lookup diag1Lookup[diag2diag1[i][j]] = falsetrue
diag2Lookup[diag2[i][j]] = true
for (j in 0...n) diag2[i][j] = i - j + n - 1}
placePiece.call(piece, countSoFar + 1, maxCount)
board[i][j] = false
if (piece != "K") {
diag1Lookup[diag1[i][j]] = false
diag2Lookup[diag2[i][j]] = false
}
}
}
}
}
Line 1,700 ⟶ 1,725:
}
 
var start = System.clock
var pieces = ["Q", "B", "K"]
var limits = {"Q": 10, "B": 610, "K": 510}
var names = {"Q": "Queens", "B": "Bishops", "K": "Knights"}
for (piece in pieces) {
Line 1,710 ⟶ 1,736:
board = List.filled(n, null)
for (i in 0...n) board[i] = List.filled(n, false)
diag1if = List.filled(n,piece null!= "K") {
for (i in 0.. diag1 = List.filled(n), {null)
diag1[for (i] =in List0...filled(n, 0) {
for (j in 0...n) diag1[i][j] = iList.filled(n, + j0)
for (ij in 0...n) {diag1[i][j] = i + j
}
diag2 = List.filled(n, null)
diag2[for (i] =in List0...filled(n, 0) {
diag1Lookup diag2[i] = List.filled(2*n-1, false0)
for (j in 0...n) diag2[i][j] = i - j + n - 1
}
diag2Lookup diag1Lookup = List.filled(2*n-1, false)
diag2Lookup = List.filled(2*n-1, false)
}
diag2 = List.filled(n, null)
for (i in 0...n) {
diag2[i] = List.filled(n, 0)
for (j in 0...n) diag2[i][j] = i - j + n - 1
}
diag1Lookup = List.filled(2*n-1, false)
diag2Lookup = List.filled(2*n-1, false)
minCount = Num.maxSafeInteger
layout = ""
placePiece.callfor (piece,maxCount 0in 1..n*n) {
placePiece.call(piece, 0, maxCount)
if (minCount <= n*n) break
Q . . . . . . . }
Fmt.print("$2d x $-2d : $d", n, n, minCount)
if (n == limits[piece]) {
Line 1,733 ⟶ 1,764:
n = n + 1
}
}
}</lang>
System.print("Took %(System.clock - start) seconds.")</lang>
 
{{out}}
Line 1,773 ⟶ 1,805:
5 x 5 : 5
6 x 6 : 6
7 x 7 : 7
8 x 8 : 8
9 x 9 : 9
10 x 10 : 10
 
Bishops on a 610 x 610 board:
 
B. . . B. . . . . . B
. . . B. . . . . . .
. . . B . B . . . .
. . . B . B . B . .
B . . B. B. . . . . .
. . . . . . . . . .
. . . . . B . . . .
. . . . . B . . . .
. . . . . B . . . .
. . Q. . . . . . . .
 
Knights
Line 1,791 ⟶ 1,831:
4 x 4 : 4
5 x 5 : 5
6 x 6 : 8
7 x 7 : 13
8 x 8 : 14
9 x 9 : 14
10 x 10 : 16
 
Knights on a 510 x 510 board:
 
K. . . . . . . . . .
. . K K . . . . . .
. . K K . . . K K .
. . . . . . . K K .
. . . . . . . . . .
. . . . Q. . . . . .
</pre>
. QK K . . . . . . .
If I limit the board size for the queens to 8 x 8, the run time comes down to around 2 minutes 12 seconds and the following example layout is produced:
. .K K . Q . . K K . .
<pre>
. . . . . . K K . .
Queens on a 8 x 8 board:
. . . . . . . . . .
 
Took 1583.020941 seconds.
Q . . . . . . .
. . Q . . . . .
. . . . Q . . .
. Q . . . . . .
. . . Q . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
</pre>
9,485

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.