September Morn Update
This commit is contained in:
parent
4e2d22a71d
commit
aac6731f2c
6856 changed files with 141342 additions and 21127 deletions
|
|
@ -15,6 +15,7 @@ For the number of solutions for small values of '''N''', see  
|
|||
* [[Solve a Hidato puzzle]]
|
||||
* [[Solve a Holy Knight's tour]]
|
||||
* [[Knight's tour]]
|
||||
* [[Peaceful chess queen armies]]
|
||||
* [[Solve a Hopido puzzle]]
|
||||
* [[Solve a Numbrix puzzle]]
|
||||
* [[Solve the no connection puzzle]]
|
||||
|
|
|
|||
1
Task/N-queens-problem/00META.yaml
Normal file
1
Task/N-queens-problem/00META.yaml
Normal file
|
|
@ -0,0 +1 @@
|
|||
--- {}
|
||||
41
Task/N-queens-problem/FreeBASIC/n-queens-problem-2.freebasic
Normal file
41
Task/N-queens-problem/FreeBASIC/n-queens-problem-2.freebasic
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Sub aux(n As Integer, i As Integer, a() As Integer, _
|
||||
u() As Integer, v() As Integer, ByRef m As LongInt)
|
||||
|
||||
Dim As Integer j, k, p, q
|
||||
If i > n Then
|
||||
m += 1
|
||||
For k = 1 To n : Print a(k); : Next : Print
|
||||
Else
|
||||
For j = i To n
|
||||
k = a(j)
|
||||
p = i - k + n
|
||||
q = i + k - 1
|
||||
If u(p) And v(q) Then
|
||||
u(p) = 0 : v(q) = 0
|
||||
a(j) = a(i) : a(i) = k
|
||||
aux(n, i + 1, a(), u(), v(), m)
|
||||
u(p) = 1 : v(q) = 1
|
||||
a(i) = a(j) : a(j) = k
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Dim As Integer n, i
|
||||
Dim m As LongInt = 1
|
||||
If Command(1) <> "" Then
|
||||
n = CInt(Command(1))
|
||||
ReDim a(1 To n) As Integer
|
||||
ReDim u(1 To 2 * n - 1) As Integer
|
||||
ReDim v(1 To 2 * n - 1) As Integer
|
||||
For i = 1 To n
|
||||
a(i) = i
|
||||
Next
|
||||
For i = 1 To 2 * n - 1
|
||||
u(i) = 1
|
||||
v(i) = 1
|
||||
Next
|
||||
m = 0
|
||||
aux(n, 1, a(), u(), v(), m)
|
||||
Print m
|
||||
End If
|
||||
43
Task/N-queens-problem/FreeBASIC/n-queens-problem-3.freebasic
Normal file
43
Task/N-queens-problem/FreeBASIC/n-queens-problem-3.freebasic
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
Dim As Integer n, i, j, k, p, q
|
||||
Dim m As LongInt = 0
|
||||
|
||||
If Command(1) <> "" Then
|
||||
n = CInt(Command(1))
|
||||
ReDim a(1 To n) As Integer
|
||||
ReDim s(1 To n) As Integer
|
||||
ReDim u(1 To 2 * n - 1) As Integer
|
||||
ReDim v(1 To 2 * n - 1) As Integer
|
||||
For i = 1 To n
|
||||
a(i) = i
|
||||
Next
|
||||
For i = 1 To 2 * n - 1
|
||||
u(i) = 1
|
||||
v(i) = 1
|
||||
Next
|
||||
m = 0
|
||||
i = 1
|
||||
L1: If i > n Then
|
||||
m += 1
|
||||
For k = 1 To n : Print a(k); : Next : Print
|
||||
Goto L4
|
||||
End If
|
||||
j = i
|
||||
L2: k = a(j)
|
||||
p = i - k + n
|
||||
q = i + k - 1
|
||||
If u(p) And v(q) Then
|
||||
u(p) = 0 : v(q) = 0
|
||||
a(j) = a(i) : a(i) = k
|
||||
s(i) = j
|
||||
i += 1
|
||||
Goto L1
|
||||
End If
|
||||
L3: j += 1 : If j <= n Goto L2
|
||||
L4: i -= 1 : If i = 0 Then Print m : End
|
||||
j = s(i)
|
||||
k = a(i) : a(i) = a(j) : a(j) = k
|
||||
p = i - k + n
|
||||
q = i + k - 1
|
||||
u(p) = 1 : v(q) = 1
|
||||
Goto L3
|
||||
End If
|
||||
|
|
@ -1,136 +1,124 @@
|
|||
/*
|
||||
* N-Queens Problem
|
||||
*
|
||||
* For an NxN chess board, 'safely' place a chess queen in every column and row such that none can attack another.
|
||||
* This solution is based Wirth Pascal solution, although a tad cleaner, thus easier to understand as it uses Go/C
|
||||
* style indexing and naming, and also prints the Queen using a Unicode 'rune' (which other languages do not handle natively).
|
||||
*
|
||||
* N rows by N columns are number left to right top to bottom 0 - 7
|
||||
*
|
||||
* There are 2N-1 diagonals (showing an 8x8)
|
||||
* the upper-right to lower-left are numbered row + col that is:
|
||||
* 0 1 2 3 4 5 6 7
|
||||
* 1 2 3 4 5 6 7 8
|
||||
* 2 3 4 5 6 7 8 9
|
||||
* 3 4 5 6 7 8 9 10
|
||||
* 4 5 6 7 8 9 10 11
|
||||
* 5 6 7 8 9 10 11 12
|
||||
* 6 7 8 9 10 11 12 13
|
||||
* 7 8 9 10 11 12 13 14
|
||||
*
|
||||
* the upper-left to lower-right are numbered N-1 + row - col
|
||||
* 7 6 5 4 3 2 1 0
|
||||
* 8 7 6 5 4 3 2 1
|
||||
* 9 8 7 6 5 4 3 2
|
||||
* 10 9 8 7 6 5 4 3
|
||||
* 11 10 9 8 7 6 5 4
|
||||
* 12 11 10 9 8 7 6 5
|
||||
* 13 12 11 10 9 8 7 6
|
||||
* 14 13 12 11 10 9 8 7
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
import "fmt"
|
||||
|
||||
"rosettacode.org/dlx" // or where ever you put the dlx package
|
||||
)
|
||||
const N = 8
|
||||
const HAS_QUEEN = false
|
||||
const EMPTY = true
|
||||
const UNASSIGNED = -1
|
||||
const white_queen = '\u2655'
|
||||
|
||||
|
||||
var row_num[N]int // results, indexed by row will be the column where the queen lives (UNASSIGNED) is empty
|
||||
var right_2_left_diag[(2*N-1)]bool // T if no queen in diag[idx]: row i, column col is diag i+col
|
||||
var left_2_right_diag[(2*N-1)]bool // T is no queen in diag[idx], row i, column col is N-1 + i-col
|
||||
|
||||
|
||||
func printresults() {
|
||||
for col := 0; col < N; col++ {
|
||||
if col != 0 {
|
||||
fmt.Printf(" ");
|
||||
}
|
||||
fmt.Printf("%d,%d", col, row_num[col])
|
||||
}
|
||||
fmt.Printf("\n");
|
||||
for row := 0; row < N; row++ {
|
||||
for col := 0; col < N; col++ {
|
||||
if col == row_num[row] {
|
||||
fmt.Printf(" %c ", white_queen)
|
||||
} else {
|
||||
fmt.Printf(" . ")
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* save a queen on the board by saving where we think it should go, and marking the diagonals as occupied
|
||||
*/
|
||||
|
||||
func savequeen(row int, col int) {
|
||||
row_num[row] = col // save queen column for this row
|
||||
right_2_left_diag[row+col] = HAS_QUEEN // mark forward diags as occupied
|
||||
left_2_right_diag[row-col+(N-1)] = HAS_QUEEN // mark backward diags as occupied
|
||||
}
|
||||
|
||||
/*
|
||||
* backout a previously saved queen by clearing where we put it, and marking the diagonals as empty
|
||||
*/
|
||||
|
||||
func clearqueen(row int, col int) {
|
||||
row_num[row] = UNASSIGNED
|
||||
right_2_left_diag[row+col] = EMPTY
|
||||
left_2_right_diag[row-col+(N-1)] = EMPTY
|
||||
}
|
||||
|
||||
/*
|
||||
* for each column try the solutions
|
||||
*/
|
||||
func trycol(col int) bool {
|
||||
// check each row to look for the first empty row that does not have a diagonal in use too
|
||||
for row := 0; row < N; row++ {
|
||||
if row_num[row] == UNASSIGNED && // has the row been used yet?
|
||||
right_2_left_diag[row+col] == EMPTY && // check for the forward diags
|
||||
left_2_right_diag[row-col+(N-1)] == EMPTY { // check for the backwards diags
|
||||
savequeen(row, col) // this is a possible solution
|
||||
// Tricky part here: going forward thru the col up to but not including the rightmost one
|
||||
// if this fails, we are done, no need to search any more
|
||||
if col < N-1 && !trycol(col+1) {
|
||||
// ok this did not work - we need to try a different row, so undo the guess
|
||||
clearqueen(row, col)
|
||||
} else {
|
||||
// we have a solution on this row/col, start popping the stack.
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false // not a solution for this col, pop the stack, undo the last guess, and try the next one
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.SetPrefix("N-queens: ")
|
||||
log.SetFlags(0)
|
||||
profile := flag.Bool("profile", false, "show DLX profile")
|
||||
flag.Parse()
|
||||
|
||||
for N := 2; N <= 18; N++ {
|
||||
err := nqueens(N, N == 8, *profile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func nqueens(N int, printFirst, profile bool) error {
|
||||
// Build a new DLX matrix with 2N primary columns and 4N-6 secondary
|
||||
// columns: R0..R(N-1), F0..F(N-1), A1..A(2N-3), B1..B(2N-3).
|
||||
// We also know the number of cells and solution rows required.
|
||||
m := dlx.NewWithHint(2*N, 4*N-6, N*N*4-4, 8)
|
||||
|
||||
s := solution{
|
||||
N: N,
|
||||
renumFwd: make([]int, 0, 2*N),
|
||||
renumBack: make([]int, 2*N),
|
||||
printFirst: printFirst,
|
||||
}
|
||||
|
||||
// column indexes
|
||||
iR0 := 0
|
||||
iF0 := iR0 + N
|
||||
iA1 := iF0 + N
|
||||
iB1 := iA1 + 2*N - 3
|
||||
|
||||
// Use "organ-pipe" ordering. E.g. for N=8:
|
||||
// R4 F4 R3 F3 R5 F5 R2 F2 R6 F6 R1 F1 R7 F7 R0 F0
|
||||
// This can reduce the number of link updates required by
|
||||
// almost half for large N; see Knuth's paper for details.
|
||||
mid := N / 2
|
||||
for off := 0; off <= N-mid; off++ {
|
||||
i := mid - off
|
||||
if i >= 0 {
|
||||
s.renumBack[iR0+i] = len(s.renumFwd)
|
||||
s.renumBack[iF0+i] = len(s.renumFwd) + 1
|
||||
s.renumFwd = append(s.renumFwd, iR0+i, iF0+i)
|
||||
}
|
||||
if i = mid + off; off != 0 && i < N {
|
||||
s.renumBack[iR0+i] = len(s.renumFwd)
|
||||
s.renumBack[iF0+i] = len(s.renumFwd) + 1
|
||||
s.renumFwd = append(s.renumFwd, iR0+i, iF0+i)
|
||||
}
|
||||
}
|
||||
|
||||
// Add constraint rows.
|
||||
// TODO: pre-eliminate symetrical possibilities.
|
||||
cols := make([]int, 4)
|
||||
for i := 0; i < N; i++ {
|
||||
for j := 0; j < N; j++ {
|
||||
cols[0] = iR0 + i // Ri, rank i
|
||||
cols[1] = iF0 + j // Fj, file j
|
||||
a := (i + j) // A(i+j), diagonals
|
||||
b := (N - 1 - i + j) // B(N-1-i+j), reverse diagonals
|
||||
cols = cols[:2]
|
||||
// Do organ-pipe reordering for R and F.
|
||||
for i, c := range cols {
|
||||
cols[i] = s.renumBack[c]
|
||||
}
|
||||
|
||||
// Only add diagonals with more than one space; that
|
||||
// is we omit the corners: A0, A(2N-2), B0, and B(2N-2)
|
||||
if 0 < a && a < 2*N-2 {
|
||||
cols = append(cols, iA1+a-1)
|
||||
}
|
||||
if 0 < b && b < 2*N-2 {
|
||||
cols = append(cols, iB1+b-1)
|
||||
}
|
||||
|
||||
m.AddRow(cols)
|
||||
}
|
||||
}
|
||||
|
||||
// Search for solutions.
|
||||
start := time.Now()
|
||||
err := m.Search(s.found)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
elapsed := time.Since(start)
|
||||
fmt.Printf("%d×%d queens has %2d solutions, found in %v\n", N, N, s.count, elapsed)
|
||||
if profile {
|
||||
m.ProfileWrite(os.Stderr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type solution struct {
|
||||
N int
|
||||
count int
|
||||
renumFwd []int // for "organ-pipe" column ordering
|
||||
renumBack []int
|
||||
printFirst bool
|
||||
}
|
||||
|
||||
func (s *solution) found(m *dlx.Matrix) error {
|
||||
s.count++
|
||||
if s.printFirst && s.count == 1 {
|
||||
fmt.Printf("First %d×%d queens solution:\n", s.N, s.N)
|
||||
for _, cols := range m.SolutionIDs(nil) {
|
||||
var r, f int
|
||||
for _, c := range cols {
|
||||
// Undo organ-pipe reodering
|
||||
if c < len(s.renumFwd) {
|
||||
c = s.renumFwd[c]
|
||||
}
|
||||
if c < s.N {
|
||||
r = c + 1
|
||||
} else if c < 2*s.N {
|
||||
f = c - s.N + 1
|
||||
}
|
||||
}
|
||||
fmt.Printf(" R%d F%d\n", r, f)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
for i := 0; i < N ; i++ {
|
||||
row_num[i] = UNASSIGNED
|
||||
}
|
||||
for i := 0; i < 2*N-1 ; i++ {
|
||||
right_2_left_diag[i] = EMPTY
|
||||
}
|
||||
for i := 0; i < 2*N-1 ; i++ {
|
||||
left_2_right_diag[i] = EMPTY
|
||||
}
|
||||
trycol(0)
|
||||
printresults()
|
||||
}
|
||||
|
|
|
|||
136
Task/N-queens-problem/Go/n-queens-problem-3.go
Normal file
136
Task/N-queens-problem/Go/n-queens-problem-3.go
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"rosettacode.org/dlx" // or where ever you put the dlx package
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetPrefix("N-queens: ")
|
||||
log.SetFlags(0)
|
||||
profile := flag.Bool("profile", false, "show DLX profile")
|
||||
flag.Parse()
|
||||
|
||||
for N := 2; N <= 18; N++ {
|
||||
err := nqueens(N, N == 8, *profile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func nqueens(N int, printFirst, profile bool) error {
|
||||
// Build a new DLX matrix with 2N primary columns and 4N-6 secondary
|
||||
// columns: R0..R(N-1), F0..F(N-1), A1..A(2N-3), B1..B(2N-3).
|
||||
// We also know the number of cells and solution rows required.
|
||||
m := dlx.NewWithHint(2*N, 4*N-6, N*N*4-4, 8)
|
||||
|
||||
s := solution{
|
||||
N: N,
|
||||
renumFwd: make([]int, 0, 2*N),
|
||||
renumBack: make([]int, 2*N),
|
||||
printFirst: printFirst,
|
||||
}
|
||||
|
||||
// column indexes
|
||||
iR0 := 0
|
||||
iF0 := iR0 + N
|
||||
iA1 := iF0 + N
|
||||
iB1 := iA1 + 2*N - 3
|
||||
|
||||
// Use "organ-pipe" ordering. E.g. for N=8:
|
||||
// R4 F4 R3 F3 R5 F5 R2 F2 R6 F6 R1 F1 R7 F7 R0 F0
|
||||
// This can reduce the number of link updates required by
|
||||
// almost half for large N; see Knuth's paper for details.
|
||||
mid := N / 2
|
||||
for off := 0; off <= N-mid; off++ {
|
||||
i := mid - off
|
||||
if i >= 0 {
|
||||
s.renumBack[iR0+i] = len(s.renumFwd)
|
||||
s.renumBack[iF0+i] = len(s.renumFwd) + 1
|
||||
s.renumFwd = append(s.renumFwd, iR0+i, iF0+i)
|
||||
}
|
||||
if i = mid + off; off != 0 && i < N {
|
||||
s.renumBack[iR0+i] = len(s.renumFwd)
|
||||
s.renumBack[iF0+i] = len(s.renumFwd) + 1
|
||||
s.renumFwd = append(s.renumFwd, iR0+i, iF0+i)
|
||||
}
|
||||
}
|
||||
|
||||
// Add constraint rows.
|
||||
// TODO: pre-eliminate symetrical possibilities.
|
||||
cols := make([]int, 4)
|
||||
for i := 0; i < N; i++ {
|
||||
for j := 0; j < N; j++ {
|
||||
cols[0] = iR0 + i // Ri, rank i
|
||||
cols[1] = iF0 + j // Fj, file j
|
||||
a := (i + j) // A(i+j), diagonals
|
||||
b := (N - 1 - i + j) // B(N-1-i+j), reverse diagonals
|
||||
cols = cols[:2]
|
||||
// Do organ-pipe reordering for R and F.
|
||||
for i, c := range cols {
|
||||
cols[i] = s.renumBack[c]
|
||||
}
|
||||
|
||||
// Only add diagonals with more than one space; that
|
||||
// is we omit the corners: A0, A(2N-2), B0, and B(2N-2)
|
||||
if 0 < a && a < 2*N-2 {
|
||||
cols = append(cols, iA1+a-1)
|
||||
}
|
||||
if 0 < b && b < 2*N-2 {
|
||||
cols = append(cols, iB1+b-1)
|
||||
}
|
||||
|
||||
m.AddRow(cols)
|
||||
}
|
||||
}
|
||||
|
||||
// Search for solutions.
|
||||
start := time.Now()
|
||||
err := m.Search(s.found)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
elapsed := time.Since(start)
|
||||
fmt.Printf("%d×%d queens has %2d solutions, found in %v\n", N, N, s.count, elapsed)
|
||||
if profile {
|
||||
m.ProfileWrite(os.Stderr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type solution struct {
|
||||
N int
|
||||
count int
|
||||
renumFwd []int // for "organ-pipe" column ordering
|
||||
renumBack []int
|
||||
printFirst bool
|
||||
}
|
||||
|
||||
func (s *solution) found(m *dlx.Matrix) error {
|
||||
s.count++
|
||||
if s.printFirst && s.count == 1 {
|
||||
fmt.Printf("First %d×%d queens solution:\n", s.N, s.N)
|
||||
for _, cols := range m.SolutionIDs(nil) {
|
||||
var r, f int
|
||||
for _, c := range cols {
|
||||
// Undo organ-pipe reodering
|
||||
if c < len(s.renumFwd) {
|
||||
c = s.renumFwd[c]
|
||||
}
|
||||
if c < s.N {
|
||||
r = c + 1
|
||||
} else if c < 2*s.N {
|
||||
f = c - s.N + 1
|
||||
}
|
||||
}
|
||||
fmt.Printf(" R%d F%d\n", r, f)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,40 +1,39 @@
|
|||
import Data.List (transpose, intercalate)
|
||||
import Data.Bool (bool)
|
||||
|
||||
queenPuzzle :: Int -> Int -> [[Int]]
|
||||
queenPuzzle nRows nCols
|
||||
| nRows <= 0 = [[]]
|
||||
| otherwise =
|
||||
foldr
|
||||
(\solution a ->
|
||||
(\qs a ->
|
||||
a ++
|
||||
foldr
|
||||
(\iCol b ->
|
||||
if safe (nRows - 1) iCol solution
|
||||
then b ++ [solution ++ [iCol]]
|
||||
else b)
|
||||
(\iCol b -> bool b (b ++ [qs ++ [iCol]]) (safe (nRows - 1) iCol qs))
|
||||
[]
|
||||
[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 ------------------------------------------------------------------------
|
||||
safe :: Int -> Int -> [Int] -> Bool
|
||||
safe iRow iCol qs =
|
||||
(not . or) $
|
||||
zipWith
|
||||
(\sc sr ->
|
||||
(iCol == sc) || (sc + sr == (iCol + iRow)) || (sc - sr == (iCol - iRow)))
|
||||
qs
|
||||
[0 .. iRow - 1]
|
||||
|
||||
-- TEST ---------------------------------------------------
|
||||
-- 10 columns of solutions for the 7*7 board:
|
||||
showSolutions :: Int -> Int -> [String]
|
||||
showSolutions nCols nBoardSize =
|
||||
showSolutions nCols nSize =
|
||||
unlines <$>
|
||||
(((intercalate " " <$>) . transpose . (boardLines <$>)) <$>
|
||||
chunksOf nCols (queenPuzzle nBoardSize nBoardSize))
|
||||
((fmap (intercalate " ") . transpose . fmap boardLines) <$>
|
||||
chunksOf nCols (queenPuzzle nSize nSize))
|
||||
where
|
||||
boardLines rows =
|
||||
(\r -> foldMap (\c -> if_ (c == r) "♛" ".") [1 .. (length rows)]) <$> rows
|
||||
(\r -> (bool '.' '♛' . (== r)) <$> [1 .. (length rows)]) <$> rows
|
||||
|
||||
chunksOf :: Int -> [a] -> [[a]]
|
||||
chunksOf i xs = take i <$> ($ (:)) (splits xs) []
|
||||
|
|
@ -42,9 +41,5 @@ chunksOf i xs = take i <$> ($ (:)) (splits xs) []
|
|||
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
|
||||
main = (putStrLn . unlines) $ showSolutions 10 7
|
||||
|
|
|
|||
63
Task/N-queens-problem/Haskell/n-queens-problem-5.hs
Normal file
63
Task/N-queens-problem/Haskell/n-queens-problem-5.hs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import Control.Monad
|
||||
import System.Environment
|
||||
|
||||
-- | data types for the puzzle
|
||||
type Row = Int
|
||||
type State = [Row]
|
||||
type Thread = [Row]
|
||||
|
||||
-- | utility functions
|
||||
empty = null
|
||||
|
||||
-- | Check for infeasible states
|
||||
infeasible :: Int -> (State, Thread) -> Bool
|
||||
infeasible n ([], _) = False
|
||||
infeasible n ((r:rs),t) = length rs >= n || attack r rs || infeasible n (rs, t)
|
||||
|
||||
feasible n st = not $ infeasible n st
|
||||
|
||||
-- | Check if a row is attacking another row of a state
|
||||
attack :: Row -> [Row] -> Bool
|
||||
attack r rs = r `elem` rs
|
||||
|| r `elem` (upperDiag rs)
|
||||
|| r `elem` (lowerDiag rs)
|
||||
where
|
||||
upperDiag xs = zipWith (-) xs [1..]
|
||||
lowerDiag xs = zipWith (+) xs [1..]
|
||||
|
||||
-- | Check if it is a goal state
|
||||
isGoal :: Int -> (State, Thread) -> Bool
|
||||
isGoal n (rs,t) = (feasible n (rs,t)) && (length rs == n)
|
||||
|
||||
-- | Perform a move
|
||||
move :: Int -> (State, Thread) -> (State, Thread)
|
||||
move x (s,t) = (x:s, x:t)
|
||||
|
||||
choices n = [1..n]
|
||||
moves n = pure move <*> choices n
|
||||
|
||||
emptySt = ([],[])
|
||||
|
||||
-- | Breadth-first search
|
||||
bfs :: Int -> [(State, Thread)] -> (State, Thread)
|
||||
bfs n [] = error "Couldn't find a feasible solution"
|
||||
bfs n sts | (not.empty) goal = head goal
|
||||
| otherwise = bfs n sts'
|
||||
where
|
||||
goal = filter (isGoal n) sts'
|
||||
sts' = filter (feasible n) $ (moves n) <*> sts
|
||||
|
||||
-- | Depth-first search
|
||||
dfs :: Int -> (State, Thread) -> [(State, Thread)]
|
||||
dfs n st | isGoal n st = [st]
|
||||
| infeasible n st = [emptySt]
|
||||
| otherwise = do x <- [1..n]
|
||||
st' <- dfs n $ move x st
|
||||
guard $ st' /= emptySt
|
||||
return st'
|
||||
|
||||
main = do
|
||||
[narg] <- getArgs
|
||||
let n = read narg :: Int
|
||||
print (bfs n [emptySt])
|
||||
print (head $ dfs n emptySt)
|
||||
114
Task/N-queens-problem/PDP-11-Assembly/n-queens-problem.pdp-11
Normal file
114
Task/N-queens-problem/PDP-11-Assembly/n-queens-problem.pdp-11
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
; "eight queens problem" benchmark test
|
||||
|
||||
.radix 16
|
||||
|
||||
.loc 0
|
||||
|
||||
nop ;
|
||||
mov #scr,@#E800
|
||||
mov #88C6,@#E802
|
||||
; clear the display RAM
|
||||
mov #scr,r0
|
||||
mov #1E0,r1
|
||||
cls: clr (r0)+
|
||||
sob r1,cls
|
||||
; display the initial counter value
|
||||
clr r3
|
||||
mov #scr,r0
|
||||
jsr pc,number
|
||||
; perform the test
|
||||
jsr pc,queens
|
||||
; display the counter
|
||||
mov #scr,r0
|
||||
jsr pc,number
|
||||
finish: br finish
|
||||
|
||||
; display the character R1 at the screen address R0,
|
||||
; advance the pointer R0 to the next column
|
||||
putc: mov r2,-(sp)
|
||||
; R1 <- 6 * R1
|
||||
asl r1 ;* 2
|
||||
mov r1,-(sp)
|
||||
asl r1 ;* 4
|
||||
add (sp)+,r1 ;* 6
|
||||
add #chars,r1
|
||||
mov #6,r2
|
||||
putc1: movb (r1)+,(r0)
|
||||
add #1E,r0
|
||||
sob r2,putc1
|
||||
sub #B2,r0 ;6 * 1E - 2 = B2
|
||||
mov (sp)+,r2
|
||||
rts pc
|
||||
|
||||
print1: jsr pc,putc
|
||||
; print a string pointed to by R2 at the screen address R0,
|
||||
; advance the pointer R0 to the next column,
|
||||
; the string should be terminated by a negative byte
|
||||
print: movb (r2)+,r1
|
||||
bpl print1
|
||||
rts pc
|
||||
|
||||
; display the word R3 decimal at the screen address R0
|
||||
number: mov sp,r1
|
||||
mov #A0A,-(sp)
|
||||
mov (sp),-(sp)
|
||||
mov (sp),-(sp)
|
||||
movb #80,-(r1)
|
||||
numb1: clr r2
|
||||
div #A,r2
|
||||
movb r3,-(r1)
|
||||
mov r2,r3
|
||||
bne numb1
|
||||
mov sp,r2
|
||||
jsr pc,print
|
||||
add #6,sp
|
||||
rts pc
|
||||
|
||||
queens: mov #64,r5 ;100
|
||||
l06: clr r3
|
||||
clr r0
|
||||
l00: cmp #8,r0
|
||||
beq l05
|
||||
inc r0
|
||||
movb #8,ary(r0)
|
||||
l01: inc r3
|
||||
mov r0,r1
|
||||
l02: dec r1
|
||||
beq l00
|
||||
movb ary(r0),r2
|
||||
movb ary(r1),r4
|
||||
sub r2,r4
|
||||
beq l04
|
||||
bcc l03
|
||||
neg r4
|
||||
l03: add r1,r4
|
||||
sub r0,r4
|
||||
bne l02
|
||||
l04: decb ary(r0)
|
||||
bne l01
|
||||
sob r0,l04
|
||||
l05: sob r5,l06
|
||||
mov r3,cnt
|
||||
rts pc
|
||||
|
||||
; characters, width = 8 pixels, height = 6 pixels
|
||||
chars: .byte 3C, 46, 4A, 52, 62, 3C ;digit '0'
|
||||
.byte 18, 28, 8, 8, 8, 3E ;digit '1'
|
||||
.byte 3C, 42, 2, 3C, 40, 7E ;digit '2'
|
||||
.byte 3C, 42, C, 2, 42, 3C ;digit '3'
|
||||
.byte 8, 18, 28, 48, 7E, 8 ;digit '4'
|
||||
.byte 7E, 40, 7C, 2, 42, 3C ;digit '5'
|
||||
.byte 3C, 40, 7C, 42, 42, 3C ;digit '6'
|
||||
.byte 7E, 2, 4, 8, 10, 10 ;digit '7'
|
||||
.byte 3C, 42, 3C, 42, 42, 3C ;digit '8'
|
||||
.byte 3C, 42, 42, 3E, 2, 3C ;digit '9'
|
||||
.byte 0, 0, 0, 0, 0, 0 ;space
|
||||
|
||||
.even
|
||||
|
||||
cnt: .blkw 1
|
||||
ary: .blkb 9
|
||||
|
||||
.loc 200
|
||||
|
||||
scr: ;display RAM
|
||||
|
|
@ -33,9 +33,8 @@ sub try_column {
|
|||
}
|
||||
}
|
||||
|
||||
$board_size = 12; # takes a minute or so, 14,200 solutions
|
||||
$board_size = 12;
|
||||
try_column(0);
|
||||
|
||||
local $" = "\n";
|
||||
print @solutions;
|
||||
print "total ", scalar(@solutions), " solutions\n";
|
||||
#print for @solutions; # un-comment to see all solutions
|
||||
print "total " . @solutions . " solutions\n";
|
||||
|
|
|
|||
33
Task/N-queens-problem/Picat/n-queens-problem.picat
Normal file
33
Task/N-queens-problem/Picat/n-queens-problem.picat
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import cp.
|
||||
|
||||
% CP approach
|
||||
queens_cp(N, Q) =>
|
||||
Q = new_list(N),
|
||||
Q :: 1..N,
|
||||
|
||||
all_different(Q),
|
||||
all_different([$Q[I]-I : I in 1..N]),
|
||||
all_different([$Q[I]+I : I in 1..N]),
|
||||
solve([ff],Q).
|
||||
|
||||
% SAT approach (using a N x N matrix)
|
||||
queens_sat(N,Q) =>
|
||||
Q = new_array(N,N),
|
||||
Q :: 0..1,
|
||||
|
||||
foreach (K in 1-N..N-1)
|
||||
sum([Q[I,J] : I in 1..N, J in 1..N, I-J==K]) #=< 1
|
||||
end,
|
||||
|
||||
foreach (K in 2..2*N)
|
||||
sum([Q[I,J] : I in 1..N, J in 1..N, I+J==K]) #=< 1
|
||||
end,
|
||||
|
||||
foreach (I in 1..N)
|
||||
sum([Q[I,J] : J in 1..N]) #= 1
|
||||
end,
|
||||
|
||||
foreach (J in 1..N)
|
||||
sum([Q[I,J] : I in 1..N]) #= 1
|
||||
end,
|
||||
solve([inout],Q).
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#COMPILE EXE
|
||||
#DIM ALL
|
||||
|
||||
SUB aux(n AS INTEGER, i AS INTEGER, a() AS INTEGER, _
|
||||
u() AS INTEGER, v() AS INTEGER, m AS QUAD)
|
||||
|
||||
LOCAL j, k, p, q AS INTEGER
|
||||
IF i > n THEN
|
||||
INCR m
|
||||
FOR k = 1 TO n : PRINT a(k); : NEXT : PRINT
|
||||
ELSE
|
||||
FOR j = i TO n
|
||||
k = a(j)
|
||||
p = i - k + n
|
||||
q = i + k - 1
|
||||
IF u(p) AND v(q) THEN
|
||||
u(p) = 0 : v(q) = 0
|
||||
a(j) = a(i) : a(i) = k
|
||||
CALL aux(n, i + 1, a(), u(), v(), m)
|
||||
u(p) = 1 : v(q) = 1
|
||||
a(i) = a(j) : a(j) = k
|
||||
END IF
|
||||
NEXT
|
||||
END IF
|
||||
END SUB
|
||||
|
||||
FUNCTION PBMAIN () AS LONG
|
||||
LOCAL n, i AS INTEGER
|
||||
LOCAL m AS QUAD
|
||||
IF COMMAND$(1) <> "" THEN
|
||||
n = VAL(COMMAND$(1))
|
||||
REDIM a(1 TO n) AS INTEGER
|
||||
REDIM u(1 TO 2 * n - 1) AS INTEGER
|
||||
REDIM v(1 TO 2 * n - 1) AS INTEGER
|
||||
FOR i = 1 TO n
|
||||
a(i) = i
|
||||
NEXT
|
||||
FOR i = 1 TO 2 * n - 1
|
||||
u(i) = 1
|
||||
v(i) = 1
|
||||
NEXT
|
||||
m = 0
|
||||
CALL aux(n, 1, a(), u(), v(), m)
|
||||
PRINT m
|
||||
END IF
|
||||
END FUNCTION
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#COMPILE EXE
|
||||
#DIM ALL
|
||||
|
||||
FUNCTION PBMAIN () AS LONG
|
||||
LOCAL n, i, j, k, p, q AS INTEGER
|
||||
LOCAL m AS QUAD
|
||||
IF COMMAND$(1) <> "" THEN
|
||||
n = VAL(COMMAND$(1))
|
||||
REDIM a(1 TO n) AS INTEGER
|
||||
REDIM s(1 TO n) AS INTEGER
|
||||
REDIM u(1 TO 2 * n - 1) AS INTEGER
|
||||
REDIM v(1 TO 2 * n - 1) AS INTEGER
|
||||
FOR i = 1 TO n
|
||||
a(i) = i
|
||||
NEXT
|
||||
FOR i = 1 TO 2 * n - 1
|
||||
u(i) = 1
|
||||
v(i) = 1
|
||||
NEXT
|
||||
m = 0
|
||||
i = 1
|
||||
1 IF i > n THEN
|
||||
INCR m
|
||||
FOR k = 1 TO n : PRINT a(k); : NEXT : PRINT
|
||||
GOTO 4
|
||||
END IF
|
||||
j = i
|
||||
2 k = a(j)
|
||||
p = i - k + n
|
||||
q = i + k - 1
|
||||
IF u(p) AND v(q) THEN
|
||||
u(p) = 0 : v(q) = 0
|
||||
a(j) = a(i) : a(i) = k
|
||||
s(i) = j
|
||||
INCR i
|
||||
GOTO 1
|
||||
END IF
|
||||
3 INCR j : IF j <= n GOTO 2
|
||||
4 DECR i : IF i = 0 THEN PRINT m : EXIT FUNCTION
|
||||
j = s(i)
|
||||
k = a(i) : a(i) = a(j) : a(j) = k
|
||||
p = i - k + n
|
||||
q = i + k - 1
|
||||
u(p) = 1 : v(q) = 1
|
||||
GOTO 3
|
||||
END IF
|
||||
END FUNCTION
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
defint a-z
|
||||
option base 1
|
||||
input "n=",n
|
||||
dim a(n), s(n), u(4*n-2)
|
||||
for i=1 to n: a(i)=i: next
|
||||
for i=1 to 4*n-2: u(i)=0: next
|
||||
m=0
|
||||
i=1
|
||||
r=2*n-1
|
||||
goto 20
|
||||
10 s(i)=j
|
||||
u(p)=1
|
||||
u(q+r)=1
|
||||
incr i
|
||||
20 if i>n goto 60
|
||||
j=i
|
||||
30 z=a(i)
|
||||
y=a(j)
|
||||
p=i-y+n
|
||||
q=i+y-1
|
||||
a(i)=y
|
||||
a(j)=z
|
||||
if u(p)=0 and u(q+r)=0 goto 10
|
||||
40 incr j
|
||||
if j<=n goto 30
|
||||
50 decr j
|
||||
if j=i goto 70
|
||||
swap a(i),a(j)
|
||||
goto 50
|
||||
60 incr m
|
||||
for k=1 to n: print a(k);: next: print
|
||||
70 decr i
|
||||
if i=0 goto 80
|
||||
p=i-a(i)+n
|
||||
q=i+a(i)-1
|
||||
j=s(i)
|
||||
u(p)=0
|
||||
u(q+r)=0
|
||||
goto 40
|
||||
80 print m
|
||||
|
|
@ -1,23 +1,11 @@
|
|||
def queens(n):
|
||||
a = list(range(n))
|
||||
up = [True]*(2*n - 1)
|
||||
down = [True]*(2*n - 1)
|
||||
def sub(i):
|
||||
if i == n:
|
||||
yield tuple(a)
|
||||
else:
|
||||
for k in range(i, n):
|
||||
j = a[k]
|
||||
p = i + j
|
||||
q = i - j + n - 1
|
||||
if up[p] and down[q]:
|
||||
up[p] = down[q] = False
|
||||
a[i], a[k] = a[k], a[i]
|
||||
yield from sub(i + 1)
|
||||
up[p] = down[q] = True
|
||||
a[i], a[k] = a[k], a[i]
|
||||
yield from sub(0)
|
||||
def solve(n, i, a, b, c):
|
||||
if i < n:
|
||||
for j in range(n):
|
||||
if j not in a and i+j not in b and i-j not in c:
|
||||
for solution in solve(n, i+1, a+[j], b+[i+j], c+[i-j]):
|
||||
yield solution
|
||||
else:
|
||||
yield a
|
||||
|
||||
#Count solutions for n=8:
|
||||
sum(1 for p in queens(8))
|
||||
92
|
||||
for solution in solve(8, 0, [], [], []):
|
||||
print(solution)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
def queens_lex(n):
|
||||
def queens(n):
|
||||
a = list(range(n))
|
||||
up = [True]*(2*n - 1)
|
||||
down = [True]*(2*n - 1)
|
||||
|
|
@ -7,25 +7,17 @@ def queens_lex(n):
|
|||
yield tuple(a)
|
||||
else:
|
||||
for k in range(i, n):
|
||||
a[i], a[k] = a[k], a[i]
|
||||
j = a[i]
|
||||
j = a[k]
|
||||
p = i + j
|
||||
q = i - j + n - 1
|
||||
if up[p] and down[q]:
|
||||
up[p] = down[q] = False
|
||||
a[i], a[k] = a[k], a[i]
|
||||
yield from sub(i + 1)
|
||||
up[p] = down[q] = True
|
||||
x = a[i]
|
||||
for k in range(i + 1, n):
|
||||
a[k - 1] = a[k]
|
||||
a[n - 1] = x
|
||||
a[i], a[k] = a[k], a[i]
|
||||
yield from sub(0)
|
||||
|
||||
next(queens(31))
|
||||
(0, 2, 4, 1, 3, 8, 10, 12, 14, 6, 17, 21, 26, 28, 25, 27, 24, 30, 7, 5, 29, 15, 13, 11, 9, 18, 22, 19, 23, 16, 20)
|
||||
|
||||
next(queens_lex(31))
|
||||
(0, 2, 4, 1, 3, 8, 10, 12, 14, 5, 17, 22, 25, 27, 30, 24, 26, 29, 6, 16, 28, 13, 9, 7, 19, 11, 15, 18, 21, 23, 20)
|
||||
|
||||
#Compare to A065188
|
||||
#1, 3, 5, 2, 4, 9, 11, 13, 15, 6, 8, 19, 7, 22, 10, 25, 27, 29, 31, 12, 14, 35, 37, ...
|
||||
#Count solutions for n=8:
|
||||
sum(1 for p in queens(8))
|
||||
92
|
||||
|
|
|
|||
31
Task/N-queens-problem/Python/n-queens-problem-7.py
Normal file
31
Task/N-queens-problem/Python/n-queens-problem-7.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
def queens_lex(n):
|
||||
a = list(range(n))
|
||||
up = [True]*(2*n - 1)
|
||||
down = [True]*(2*n - 1)
|
||||
def sub(i):
|
||||
if i == n:
|
||||
yield tuple(a)
|
||||
else:
|
||||
for k in range(i, n):
|
||||
a[i], a[k] = a[k], a[i]
|
||||
j = a[i]
|
||||
p = i + j
|
||||
q = i - j + n - 1
|
||||
if up[p] and down[q]:
|
||||
up[p] = down[q] = False
|
||||
yield from sub(i + 1)
|
||||
up[p] = down[q] = True
|
||||
x = a[i]
|
||||
for k in range(i + 1, n):
|
||||
a[k - 1] = a[k]
|
||||
a[n - 1] = x
|
||||
yield from sub(0)
|
||||
|
||||
next(queens(31))
|
||||
(0, 2, 4, 1, 3, 8, 10, 12, 14, 6, 17, 21, 26, 28, 25, 27, 24, 30, 7, 5, 29, 15, 13, 11, 9, 18, 22, 19, 23, 16, 20)
|
||||
|
||||
next(queens_lex(31))
|
||||
(0, 2, 4, 1, 3, 8, 10, 12, 14, 5, 17, 22, 25, 27, 30, 24, 26, 29, 6, 16, 28, 13, 9, 7, 19, 11, 15, 18, 21, 23, 20)
|
||||
|
||||
#Compare to A065188
|
||||
#1, 3, 5, 2, 4, 9, 11, 13, 15, 6, 8, 19, 7, 22, 10, 25, 27, 29, 31, 12, 14, 35, 37, ...
|
||||
145
Task/N-queens-problem/Python/n-queens-problem-8.py
Normal file
145
Task/N-queens-problem/Python/n-queens-problem-8.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
'''N Queens problem'''
|
||||
|
||||
from functools import reduce
|
||||
from itertools import chain
|
||||
|
||||
|
||||
# queenPuzzle :: Int -> Int -> [[Int]]
|
||||
def queenPuzzle(nRows, nCols):
|
||||
'''All board patterns of this dimension
|
||||
in which no two Queens share a row,
|
||||
column, or diagonal.
|
||||
'''
|
||||
def go(nRows, nCols):
|
||||
return reduce(
|
||||
lambda a, xys: a + reduce(
|
||||
lambda b, iCol: b + [xys + [iCol]] if (
|
||||
safe(nRows - 1, iCol, xys)
|
||||
) else b,
|
||||
enumFromTo(1)(nCols),
|
||||
[]
|
||||
),
|
||||
go(nRows - 1, nCols),
|
||||
[]
|
||||
) if nRows > 0 else [[]]
|
||||
return go(nRows, nCols)
|
||||
|
||||
|
||||
# safe :: Int -> Int -> [Int] -> Bool
|
||||
def safe(iRow, iCol, pattern):
|
||||
'''True if no two queens in the pattern
|
||||
share a row, column or diagonal.
|
||||
'''
|
||||
def p(sc, sr):
|
||||
return (iCol == sc) or (
|
||||
sc + sr == (iCol + iRow)
|
||||
) or (sc - sr == (iCol - iRow))
|
||||
return not any(map(p, pattern, range(0, iRow)))
|
||||
|
||||
|
||||
# TEST ----------------------------------------------------
|
||||
# main :: IO ()
|
||||
def main():
|
||||
'''Number of solutions for boards of various sizes'''
|
||||
|
||||
n = 5
|
||||
xs = queenPuzzle(n, n)
|
||||
|
||||
print(
|
||||
str(len(xs)) + ' solutions for a {n} * {n} board:\n'.format(n=n)
|
||||
)
|
||||
print(showBoards(10)(xs))
|
||||
|
||||
print(
|
||||
fTable(
|
||||
'\n\n' + main.__doc__ + ':\n'
|
||||
)(str)(lambda n: str(n).rjust(3, ' '))(
|
||||
lambda n: len(queenPuzzle(n, n))
|
||||
)(enumFromTo(1)(10))
|
||||
)
|
||||
|
||||
|
||||
# GENERIC -------------------------------------------------
|
||||
|
||||
# enumFromTo :: (Int, Int) -> [Int]
|
||||
def enumFromTo(m):
|
||||
'''Integer enumeration from m to n.'''
|
||||
return lambda n: list(range(m, 1 + n))
|
||||
|
||||
|
||||
# chunksOf :: Int -> [a] -> [[a]]
|
||||
def chunksOf(n):
|
||||
'''A series of lists of length n, subdividing the
|
||||
contents of xs. Where the length of xs is not evenly
|
||||
divible, the final list will be shorter than n.
|
||||
'''
|
||||
return lambda xs: reduce(
|
||||
lambda a, i: a + [xs[i:n + i]],
|
||||
range(0, len(xs), n), []
|
||||
) if 0 < n else []
|
||||
|
||||
|
||||
# intercalate :: [a] -> [[a]] -> [a]
|
||||
# intercalate :: String -> [String] -> String
|
||||
def intercalate(x):
|
||||
'''The concatenation of xs
|
||||
interspersed with copies of x.
|
||||
'''
|
||||
return lambda xs: x.join(xs) if isinstance(x, str) else list(
|
||||
chain.from_iterable(
|
||||
reduce(lambda a, v: a + [x, v], xs[1:], [xs[0]])
|
||||
)
|
||||
) if xs else []
|
||||
|
||||
|
||||
# FORMATTING ----------------------------------------------
|
||||
|
||||
# showBoards :: Int -> [[Int]] -> String
|
||||
def showBoards(nCols):
|
||||
'''String representation, with N columns
|
||||
of a set of board patterns.
|
||||
'''
|
||||
def showBlock(b):
|
||||
return '\n'.join(map(intercalate(' '), zip(*b)))
|
||||
|
||||
def go(bs):
|
||||
return '\n\n'.join(map(
|
||||
showBlock,
|
||||
chunksOf(nCols)(
|
||||
list(map(showBoard, bs))
|
||||
)
|
||||
))
|
||||
return lambda boards: go(boards)
|
||||
|
||||
|
||||
# showBoard :: [Int] -> String
|
||||
def showBoard(xs):
|
||||
'''String representation of a Queens board.'''
|
||||
lng = len(xs)
|
||||
|
||||
def showLine(n):
|
||||
return ('.' * (n - 1)) + '♛' + ('.' * (lng - n))
|
||||
return list(map(showLine, xs))
|
||||
|
||||
|
||||
# fTable :: String -> (a -> String) ->
|
||||
# (b -> String) -> (a -> b) -> [a] -> String
|
||||
def fTable(s):
|
||||
'''Heading -> x display function -> fx display function ->
|
||||
f -> xs -> tabular string.
|
||||
'''
|
||||
def go(xShow, fxShow, f, xs):
|
||||
ys = [xShow(x) for x in xs]
|
||||
w = max(map(len, ys))
|
||||
return s + '\n' + '\n'.join(map(
|
||||
lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
|
||||
xs, ys
|
||||
))
|
||||
return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
|
||||
xShow, fxShow, f, xs
|
||||
)
|
||||
|
||||
|
||||
# MAIN ---
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,48 +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 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.*/
|
||||
if N=='' | N=="," then N= 8 /*Not specified: Then use the default.*/
|
||||
if N<1 then call 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.*/
|
||||
/* [↓] 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; file=1 /*Queen not being attacked? Then eureka*/
|
||||
rank=rank+1 /*use another attempt at another rank. */
|
||||
do while #<N; @.file.rank= 1 /*keep placing queens until we're done.*/
|
||||
if ok(file, rank) then do; file= 1; #= # + 1 /*Queen not being attacked? Then eureka*/
|
||||
rank= rank + 1 /*use another attempt at another rank. */
|
||||
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) 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:"; 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 black─square queen.*/
|
||||
Wqueen = ' 'queen" " /* " " " white─square " */
|
||||
|
||||
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. */
|
||||
else if B then _=_ || bar || copies(dither,3) /*use dithering for sq.*/
|
||||
else _=_ || bar || copies(' ' ,3) /* " 3 blanks " " */
|
||||
end /*file*/ /* [↑] preserve square─ish chessboard.*/
|
||||
say pad _ || bar /*show a single rank of the chessboard.*/
|
||||
end /*rank*/ /*80 cols can view a 19x19 chessboard.*/
|
||||
|
||||
say pad translate('╚'g"╝", '╩', "╬") /*display the last rank (of the board).*/
|
||||
@.file.rank= 0 /*It isn't safe. So remove this queen.*/
|
||||
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*/
|
||||
call show
|
||||
exit 1 /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
nOK: say; say "No solution for" N 'queens.'; say; exit 0
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
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
|
||||
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? */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
show: say 'A solution for ' N " queens:" /*display a title to the terminal.*/
|
||||
g= substr( copies("╬═══", N) ,2) /*start of all cells on chessboard*/
|
||||
say; say pad translate('╔'g"╗", '╦', "╬") /*display top rank (of the board).*/
|
||||
line = '╠'g"╣"; dither= "▓"; ditherQ= '░' /*define a line for cell boundary.*/
|
||||
bar = '║' ; queen = "Q" /*kinds: horiz., vert., salad.*/
|
||||
Bqueen = ditherQ || queen || ditherQ /*glyph befitting a black square Q*/
|
||||
Wqueen = ' 'queen" " /* " " " white " "*/
|
||||
do rank=1 for N; if rank\==1 then say pad line; _= /*show rank sep. */
|
||||
do file=1 for N; B = (file + rank) // 2 /*square black ? */
|
||||
Qgylph= Wqueen; if B then Qgylph= Bqueen /*use dithered Q.*/
|
||||
if @.file.rank then _= _ || bar || Qgylph /*3─char Q symbol*/
|
||||
else if B then _=_ || bar || copies(dither,3) /*dithering */
|
||||
else _=_ || bar || copies( ' ' ,3) /* 3 blanks */
|
||||
end /*file*/ /* [↑] preserve square─ish board.*/
|
||||
say pad _ || bar /*show a single rank of the board.*/
|
||||
end /*rank*/ /*80 cols can view a 19x19 board.*/
|
||||
say pad translate('╚'g"╝", '╩', "╬"); return /*display the last rank (of board)*/
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
# list, place the second-column queen in the row with the second number in
|
||||
# the list, etc.
|
||||
|
||||
|
||||
def n_queens(n)
|
||||
if n == 1
|
||||
return "Q"
|
||||
|
|
@ -25,35 +26,32 @@ def n_queens(n)
|
|||
rem = n % 12 # (1)
|
||||
nums = evens # (2)
|
||||
|
||||
nums.push(nums.shift) if rem == 3 or rem == 9 # (3)
|
||||
nums.rotate if rem == 3 or rem == 9 # (3)
|
||||
|
||||
# (4)
|
||||
if rem == 8
|
||||
odds = odds.each_slice(2).inject([]) {|ary, (a,b)| ary += [b,a]}
|
||||
odds = odds.each_slice(2).flat_map(&:reverse)
|
||||
end
|
||||
nums.concat(odds)
|
||||
|
||||
# (5)
|
||||
if rem == 2
|
||||
idx = []
|
||||
[1,3,5].each {|i| idx[i] = nums.index(i)}
|
||||
nums[idx[1]], nums[idx[3]] = nums[idx[3]], nums[idx[1]]
|
||||
nums.slice!(idx[5])
|
||||
nums.push(5)
|
||||
nums[nums.index(1)], nums[nums.index(3)] = nums[nums.index(3)], nums[nums.index(1)]
|
||||
nums << nums.delete(5)
|
||||
end
|
||||
|
||||
# (6)
|
||||
if rem == 3 or rem == 9
|
||||
[1,3].each do |i|
|
||||
nums.slice!( nums.index(i) )
|
||||
nums.push(i)
|
||||
end
|
||||
nums << nums.delete(1)
|
||||
nums << nums.delete(3)
|
||||
end
|
||||
|
||||
# (7)
|
||||
board = Array.new(n) {Array.new(n) {"."}}
|
||||
n.times {|i| board[i][nums[i] - 1] = "Q"}
|
||||
board.inject("") {|str, row| str << row.join(" ") << "\n"}
|
||||
nums.map do |q|
|
||||
a = Array.new(n,".")
|
||||
a[q-1] = "Q"
|
||||
a*(" ")
|
||||
end
|
||||
end
|
||||
|
||||
(1 .. 15).each {|n| puts "n=#{n}"; puts n_queens(n); puts}
|
||||
|
|
|
|||
49
Task/N-queens-problem/Scala/n-queens-problem.scala
Normal file
49
Task/N-queens-problem/Scala/n-queens-problem.scala
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
object NQueens {
|
||||
|
||||
private implicit class RichPair[T](
|
||||
pair: (T,T))(
|
||||
implicit num: Numeric[T]
|
||||
) {
|
||||
import num._
|
||||
|
||||
def safe(x: T, y: T): Boolean =
|
||||
pair._1 - pair._2 != abs(x - y)
|
||||
}
|
||||
|
||||
def solve(n: Int): Iterator[Seq[Int]] = {
|
||||
(0 to n-1)
|
||||
.permutations
|
||||
.filter { v =>
|
||||
(0 to n-1).forall { y =>
|
||||
(y+1 to n-1).forall { x =>
|
||||
(x,y).safe(v(x),v(y))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val n = args.headOption.getOrElse("8").toInt
|
||||
val (solns1, solns2) = solve(n).duplicate
|
||||
solns1
|
||||
.zipWithIndex
|
||||
.foreach { case (soln, i) =>
|
||||
Console.out.println(s"Solution #${i+1}")
|
||||
output(n)(soln)
|
||||
}
|
||||
val n_solns = solns2.size
|
||||
if (n_solns == 1) {
|
||||
Console.out.println("Found 1 solution")
|
||||
} else {
|
||||
Console.out.println(s"Found $n_solns solutions")
|
||||
}
|
||||
}
|
||||
|
||||
def output(n: Int)(board: Seq[Int]): Unit = {
|
||||
board.foreach { queen =>
|
||||
val row =
|
||||
"_|" * queen + "Q" + "|_" * (n-queen-1)
|
||||
Console.out.println(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Task/N-queens-problem/Swift/n-queens-problem.swift
Normal file
56
Task/N-queens-problem/Swift/n-queens-problem.swift
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
let maxn = 31
|
||||
|
||||
func nq(n: Int) -> Int {
|
||||
var cols = Array(repeating: 0, count: maxn)
|
||||
var diagl = Array(repeating: 0, count: maxn)
|
||||
var diagr = Array(repeating: 0, count: maxn)
|
||||
var posibs = Array(repeating: 0, count: maxn)
|
||||
var num = 0
|
||||
for q0 in 0...n-3 {
|
||||
for q1 in q0+2...n-1 {
|
||||
let bit0: Int = 1<<q0
|
||||
let bit1: Int = 1<<q1
|
||||
var d: Int = 0
|
||||
cols[0] = bit0 | bit1 | (-1<<n)
|
||||
diagl[0] = (bit0<<1|bit1)<<1
|
||||
diagr[0] = (bit0>>1|bit1)>>1
|
||||
|
||||
var posib: Int = ~(cols[0] | diagl[0] | diagr[0])
|
||||
|
||||
while (d >= 0) {
|
||||
while(posib != 0) {
|
||||
let bit: Int = posib & -posib
|
||||
let ncols: Int = cols[d] | bit
|
||||
let ndiagl: Int = (diagl[d] | bit) << 1;
|
||||
let ndiagr: Int = (diagr[d] | bit) >> 1;
|
||||
let nposib: Int = ~(ncols | ndiagl | ndiagr);
|
||||
posib^=bit
|
||||
num += (ncols == -1 ? 1 : 0)
|
||||
if (nposib != 0){
|
||||
if(posib != 0) {
|
||||
posibs[d] = posib
|
||||
d += 1
|
||||
}
|
||||
cols[d] = ncols
|
||||
diagl[d] = ndiagl
|
||||
diagr[d] = ndiagr
|
||||
posib = nposib
|
||||
}
|
||||
}
|
||||
d -= 1
|
||||
posib = d<0 ? n : posibs[d]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return num*2
|
||||
}
|
||||
if(CommandLine.arguments.count == 2) {
|
||||
|
||||
let board_size: Int = Int(CommandLine.arguments[1])!
|
||||
print ("Number of solutions for board size \(board_size) is: \(nq(n:board_size))")
|
||||
|
||||
} else {
|
||||
print("Usage: 8q <n>")
|
||||
}
|
||||
78
Task/N-queens-problem/UNIX-Shell/n-queens-problem.sh
Normal file
78
Task/N-queens-problem/UNIX-Shell/n-queens-problem.sh
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#!/bin/bash
|
||||
|
||||
# variable declaration
|
||||
typeset -i BoardSize=8
|
||||
typeset -i p=0
|
||||
typeset -i total=0
|
||||
typeset -i board
|
||||
|
||||
# initialization
|
||||
function init
|
||||
{
|
||||
for (( i=0;i<$BoardSize;i++ ))
|
||||
do
|
||||
(( board[$i]=-1 ))
|
||||
done
|
||||
}
|
||||
|
||||
# check if queen can be placed
|
||||
function place
|
||||
{
|
||||
typeset -i flag=1
|
||||
for (( i=0;i<$1;i++ ))
|
||||
do
|
||||
if [[ (${board[$i]}-${board[$1]} -eq ${i}-${1}) || (${board[$i]}-${board[$1]} -eq ${1}-${i}) || (${board[$i]} -eq ${board[$1]}) ]]
|
||||
then
|
||||
(( flag=0 ))
|
||||
fi
|
||||
done
|
||||
[[ $flag -eq 0 ]]
|
||||
return $?
|
||||
}
|
||||
|
||||
# print the result
|
||||
function out
|
||||
{
|
||||
printf "Problem of queen %d:%d\n" $BoardSize $total
|
||||
}
|
||||
|
||||
# free the variables
|
||||
function depose
|
||||
{
|
||||
unset p
|
||||
unset total
|
||||
unset board
|
||||
unset BoardSize
|
||||
}
|
||||
|
||||
# back tracing
|
||||
function work
|
||||
{
|
||||
while [[ $p -gt -1 ]]
|
||||
do
|
||||
(( board[$p]++ ))
|
||||
if [[ ${board[$p]} -ge ${BoardSize} ]]
|
||||
then # back tracing
|
||||
(( p-- ))
|
||||
else # try next position
|
||||
place $p
|
||||
if [[ $? -eq 1 ]]
|
||||
then
|
||||
(( p++ ))
|
||||
if [[ $p -ge ${BoardSize} ]]
|
||||
then
|
||||
(( total++ ))
|
||||
(( p-- ))
|
||||
else
|
||||
(( board[$p]=-1 ))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# entry
|
||||
init
|
||||
work
|
||||
out
|
||||
depose
|
||||
Loading…
Add table
Add a link
Reference in a new issue