Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1,4 +1,7 @@
Solve the [[WP:Eight_queens_puzzle|eight queens puzzle]]. You can extend the problem to solve the puzzle with a board of side NxN. Number of solutions for small values of N is [http://oeis.org/A000170 here].
Solve the [[WP:Eight_queens_puzzle|eight queens puzzle]].
You can extend the problem to solve the puzzle with a board of side NxN.
For the number of solutions for small values of N, see [http://oeis.org/A000170 oeis.org].
;Cf.
* [[Knight's tour]]

View file

@ -0,0 +1,285 @@
TYPES: BEGIN OF gty_matrix,
1 TYPE c,
2 TYPE c,
3 TYPE c,
4 TYPE c,
5 TYPE c,
6 TYPE c,
7 TYPE c,
8 TYPE c,
9 TYPE c,
10 TYPE c,
END OF gty_matrix,
gty_t_matrix TYPE STANDARD TABLE OF gty_matrix INITIAL SIZE 8.
DATA: gt_matrix TYPE gty_t_matrix,
gs_matrix TYPE gty_matrix,
gv_count TYPE i VALUE 0,
gv_solut TYPE i VALUE 0.
SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE text-b01.
PARAMETERS: p_number TYPE i OBLIGATORY DEFAULT 8.
SELECTION-SCREEN END OF BLOCK b01.
" Filling empty table
START-OF-SELECTION.
DO p_number TIMES.
APPEND gs_matrix TO gt_matrix.
ENDDO.
" Recursive Function
PERFORM fill_matrix USING gv_count 1 1 CHANGING gt_matrix.
BREAK-POINT.
*&---------------------------------------------------------------------*
*& Form FILL_MATRIX
*----------------------------------------------------------------------*
FORM fill_matrix USING p_count TYPE i
p_i TYPE i
p_j TYPE i
CHANGING p_matrix TYPE gty_t_matrix.
DATA: lv_i TYPE i,
lv_j TYPE i,
lv_result TYPE c LENGTH 1,
lt_matrix TYPE gty_t_matrix,
lv_count TYPE i,
lv_value TYPE c.
lt_matrix[] = p_matrix[].
lv_count = p_count.
lv_i = p_i.
lv_j = p_j.
WHILE lv_i LE p_number.
WHILE lv_j LE p_number.
CLEAR lv_result.
PERFORM check_position USING lv_i lv_j CHANGING lv_result lt_matrix.
IF lv_result NE 'X'.
MOVE 'X' TO lv_value.
PERFORM get_position USING lv_i lv_j 'U' CHANGING lv_value lt_matrix.
ADD 1 TO lv_count.
IF lv_count EQ p_number.
PERFORM show_matrix USING lt_matrix.
ELSE.
PERFORM fill_matrix USING lv_count lv_i lv_j CHANGING lt_matrix.
ENDIF.
lv_value = space.
PERFORM get_position USING lv_i lv_j 'U' CHANGING lv_value lt_matrix.
SUBTRACT 1 FROM lv_count.
ENDIF.
ADD 1 TO lv_j.
ENDWHILE.
ADD 1 TO lv_i.
lv_j = 1.
ENDWHILE.
ENDFORM. " FILL_MATRIX
*&---------------------------------------------------------------------*
*& Form CHECK_POSITION
*&---------------------------------------------------------------------*
FORM check_position USING value(p_i) TYPE i
value(p_j) TYPE i
CHANGING p_result TYPE c
p_matrix TYPE gty_t_matrix.
PERFORM get_position USING p_i p_j 'R' CHANGING p_result p_matrix.
CHECK p_result NE 'X'.
PERFORM check_horizontal USING p_i p_j CHANGING p_result p_matrix.
CHECK p_result NE 'X'.
PERFORM check_vertical USING p_i p_j CHANGING p_result p_matrix.
CHECK p_result NE 'X'.
PERFORM check_diagonals USING p_i p_j CHANGING p_result p_matrix.
ENDFORM. " CHECK_POSITION
*&---------------------------------------------------------------------*
*& Form GET_POSITION
*&---------------------------------------------------------------------*
FORM get_position USING value(p_i) TYPE i
value(p_j) TYPE i
value(p_action) TYPE c
CHANGING p_result TYPE c
p_matrix TYPE gty_t_matrix.
FIELD-SYMBOLS: <fs_lmatrix> TYPE gty_matrix,
<fs_lfield> TYPE any.
READ TABLE p_matrix ASSIGNING <fs_lmatrix> INDEX p_i.
ASSIGN COMPONENT p_j OF STRUCTURE <fs_lmatrix> TO <fs_lfield>.
CASE p_action.
WHEN 'U'.
<fs_lfield> = p_result.
WHEN 'R'.
p_result = <fs_lfield>.
WHEN OTHERS.
ENDCASE.
ENDFORM. " GET_POSITION
*&---------------------------------------------------------------------*
*& Form CHECK_HORIZONTAL
*&---------------------------------------------------------------------*
FORM check_horizontal USING value(p_i) TYPE i
value(p_j) TYPE i
CHANGING p_result TYPE c
p_matrix TYPE gty_t_matrix.
DATA: lv_j TYPE i,
ls_matrix TYPE gty_matrix.
FIELD-SYMBOLS <fs> TYPE c.
lv_j = 1.
READ TABLE p_matrix INTO ls_matrix INDEX p_i.
WHILE lv_j LE p_number.
ASSIGN COMPONENT lv_j OF STRUCTURE ls_matrix TO <fs>.
IF <fs> EQ 'X'.
p_result = 'X'.
RETURN.
ENDIF.
ADD 1 TO lv_j.
ENDWHILE.
ENDFORM. " CHECK_HORIZONTAL
*&---------------------------------------------------------------------*
*& Form CHECK_VERTICAL
*&---------------------------------------------------------------------*
FORM check_vertical USING value(p_i) TYPE i
value(p_j) TYPE i
CHANGING p_result TYPE c
p_matrix TYPE gty_t_matrix.
DATA: lv_i TYPE i,
ls_matrix TYPE gty_matrix.
FIELD-SYMBOLS <fs> TYPE c.
lv_i = 1.
WHILE lv_i LE p_number.
READ TABLE p_matrix INTO ls_matrix INDEX lv_i.
ASSIGN COMPONENT p_j OF STRUCTURE ls_matrix TO <fs>.
IF <fs> EQ 'X'.
p_result = 'X'.
RETURN.
ENDIF.
ADD 1 TO lv_i.
ENDWHILE.
ENDFORM. " CHECK_VERTICAL
*&---------------------------------------------------------------------*
*& Form CHECK_DIAGONALS
*&---------------------------------------------------------------------*
FORM check_diagonals USING value(p_i) TYPE i
value(p_j) TYPE i
CHANGING p_result TYPE c
p_matrix TYPE gty_t_matrix.
DATA: lv_dx TYPE i,
lv_dy TYPE i.
* I++ J++ (Up Right)
lv_dx = 1.
lv_dy = 1.
PERFORM check_diagonal USING p_i p_j lv_dx lv_dy CHANGING p_result p_matrix.
CHECK p_result NE 'X'.
* I-- J-- (Left Down)
lv_dx = -1.
lv_dy = -1.
PERFORM check_diagonal USING p_i p_j lv_dx lv_dy CHANGING p_result p_matrix.
CHECK p_result NE 'X'.
* I++ J-- (Right Down)
lv_dx = 1.
lv_dy = -1.
PERFORM check_diagonal USING p_i p_j lv_dx lv_dy CHANGING p_result p_matrix.
CHECK p_result NE 'X'.
* I-- J++ (Left Up)
lv_dx = -1.
lv_dy = 1.
PERFORM check_diagonal USING p_i p_j lv_dx lv_dy CHANGING p_result p_matrix.
CHECK p_result NE 'X'.
ENDFORM. " CHECK_DIAGONALS
*&---------------------------------------------------------------------*
*& Form CHECK_DIAGONAL
*&---------------------------------------------------------------------*
FORM check_diagonal USING value(p_i) TYPE i
value(p_j) TYPE i
value(p_dx) TYPE i
value(p_dy) TYPE i
CHANGING p_result TYPE c
p_matrix TYPE gty_t_matrix.
DATA: lv_i TYPE i,
lv_j TYPE i,
ls_matrix TYPE gty_matrix.
FIELD-SYMBOLS <fs> TYPE c.
lv_i = p_i.
lv_j = p_j.
WHILE 1 EQ 1.
ADD: p_dx TO lv_i, p_dy TO lv_j.
IF p_dx EQ 1.
IF lv_i GT p_number. EXIT. ENDIF.
ELSE.
IF lv_i LT 1. EXIT. ENDIF.
ENDIF.
IF p_dy EQ 1.
IF lv_j GT p_number. EXIT. ENDIF.
ELSE.
IF lv_j LT 1. EXIT. ENDIF.
ENDIF.
READ TABLE p_matrix INTO ls_matrix INDEX lv_i.
ASSIGN COMPONENT lv_j OF STRUCTURE ls_matrix TO <fs>.
IF <fs> EQ 'X'.
p_result = 'X'.
RETURN.
ENDIF.
ENDWHILE.
ENDFORM. " CHECK_DIAGONAL
*&---------------------------------------------------------------------*
*& Form SHOW_MATRIX
*----------------------------------------------------------------------*
FORM show_matrix USING p_matrix TYPE gty_t_matrix.
DATA: lt_matrix TYPE gty_t_matrix,
lv_j TYPE i VALUE 1,
lv_colum TYPE string VALUE '-'.
FIELD-SYMBOLS: <fs_matrix> TYPE gty_matrix,
<fs_field> TYPE c.
ADD 1 TO gv_solut.
WRITE:/ 'Solution: ', gv_solut.
DO p_number TIMES.
CONCATENATE lv_colum '----' INTO lv_colum.
ENDDO.
LOOP AT p_matrix ASSIGNING <fs_matrix>.
IF sy-tabix EQ 1.
WRITE:/ lv_colum.
ENDIF.
WRITE:/ '|'.
DO p_number TIMES.
ASSIGN COMPONENT lv_j OF STRUCTURE <fs_matrix> TO <fs_field>.
IF <fs_field> EQ space.
WRITE: <fs_field> ,'|'.
ELSE.
WRITE: <fs_field> COLOR 2 HOTSPOT ON,'|'.
ENDIF.
ADD 1 TO lv_j.
ENDDO.
lv_j = 1.
WRITE: / lv_colum.
ENDLOOP.
SKIP 1.
ENDFORM. " SHOW_MATRIX

View file

@ -0,0 +1,61 @@
( ( printBoard
= board M L x y S R row line
. :?board
& !ups:? [?M
& whl
' ( !arg:(?x.?y) ?arg
& !M:?L
& :?row:?line
& whl
' ( !L+-1:~<0:?L
& !x+1:~>!M:?x
& "---+" !line:?line
& " |" !row:?row
)
& "---+" !line:?line
& " Q |" !row:?row
& whl
' ( !L+-1:~<0:?L
& "---+" !line:?line
& " |" !row:?row
)
& "\n|" !row "\n+" !line !board:?board
)
& str$("\n+" !line !board)
)
( queens
= hor ver up down ups downs a z A Z x y Q
. !arg:(?hor.?ver.?ups.?downs.?Q)
& !ver
: (
& 1+!solutions:?solutions
{ Comment the line below if you only want a count. }
& out$(str$("\nsolution " !solutions) printBoard$!Q)
& ~ { Fail! (and backtrack to find more solutions)}
| #%?y
( ?z
& !hor
: ?A
#%?x
( ?Z
& !x+!y:?up
& !x+-1*!y:?down
& ~(!ups:? !up ?)
& ~(!downs:? !down ?)
& queens
$ ( !A !Z
. !z
. !up !ups
. !down !downs
. (!x.!y) !Q
)
)
)
)
)
& 0:?solutions
& 1 2 3 4 5 6 7 8:?H:?V {You can edit this line to find solutions for other sizes.}
& ( queens$(!H.!V...)
| out$(found !solutions solutions)
)
);

View file

@ -1,100 +1,103 @@
#include <windows.h>
// Much shorter than the version below;
// uses C++11 threads to parallelize the computation; also uses backtracking
// Outputs all solutions for any table size
#include <vector>
#include <iostream>
#include <string>
#include <iomanip>
#include <thread>
#include <future>
//--------------------------------------------------------------------------------------------------
using namespace std;
//--------------------------------------------------------------------------------------------------
class point
// Print table. 'pos' is a vector of positions the index in pos is the row,
// and the number at that index is the column where the queen is placed.
static void print(const std::vector<int> &pos)
{
public:
int x, y;
point(){ x = y = 0; }
void set( int a, int b ){ x = a; y = b; }
};
//--------------------------------------------------------------------------------------------------
class nQueens
{
public:
void solve( int c )
{
_count = c; int len = ( c + 1 ) * ( c + 1 ); _queens = new bool[len]; memset( _queens, 0, len );
_cl = new bool[c]; memset( _cl, 0, c ); _ln = new bool[c]; memset( _ln, 0, c );
point pt; pt.set( rand() % c, rand() % c ); putQueens( pt, c ); displayBoard();
delete [] _queens; delete [] _ln; delete [] _cl;
}
private:
void displayBoard()
{
system( "cls" ); string t = "+---+", q = "| Q |", s = "| |";
COORD c = { 0, 0 }; HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE );
for( int y = 0, cy = 0; y < _count; y++ )
{
int yy = y * _count;
for( int x = 0; x < _count; x++ )
{
SetConsoleCursorPosition( h, c ); cout << t;
c.Y++; SetConsoleCursorPosition( h, c );
if( _queens[x + yy] ) cout << q; else cout << s;
c.Y++; SetConsoleCursorPosition( h, c );
cout << t; c.Y = cy; c.X += 4;
}
cy += 2; c.X = 0; c.Y = cy;
}
}
bool checkD( int x, int y, int a, int b )
{
if( x < 0 || y < 0 || x >= _count || y >= _count ) return true;
if( _queens[x + y * _count] ) return false;
if( checkD( x + a, y + b, a, b ) ) return true;
return false;
}
bool check( int x, int y )
{
if( _ln[y] || _cl[x] ) return false;
if( !checkD( x, y, -1, -1 ) ) return false;
if( !checkD( x, y, 1, -1 ) ) return false;
if( !checkD( x, y, -1, 1 ) ) return false;
if( !checkD( x, y, 1, 1 ) ) return false;
return true;
}
bool putQueens( point pt, int cnt )
{
int it = _count;
while( it )
{
if( !cnt ) return true;
if( check( pt.x, pt.y ) )
{
_queens[pt.x + pt.y * _count] = _cl[pt.x] = _ln[pt.y] = true;
point tmp = pt; if( ++tmp.x >= _count ) tmp.x = 0; if( ++tmp.y >= _count ) tmp.y = 0;
if( putQueens( tmp, cnt - 1 ) ) return true;
_queens[pt.x + pt.y * _count] = _cl[pt.x] = _ln[pt.y] = false;
}
if( ++pt.x >= _count ) pt.x = 0;
it--;
// print table header
for (int i = 0; i < pos.size(); i++) {
std::cout << std::setw(3) << char('a' + i);
}
return false;
}
int _count;
bool* _queens, *_ln, *_cl;
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
nQueens n; int nq;
while( true )
{
system( "cls" ); cout << "Enter board size bigger than 3 (0 - 3 to QUIT): "; cin >> nq;
if( nq < 4 ) return 0; n.solve( nq ); cout << endl << endl;
system( "pause" );
}
return 0;
std::cout << '\n';
for (int row = 0; row < pos.size(); row++) {
int col = pos[row];
std::cout << row + 1 << std::setw(3 * col + 3) << " # ";
std::cout << '\n';
}
std::cout << "\n\n";
}
static bool threatens(int row_a, int col_a, int row_b, int col_b)
{
return row_a == row_b // same row
or col_a == col_b // same column
or std::abs(row_a - row_b) == std::abs(col_a - col_b); // diagonal
}
// the i-th queen is in the i-th row
// we only check rows up to end_idx
// so that the same function can be used for backtracking and checking the final solution
static bool good(const std::vector<int> &pos, int end_idx)
{
for (int row_a = 0; row_a < end_idx; row_a++) {
for (int row_b = row_a + 1; row_b < end_idx; row_b++) {
int col_a = pos[row_a];
int col_b = pos[row_b];
if (threatens(row_a, col_a, row_b, col_b)) {
return false;
}
}
}
return true;
}
static std::mutex print_count_mutex; // mutex protecting 'n_sols'
static int n_sols = 0; // number of solutions
// recursive DFS backtracking solver
static void n_queens(std::vector<int> &pos, int index)
{
// if we have placed a queen in each row (i. e. we are at a leaf of the search tree), check solution and return
if (index >= pos.size()) {
if (good(pos, index)) {
std::lock_guard<std::mutex> lock(print_count_mutex);
print(pos);
n_sols++;
}
return;
}
// backtracking step
if (not good(pos, index)) {
return;
}
// optimization: the first level of the search tree is parallelized
if (index == 0) {
std::vector<std::future<void>> fts;
for (int col = 0; col < pos.size(); col++) {
pos[index] = col;
auto ft = std::async(std::launch::async, [=]{ auto cpos(pos); n_queens(cpos, index + 1); });
fts.push_back(std::move(ft));
}
for (const auto &ft : fts) {
ft.wait();
}
} else { // deeper levels are not
for (int col = 0; col < pos.size(); col++) {
pos[index] = col;
n_queens(pos, index + 1);
}
}
}
int main()
{
std::vector<int> start(12); // 12: table size
n_queens(start, 0);
std::cout << n_sols << " solutions found.\n";
return 0;
}
//--------------------------------------------------------------------------------------------------

View file

@ -1,88 +1,257 @@
#include <windows.h>
// A straight-forward brute-force C++ version with formatted output,
// eschewing obfuscation and C-isms, producing ALL solutions, which
// works on any OS with a text terminal.
//
// Two basic optimizations are applied:
//
// It uses backtracking to only construct potentially valid solutions.
//
// It only computes half the solutions by brute -- once we get the
// queen halfway across the top row, any remaining solutions must be
// reflections of the ones already computed.
//
// This is a bare-bones example, without any progress feedback or output
// formatting controls, which a more complete program might provide.
//
// Beware that computing anything larger than N=14 might take a while.
// (Time gets exponentially worse the higher the number.)
// Copyright 2014 Michael Thomas Greer
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
#include <algorithm>
#include <ciso646>
#include <iomanip>
#include <iostream>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <algorithm>
//--------------------------------------------------------------------------------------------------
using namespace std;
//--------------------------------------------------------------------------------------------------
typedef unsigned int uint;
//--------------------------------------------------------------------------------------------------
class nQueens_Heuristic
// ///////////////////////////////////////////////////////////////////////////
struct queens
/////////////////////////////////////////////////////////////////////////// //
{
public:
void solve( uint n ) { makeList( n ); drawBoard( n ); }
// TYPES -------------------------------------------------------------------
private:
void drawBoard( uint n )
// A row or column index. (May be signed or unsigned.)
//
typedef signed char index_type;
// A 'solution' is a row --> column lookup of queens on the board.
//
// It has lexicographical order and can be transformed with a variety of
// reflections, which, when properly combined, produce all possible
// orientations of a solution.
//
struct solution_type: std::vector <index_type>
{
typedef std::vector <index_type> base_type;
// constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
solution_type( std::size_t N ): base_type( N, -1 ) { }
solution_type( const solution_type& s ): base_type( s ) { }
// compare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
bool operator < ( const solution_type& s ) const
{
system( "cls" ); string t = "+---+", q = "| Q |", s = "| |";
COORD c = { 0, 0 }; HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE );
uint w = 0;
for( uint y = 0, cy = 0; y < n; y++ )
{
for( uint x = 0; x < n; x++ )
{
SetConsoleCursorPosition( h, c ); cout << t;
c.Y++; SetConsoleCursorPosition( h, c );
if( x + 1 == solution[w] ) cout << q; else cout << s;
c.Y++; SetConsoleCursorPosition( h, c );
cout << t; c.Y = cy; c.X += 4;
}
cy += 2; c.X = 0; c.Y = cy; w++;
}
solution.clear(); odd.clear(); evn.clear();
auto mm = std::mismatch( begin(), end(), s.begin() );
return (mm.first != end()) and (*mm.first < *mm.second);
}
void makeList( uint n )
// transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . .
void vflip() { std::reverse( begin(), end() ); }
void hflip() { for (auto& x : *this) x = size() - 1 - x; }
void transpose()
{
uint r = n % 6;
for( uint x = 1; x <= n; x++ )
{
if( x & 1 ) odd.push_back( x );
else evn.push_back( x );
}
if( r == 2 )
{
swap( odd[0], odd[1] );
odd.erase( find( odd.begin(), odd.end(), 5 ) );
odd.push_back( 5 );
}
else if( r == 3 )
{
odd.erase( odd.begin() ); odd.erase( odd.begin() );
odd.push_back( 1 ); odd.push_back( 3 );
evn.erase( evn.begin() ); evn.push_back( 2 );
}
vector<uint>::iterator it = evn.begin();
while( it != evn.end() )
{
solution.push_back( ( *it ) );
it++;
}
it = odd.begin();
while( it != odd.end() )
{
solution.push_back( ( *it ) );
it++;
}
solution_type result( size() );
for (index_type y = 0; (std::size_t)y < size(); y++)
result[ (*this)[ y ] ] = y;
swap( result );
}
};
// MEMBER VALUES -----------------------------------------------------------
const int N;
std::set <solution_type> solutions;
// SOLVER ------------------------------------------------------------------
queens( int N = 8 ):
N( (N < 0) ? 0 : N )
{
// Row by row we create a potentially valid solution.
// If a queen can be placed in a valid spot by the time
// we get to the last row, then we've found a solution.
solution_type solution( N );
index_type row = 0;
while (true)
{
// Advance the queen along the row
++solution[ row ];
// (If we get past halfway through the first row, we're done.)
if ((row == 0) and (solution[ 0 ] > N/2)) break;
if (solution[ row ] < N)
{
// If the queen is in a good spot...
if (ok( solution, row, solution[ row ] ))
{
// ...and we're on the last row
if (row == N-1)
{
// Add the solution we found plus all it's reflections
solution_type
s = solution; solutions.insert( s );
s.vflip(); solutions.insert( s );
s.hflip(); solutions.insert( s );
s.vflip(); solutions.insert( s );
s.transpose(); solutions.insert( s );
s.vflip(); solutions.insert( s );
s.hflip(); solutions.insert( s );
s.vflip(); solutions.insert( s );
}
// otherwise begin marching a queen along the next row
else solution[ ++row ] = -1;
}
// When we get to the end of a row's columns then
// we need to backup a row and continue from there.
}
else --row;
}
}
// HELPER ------------------------------------------------------------------
// This routine helps the solver by identifying column locations
// that do not conflict with queens already placed in prior rows.
bool ok( const solution_type& columns, index_type row, index_type column )
{
for (index_type r = 0; r < row; r++)
{
index_type c = columns[ r ];
index_type delta_row = row - r;
index_type delta_col = (c < column) ? (column - c) : (c - column);
if ((c == column) or (delta_row == delta_col))
return false;
}
return true;
}
// OUTPUT A SINGLE SOLUTION ------------------------------------------------
//
// Formatted as (for example):
//
// d1 b2 g3 c4 f5 h6 e7 a8
// Q - - - - - - -
// - - - - Q - - -
// - - - - - - - Q
// - - - - - Q - -
// - - Q - - - - -
// - - - - - - Q -
// - Q - - - - - -
// - - - Q - - - -
//
friend
std::ostream&
operator << ( std::ostream& outs, const queens::solution_type& solution )
{
static const char* squares[] = { "- ", "Q " };
index_type N = solution.size();
// Display the queen positions
for (auto n = N; n--; )
outs << (char)('a' + solution[ n ]) << (N - n) << " ";
// Display the board
for (auto queen : solution)
{
outs << "\n";
for (index_type col = 0; col < N; col++)
outs << squares[ col == queen ];
}
return outs;
}
// OUTPUT ALL SOLUTIONS ----------------------------------------------------
//
// Display "no solutions" or "N solutions" followed by
// each individual solution, separated by blank lines.
friend
std::ostream&
operator << ( std::ostream& outs, const queens& q )
{
if (q.solutions.empty()) outs << "no";
else outs << q.solutions.size();
outs << " solutions";
std::size_t n = 1;
for (auto solution : q.solutions)
{
outs << "\n\n#" << n++ << "\n" << solution;
}
vector<uint> odd, evn, solution;
return outs;
}
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
/* ///////////////////////////////////////////////////////////////////////////
string_to <type> ( x )
/////////////////////////////////////////////////////////////////////////// */
template <typename T>
T string_to( const std::string& s )
{
uint n; nQueens_Heuristic nQH;
while( true )
{
cout << "Enter board size bigger than 3 (0 - 3 to QUIT): "; cin >> n;
if( n < 4 ) return 0;
nQH.solve( n ); cout << endl << endl;
}
return 0;
T result;
std::istringstream ss( s );
ss >> result;
if (!ss.eof()) throw std::runtime_error( "to_string(): invalid conversion" );
return result;
}
template <typename T, T default_value>
T string_to( const std::string& s )
{
try { return string_to <T> ( s ); }
catch (...) { return default_value; }
}
/* ///////////////////////////////////////////////////////////////////////////
main program
/////////////////////////////////////////////////////////////////////////// */
int usage( const std::string& name )
{
std::cerr <<
"usage:\n " << name << " 8\n\n"
""
"Solve the N-Queens problem, brute-force,\n"
"and show all solutions for an 8x8 board.\n\n"
""
"(Specify a value other than 8 for the board size you want.)\n";
return 1;
}
int main( int argc, char** argv )
{
signed N =
(argc < 2) ? 8 :
(argc > 2) ? 0 : string_to <signed, 0> ( argv[ 1 ] );
if (N <= 0) return usage( argv[ 0 ] );
std::cout << queens( N ) << "\n";
}
//--------------------------------------------------------------------------------------------------

View file

@ -0,0 +1,100 @@
#include <windows.h>
#include <iostream>
#include <string>
//--------------------------------------------------------------------------------------------------
using namespace std;
//--------------------------------------------------------------------------------------------------
class point
{
public:
int x, y;
point(){ x = y = 0; }
void set( int a, int b ){ x = a; y = b; }
};
//--------------------------------------------------------------------------------------------------
class nQueens
{
public:
void solve( int c )
{
_count = c; int len = ( c + 1 ) * ( c + 1 ); _queens = new bool[len]; memset( _queens, 0, len );
_cl = new bool[c]; memset( _cl, 0, c ); _ln = new bool[c]; memset( _ln, 0, c );
point pt; pt.set( rand() % c, rand() % c ); putQueens( pt, c ); displayBoard();
delete [] _queens; delete [] _ln; delete [] _cl;
}
private:
void displayBoard()
{
system( "cls" ); string t = "+---+", q = "| Q |", s = "| |";
COORD c = { 0, 0 }; HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE );
for( int y = 0, cy = 0; y < _count; y++ )
{
int yy = y * _count;
for( int x = 0; x < _count; x++ )
{
SetConsoleCursorPosition( h, c ); cout << t;
c.Y++; SetConsoleCursorPosition( h, c );
if( _queens[x + yy] ) cout << q; else cout << s;
c.Y++; SetConsoleCursorPosition( h, c );
cout << t; c.Y = cy; c.X += 4;
}
cy += 2; c.X = 0; c.Y = cy;
}
}
bool checkD( int x, int y, int a, int b )
{
if( x < 0 || y < 0 || x >= _count || y >= _count ) return true;
if( _queens[x + y * _count] ) return false;
if( checkD( x + a, y + b, a, b ) ) return true;
return false;
}
bool check( int x, int y )
{
if( _ln[y] || _cl[x] ) return false;
if( !checkD( x, y, -1, -1 ) ) return false;
if( !checkD( x, y, 1, -1 ) ) return false;
if( !checkD( x, y, -1, 1 ) ) return false;
if( !checkD( x, y, 1, 1 ) ) return false;
return true;
}
bool putQueens( point pt, int cnt )
{
int it = _count;
while( it )
{
if( !cnt ) return true;
if( check( pt.x, pt.y ) )
{
_queens[pt.x + pt.y * _count] = _cl[pt.x] = _ln[pt.y] = true;
point tmp = pt; if( ++tmp.x >= _count ) tmp.x = 0; if( ++tmp.y >= _count ) tmp.y = 0;
if( putQueens( tmp, cnt - 1 ) ) return true;
_queens[pt.x + pt.y * _count] = _cl[pt.x] = _ln[pt.y] = false;
}
if( ++pt.x >= _count ) pt.x = 0;
it--;
}
return false;
}
int _count;
bool* _queens, *_ln, *_cl;
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
nQueens n; int nq;
while( true )
{
system( "cls" ); cout << "Enter board size bigger than 3 (0 - 3 to QUIT): "; cin >> nq;
if( nq < 4 ) return 0; n.solve( nq ); cout << endl << endl;
system( "pause" );
}
return 0;
}
//--------------------------------------------------------------------------------------------------

View file

@ -0,0 +1,88 @@
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
//--------------------------------------------------------------------------------------------------
using namespace std;
//--------------------------------------------------------------------------------------------------
typedef unsigned int uint;
//--------------------------------------------------------------------------------------------------
class nQueens_Heuristic
{
public:
void solve( uint n ) { makeList( n ); drawBoard( n ); }
private:
void drawBoard( uint n )
{
system( "cls" ); string t = "+---+", q = "| Q |", s = "| |";
COORD c = { 0, 0 }; HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE );
uint w = 0;
for( uint y = 0, cy = 0; y < n; y++ )
{
for( uint x = 0; x < n; x++ )
{
SetConsoleCursorPosition( h, c ); cout << t;
c.Y++; SetConsoleCursorPosition( h, c );
if( x + 1 == solution[w] ) cout << q; else cout << s;
c.Y++; SetConsoleCursorPosition( h, c );
cout << t; c.Y = cy; c.X += 4;
}
cy += 2; c.X = 0; c.Y = cy; w++;
}
solution.clear(); odd.clear(); evn.clear();
}
void makeList( uint n )
{
uint r = n % 6;
for( uint x = 1; x <= n; x++ )
{
if( x & 1 ) odd.push_back( x );
else evn.push_back( x );
}
if( r == 2 )
{
swap( odd[0], odd[1] );
odd.erase( find( odd.begin(), odd.end(), 5 ) );
odd.push_back( 5 );
}
else if( r == 3 )
{
odd.erase( odd.begin() ); odd.erase( odd.begin() );
odd.push_back( 1 ); odd.push_back( 3 );
evn.erase( evn.begin() ); evn.push_back( 2 );
}
vector<uint>::iterator it = evn.begin();
while( it != evn.end() )
{
solution.push_back( ( *it ) );
it++;
}
it = odd.begin();
while( it != odd.end() )
{
solution.push_back( ( *it ) );
it++;
}
}
vector<uint> odd, evn, solution;
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
uint n; nQueens_Heuristic nQH;
while( true )
{
cout << "Enter board size bigger than 3 (0 - 3 to QUIT): "; cin >> n;
if( n < 4 ) return 0;
nQH.solve( n ); cout << endl << endl;
}
return 0;
}
//--------------------------------------------------------------------------------------------------

View file

@ -1,22 +1,19 @@
(defun n-queens (n m)
(if (= n 1)
(loop for x from 1 to m collect (list x))
(loop for sol in (n-queens (1- n) m) nconc
(loop for col from 1 to m when
(loop for row from 0 to (length sol) for c in sol
always (and (/= col c)
(/= (abs (- c col)) (1+ row)))
finally (return (cons col sol)))
collect it))))
(defun queens (n &optional (m n))
(if (zerop n)
(list nil)
(loop for solution in (queens (1- n) m)
nconc (loop for new-col from 1 to m
when (loop for row from 1 to n
for col in solution
always (/= new-col col (+ col row) (- col row)))
collect (cons new-col solution)))))
(defun show-solution (b n)
(loop for i in b do
(format t "~{~A~^~}~%"
(loop for x from 1 to n collect (if (= x i) "Q " ". "))))
(defun print-solution (solution)
(loop for queen-col in solution
do (loop for col from 1 to (length solution)
do (write-char (if (= col queen-col) #\Q #\.)))
(terpri))
(terpri))
(let ((i 0) (n 8))
(mapc #'(lambda (s)
(format t "Solution ~a:~%" (incf i))
(show-solution s n))
(n-queens n n)))
(defun print-queens (n)
(mapc #'print-solution (queens n)))

View file

@ -0,0 +1,19 @@
import CLPFD
import Findall
queens n qs =
qs =:= [_ | _ <- [1..n]]
& domain qs 1 (length qs)
& allDifferent qs
& allSafe qs
& labeling [FirstFail] qs
allSafe [] = success
allSafe (q:qs) = safe q qs 1 & allSafe qs
safe :: Int -> [Int] -> Int -> Success
safe _ [] _ = success
safe q (q1:qs) p = q /=# q1+#p & q /=# q1-#p & safe q qs (p+#1)
-- oneSolution = unpack $ queens 8
-- allSolutions = findall $ queens 8

View file

@ -1,7 +1,7 @@
enum side = 8;
__gshared int[side] board;
bool isUnsafe(in int y) nothrow {
bool isUnsafe(in int y) nothrow @nogc {
immutable int x = board[y];
foreach (immutable i; 1 .. y + 1) {
immutable int t = board[y - i];
@ -12,7 +12,7 @@ bool isUnsafe(in int y) nothrow {
return false;
}
void showBoard() nothrow {
void showBoard() nothrow @nogc {
import core.stdc.stdio;
static int s = 1;
@ -24,7 +24,7 @@ void showBoard() nothrow {
}
}
void main() nothrow {
void main() nothrow @nogc {
int y = 0;
board[0] = -1;

View file

@ -1,4 +1,4 @@
ulong nQueens(in uint nn) pure nothrow
ulong nQueens(in uint nn) pure nothrow @nogc @safe
in {
assert(nn > 0 && nn <= 27,
"'side' value must be in 1 .. 27.");
@ -38,7 +38,7 @@ in {
// Because !d is often faster than d != n.
while (d) {
// immutable uint pos = 1U << bits.bsf; // Slower.
immutable uint pos = -(cast(int)bits) & bits;
immutable uint pos = -int(bits) & bits;
// Mark bit used. Only put current bits on
// stack if not zero, so backtracking will

View file

@ -0,0 +1,68 @@
class
QUEENS
create
make
feature {NONE}
counter: INTEGER
place_queens(board: ARRAY[INTEGER]; level: INTEGER)
local
i, j: INTEGER
safe: BOOLEAN
do
if level > board.count
then
counter := counter + 1
else
from
i := 1
until
i > board.count
loop
safe := True
from
j := 1
until
j = level or not safe
loop
if (board[j] = i)
or (j - level = i - board[j])
or (j - level = board[j] - i)
then
safe := False
end
j := j + 1
end
if safe
then
board[level] := i
place_queens(board, level + 1)
end
i := i + 1
end
end
end
feature
possible_positions_of_n_queens(n: INTEGER): INTEGER
local
board: ARRAY[INTEGER]
do
create board.make_filled (0, 1, n)
counter := 0
place_queens(board, 1)
Result := counter
end
make
local
n: INTEGER
do
io.put_string ("Please enter the number of queens: ")
io.read_integer
n := io.last_integer
print("%NPossible number of placings: " + possible_positions_of_n_queens(n).out + "%N")
end
end

View file

@ -1,122 +1,53 @@
program queens
use omp_lib
!The preceding program implements recursion using arrays, since Fortran 77 does not allow recursive
!functions. The same algorithm is much easier to follow in Fortran 90, using the RECURSIVE keyword.
!Like previously, the program only counts solutions. It's pretty straightforward to adapt it to print
!them too: one has to replace the 'm = m + 1' instruction with a PRINT statement.
function numq(n)
implicit none
integer, parameter :: long = selected_int_kind(17)
integer, parameter :: l = 18
integer :: n, i, j, a(l*l, 2), k, p, q
integer(long) :: s, b(l*l)
real(kind(1d0)) :: t1, t2
do n = 6, l
k = 0
p = n/2
q = mod(n, 2)*(p + 1)
do i = 1, n
do j = 1, n
if ((abs(i - j) > 1) .and. ((i <= p) .or. ((i == q) .and. (j < i)))) then
k = k + 1
a(k, 1) = i
a(k, 2) = j
end if
end do
end do
s = 0
t1 = omp_get_wtime()
!$omp parallel do schedule(dynamic)
do i = 1, k
b(i) = pqueens(n, a(i, 1), a(i, 2))
end do
!$omp end parallel do
t2 = omp_get_wtime()
print "(I4, I12, F12.3)", n, 2*sum(b(1:k)), t2 - t1
integer :: i, n, m, a(n), numq
logical :: up(2*n - 1), down(2*n - 1)
do i = 1, n
a(i) = i
end do
up = .true.
down = .true.
m = 0
call sub(1)
numq = m
contains
function pqueens(n, k1, k2) result(m)
implicit none
integer(long) :: m
integer, intent(in) :: n, k1, k2
integer, parameter :: l = 20
integer :: a(l), s(l), u(4*l - 2)
integer :: i, j, y, z, p, q, r
do i = 1, n
a(i) = i
recursive subroutine sub(i)
integer :: i, j, k, p, q, s
do k = i, n
j = a(k)
p = i + j - 1
q = i - j + n
if(up(p) .and. down(q)) then
if(i == n) then
m = m + 1
else
up(p) = .false.
down(q) = .false.
s = a(i)
a(i) = a(k)
a(k) = s
call sub(i + 1)
up(p) = .true.
down(q) = .true.
s = a(i)
a(i) = a(k)
a(k) = s
end if
end if
end do
end subroutine
end function
do i = 1, 4*n - 2
u(i) = 0
end do
m = 0
r = 2*n - 1
if (k1 == k2) return
p = 1 - k1 + n
q = 1 + k1 - 1
if ((u(p) /= 0) .or. (u(q + r) /= 0)) return
u(p) = 1
u(q + r) = 1
z = a(1)
a(1) = a(k1)
a(k1) = z
p = 2 - k2 + n
q = 2 + k2 - 1
if ((u(p) /= 0) .or. (u(q + r) /= 0)) return
u(p) = 1
u(q + r) = 1
if (k2 /= 1) then
z = a(2)
a(2) = a(k2)
a(k2) = z
else
z = a(2)
a(2) = a(k1)
a(k1) = z
end if
i = 3
go to 40
30 s(i) = j
u(p) = 1
u(q + r) = 1
i = i + 1
40 if (i > n) go to 80
j = i
50 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)) go to 30
60 j = j + 1
if (j <= n) go to 50
70 j = j - 1
if (j == i) go to 90
z = a(i)
a(i) = a(j)
a(j) = z
go to 70
!valid queens position found
80 m = m + 1
90 i = i - 1
if (i == 2) return
p = i - a(i) + n
q = i + a(i) - 1
j = s(i)
u(p) = 0
u(q + r) = 0
go to 60
end function
program queens
implicit none
integer :: numq, n, m
do n = 4, 16
m = numq(n)
print *, n, m
end do
end program

View file

@ -0,0 +1,122 @@
program queens
use omp_lib
implicit none
integer, parameter :: long = selected_int_kind(17)
integer, parameter :: l = 18
integer :: n, i, j, a(l*l, 2), k, p, q
integer(long) :: s, b(l*l)
real(kind(1d0)) :: t1, t2
do n = 6, l
k = 0
p = n/2
q = mod(n, 2)*(p + 1)
do i = 1, n
do j = 1, n
if ((abs(i - j) > 1) .and. ((i <= p) .or. ((i == q) .and. (j < i)))) then
k = k + 1
a(k, 1) = i
a(k, 2) = j
end if
end do
end do
s = 0
t1 = omp_get_wtime()
!$omp parallel do schedule(dynamic)
do i = 1, k
b(i) = pqueens(n, a(i, 1), a(i, 2))
end do
!$omp end parallel do
t2 = omp_get_wtime()
print "(I4, I12, F12.3)", n, 2*sum(b(1:k)), t2 - t1
end do
contains
function pqueens(n, k1, k2) result(m)
implicit none
integer(long) :: m
integer, intent(in) :: n, k1, k2
integer, parameter :: l = 20
integer :: a(l), s(l), u(4*l - 2)
integer :: i, j, y, z, p, q, r
do i = 1, n
a(i) = i
end do
do i = 1, 4*n - 2
u(i) = 0
end do
m = 0
r = 2*n - 1
if (k1 == k2) return
p = 1 - k1 + n
q = 1 + k1 - 1
if ((u(p) /= 0) .or. (u(q + r) /= 0)) return
u(p) = 1
u(q + r) = 1
z = a(1)
a(1) = a(k1)
a(k1) = z
p = 2 - k2 + n
q = 2 + k2 - 1
if ((u(p) /= 0) .or. (u(q + r) /= 0)) return
u(p) = 1
u(q + r) = 1
if (k2 /= 1) then
z = a(2)
a(2) = a(k2)
a(k2) = z
else
z = a(2)
a(2) = a(k1)
a(k1) = z
end if
i = 3
go to 40
30 s(i) = j
u(p) = 1
u(q + r) = 1
i = i + 1
40 if (i > n) go to 80
j = i
50 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)) go to 30
60 j = j + 1
if (j <= n) go to 50
70 j = j - 1
if (j == i) go to 90
z = a(i)
a(i) = a(j)
a(j) = z
go to 70
!valid queens position found
80 m = m + 1
90 i = i - 1
if (i == 2) return
p = i - a(i) + n
q = i + a(i) - 1
j = s(i)
u(p) = 0
u(q + r) = 0
go to 60
end function
end program

View file

@ -1,37 +1,78 @@
# Quick and dirty solution, checking all permutations without backtracking (thus it's slow)
IsSafe := function(a)
local n, i, j;
n := Length(a);
for i in [1 .. n - 1] do
for j in [i + 1 .. n] do
if AbsInt(a[j] - a[i]) = j - i then
return false;
NrQueens := function(n)
local a, up, down, m, sub;
a := [1 .. n];
up := ListWithIdenticalEntries(2*n - 1, true);
down := ListWithIdenticalEntries(2*n - 1, true);
m := 0;
sub := function(i)
local j, k, p, q;
for k in [i .. n] do
j := a[k];
p := i + j - 1;
q := i - j + n;
if up[p] and down[q] then
if i = n then
m := m + 1;
else
up[p] := false;
down[q] := false;
a[k] := a[i];
a[i] := j;
sub(i + 1);
up[p] := true;
down[q] := true;
a[i] := a[k];
a[k] := j;
fi;
fi;
od;
od;
return true;
end;
sub(1);
return m;
end;
Queens := function(n)
local p, a, v;
local a, up, down, v, sub;
a := [1 .. n];
up := ListWithIdenticalEntries(2*n - 1, true);
down := ListWithIdenticalEntries(2*n - 1, true);
v := [];
for p in SymmetricGroup(n) do
a := List([1 .. n], i -> i^p);
if IsSafe(a) then
Add(v, a);
fi;
od;
sub := function(i)
local j, k, p, q;
for k in [i .. n] do
j := a[k];
p := i + j - 1;
q := i - j + n;
if up[p] and down[q] then
if i = n then
Add(v, ShallowCopy(a));
else
up[p] := false;
down[q] := false;
a[k] := a[i];
a[i] := j;
sub(i + 1);
up[p] := true;
down[q] := true;
a[i] := a[k];
a[k] := j;
fi;
fi;
od;
end;
sub(1);
return v;
end;
v := Queens(8);;
Length(v);
PrintArray(PermutationMat(PermListList([1 .. 8], v[1]), 8));
[ [ 0, 0, 1, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 1, 0, 0 ],
[ 0, 1, 0, 0, 0, 0, 0, 0 ],
NrQueens(8);
a := Queens(8);;
PrintArray(PermutationMat(PermList(a[1]), 8));
[ [ 1, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 1, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 1 ],
[ 1, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 1, 0, 0 ],
[ 0, 0, 1, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 1, 0 ],
[ 0, 1, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 1, 0, 0, 0, 0 ] ]

View file

@ -15,11 +15,10 @@ queens n = map fst $ foldM oneMoreQueen ([],[1..n]) [1..n] where
-- given a safe arrangement y of queens in the first i rows, and a list of
-- possible choices, "oneMoreQueen y _" returns a list of all the safe
-- arrangements of queens in the first (i+1) rows along with remaining choices
oneMoreQueen (y,d) _ = [ (x:y, d\\[x]) | x <- d, safe x y]
oneMoreQueen (y,d) _ = [(x:y, delete x d) | x <- d, safe x] where
-- "safe x y" tests whether a queen at column x is safe from previous
-- queens as recorded in y
safe x y = and [ x /= c && x /= c + n && x /= c - n | (n,c) <- zip [1..] y]
-- "safe x" tests whether a queen at column x is safe from previous queens
safe x = and [x /= c + n && x /= c - n | (n,c) <- zip [1..] y]
-- prints what the board looks like for a solution; with an extra newline
printSolution y = do

View file

@ -7,5 +7,5 @@ main = mapM_ print $ queens 8
queens :: Int -> [[Int]]
queens n = foldM f [] [1..n]
where
f qs k = [q:qs | q <- [1..n] \\ qs, q `notDiag` qs]
f qs _ = [q:qs | q <- [1..n] \\ qs, q `notDiag` qs]
q `notDiag` qs = and [abs (q - qi) /= i | (qi,i) <- qs `zip` [1..]]

View file

@ -0,0 +1,59 @@
Queens New count,flip,row,sol
Set sol=0
For row(1)=1:1:4 Do try(2) ; Not 8, the other 4 are symmetric...
;
; Remove symmetric solutions
Set sol="" For Set sol=$Order(sol(sol)) Quit:sol="" Do
. New xx,yy
. Kill sol($Translate(sol,12345678,87654321)) ; Vertical flip
. Kill sol($Reverse(sol)) ; Horizontal flip
. Set flip="--------" for xx=1:1:8 Do ; Flip over top left to bottom right diagonal
. . New nx,ny
. . Set yy=$Extract(sol,xx),nx=8+1-xx,ny=8+1-yy
. . Set $Extract(flip,ny)=nx
. . Quit
. Kill sol(flip)
. Set flip="--------" for xx=1:1:8 Do ; Flip over top right to bottom left diagonal
. . New nx,ny
. . Set yy=$Extract(sol,xx),nx=xx,ny=yy
. . Set $Extract(flip,ny)=nx
. . Quit
. Kill sol(flip)
. Quit
;
; Display remaining solutions
Set count=0,sol="" For Set sol=$Order(sol(sol)) Quit:sol="" Do Quit:sol=""
. New s1,s2,s3,txt,x,y
. Set s1=sol,s2=$Order(sol(s1)),s3="" Set:s2'="" s3=$Order(sol(s2))
. Set txt="+--+--+--+--+--+--+--+--+"
. Write !," ",txt Write:s2'="" " ",txt Write:s3'="" " ",txt
. For y=8:-1:1 Do
. . Write !,y," |"
. . For x=1:1:8 Write $Select($Extract(s1,x)=y:" Q",x+y#2:" ",1:"##"),"|"
. . If s2'="" Write " |"
. . If s2'="" For x=1:1:8 Write $Select($Extract(s2,x)=y:" Q",x+y#2:" ",1:"##"),"|"
. . If s3'="" Write " |"
. . If s3'="" For x=1:1:8 Write $Select($Extract(s3,x)=y:" Q",x+y#2:" ",1:"##"),"|"
. . Write !," ",txt Write:s2'="" " ",txt Write:s3'="" " ",txt
. . Quit
. Set txt=" A B C D E F G H"
. Write !," ",txt Write:s2'="" " ",txt Write:s3'="" " ",txt Write !
. Set sol=s3
. Quit
Quit
try(col) New ok,pcol
If col>8 Do Quit
. New out,x
. Set out="" For x=1:1:8 Set out=out_row(x)
. Set sol(out)=1
. Quit
For row(col)=1:1:8 Do
. Set ok=1
. For pcol=1:1:col-1 If row(pcol)=row(col) Set ok=0 Quit
. Quit:'ok
. For pcol=1:1:col-1 If col-pcol=$Translate(row(pcol)-row(col),"-") Set ok=0 Quit
. Quit:'ok
. Do try(col+1)
. Quit
Quit
Do Queens

View file

@ -1,63 +1,3 @@
Queens New count,flip,row,sol
Set sol=0
For row(1)=1:1:4 Do try(2) ; Not 8, the other 4 are symmetric...
;
; Remove symmetric solutions
Set sol="" For Set sol=$Order(sol(sol)) Quit:sol="" Do
. New xx,yy
. Kill sol($Translate(sol,12345678,87654321)) ; Vertical flip
. Kill sol($Reverse(sol)) ; Horizontal flip
. Set flip="--------" for xx=1:1:8 Do ; Flip over top left to bottom right diagonal
. . New nx,ny
. . Set yy=$Extract(sol,xx),nx=8+1-xx,ny=8+1-yy
. . Set $Extract(flip,ny)=nx
. . Quit
. Kill sol(flip)
. Set flip="--------" for xx=1:1:8 Do ; Flip over top right to bottom left diagonal
. . New nx,ny
. . Set yy=$Extract(sol,xx),nx=xx,ny=yy
. . Set $Extract(flip,ny)=nx
. . Quit
. Kill sol(flip)
. Quit
;
; Display remaining solutions
Set count=0,sol="" For Set sol=$Order(sol(sol)) Quit:sol="" Do Quit:sol=""
. New s1,s2,s3,txt,x,y
. Set s1=sol,s2=$Order(sol(s1)),s3="" Set:s2'="" s3=$Order(sol(s2))
. Set txt="+--+--+--+--+--+--+--+--+"
. Write !," ",txt Write:s2'="" " ",txt Write:s3'="" " ",txt
. For y=8:-1:1 Do
. . Write !,y," |"
. . For x=1:1:8 Write $Select($Extract(s1,x)=y:" Q",x+y#2:" ",1:"##"),"|"
. . If s2'="" Write " |"
. . If s2'="" For x=1:1:8 Write $Select($Extract(s2,x)=y:" Q",x+y#2:" ",1:"##"),"|"
. . If s3'="" Write " |"
. . If s3'="" For x=1:1:8 Write $Select($Extract(s3,x)=y:" Q",x+y#2:" ",1:"##"),"|"
. . Write !," ",txt Write:s2'="" " ",txt Write:s3'="" " ",txt
. . Quit
. Set txt=" A B C D E F G H"
. Write !," ",txt Write:s2'="" " ",txt Write:s3'="" " ",txt Write !
. Set sol=s3
. Quit
Quit
try(col) New ok,pcol
If col>8 Do Quit
. New out,x
. Set out="" For x=1:1:8 Set out=out_row(x)
. Set sol(out)=1
. Quit
For row(col)=1:1:8 Do
. Set ok=1
. For pcol=1:1:col-1 If row(pcol)=row(col) Set ok=0 Quit
. Quit:'ok
. For pcol=1:1:col-1 If col-pcol=$Translate(row(pcol)-row(col),"-") Set ok=0 Quit
. Quit:'ok
. Do try(col+1)
. Quit
Quit
Do Queens
+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
8 | |##| Q|##| |##| |##| | |##| Q|##| |##| |##| | |##| | Q| |##| |##|
+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+

View file

@ -2,8 +2,8 @@ safe[q_List, n_] :=
With[{l = Length@q},
Length@Union@q == Length@Union[q + Range@l] ==
Length@Union[q - Range@l] == l]
nQueen[q_List:{}, n_] :=
nQueen[q_List: {}, n_] :=
If[safe[q, n],
If[Length[q] == n, q,
Cases[Flatten[{nQueen[Append[q, #], n]}, 2] & /@ Range[n],
Except[{Null} | {}]]], Null]
If[Length[q] == n, {q},
Cases[nQueen[Append[q, #], n] & /@ Range[n],
Except[{Null} | {}], {2}]], Null]

View file

@ -0,0 +1,44 @@
dispSol[sol_] := sol /. {1 -> "Q" , 0 -> "-"} // Grid
solveNqueens[n_] :=
Module[{c, m, b, vars}, c = cqueens[n]; m = mqueens[n];
vars = mqueens2[n]; b = bqueens[Length[m]];
Partition[LinearProgramming[c, m, b, vars, Integers], n]]
cqueens[n_] := Table[-1, {i, n^2}]
bqueens[l_] := Table[{1, -1}, {i, l}]
mqueens2[n_] := Table[{0, 1}, {i, n^2}]
mqueens[n_] :=
Module[{t, t2, t3, t4}, t = mqueensh[n]; t2 = Append[t, mqueensv[n]];
t3 = Append[t2, mqueensd[n]]; t4 = Append[t3, mqueensdm[n]];
Partition[Flatten[t4], n^2]]
mqueensh[n_] :=
Module[{t}, t = Table[0, {i, n}, {j, n^2}];
For[i = 1, i <= n, i++,
For[j = 1, j <= n, j++, t[[i, ((i - 1)*n) + j]] = 1]]; t]
mqueensv[n_] :=
Module[{t}, t = Table[0, {i, n}, {j, n^2}];
For[i = 1, i <= n, i++,
For[j = 1, j <= n, j++, t[[j, ((i - 1)*n) + j]] = 1]]; t]
mqueensd[n_] :=
Module[{t}, t = Table[0, {i, (2*n) - 1}, {j, n^2}];
For[k = 2, k <= 2 n, k++,
For[i = 1, i <= n, i++,
For[j = 1, j <= n, j++,
If[i + j == k, t[[k - 1, ((i - 1)*n) + j]] = 1]]]]; t]
mqueensdm[n_] :=
Module[{t}, t = Table[0, {i, Sum[1, {i, 1 - n, n - 1}]}, {j, n^2}];
For[k = 1 - n, k <= n - 1, k++,
For[i = 1, i <= n, i++,
For[j = 1, j <= n, j++,
If[i == j - k, t[[k + n, ((i - 1)*n) + j]] = 1]]]]; t]
solveNqueens[8] // dispSol

View file

@ -0,0 +1,112 @@
program NQueens;
{$IFDEF FPC}
{$MODE DELPHI}
{$OPTIMIZATION ON}{$OPTIMIZATION REGVAR}{$OPTIMIZATION PeepHole}
{$OPTIMIZATION CSE}{$OPTIMIZATION ASMCSE}
{$ELSE}
{$Apptype console}
{$ENDIF}
uses
sysutils;// TDatetime
const
nmax = 17;
type
{$IFNDEF FPC}
NativeInt = longInt;
{$ENDIF}
//ala Nikolaus Wirth A-1 = H - 8
//diagonal left (A1) to rigth (H8)
tLR_diagonale = array[-nmax-1..nmax-1] of char;
//diagonal right (A8) to left (H1)
tRL_diagonale = array[0..2*nmax-2] of char;
//up to Col are the used Cols, after that the unused
tFreeCol = array[0..nmax-1] of nativeInt;
var
LR_diagonale:tLR_diagonale;
RL_diagonale:tRL_diagonale;
//Using pChar, cause it is implicit an array
//It is always set to
//@LR_diagonale[row] ,@RL_diagonale[row]
pLR,pRL : pChar;
FreeCol : tFreeCol;
i,
n : nativeInt;
gblCount : nativeUInt;
T0,T1 : TdateTime;
procedure Solution;
var
i : NativeInt;
begin
// Take's a lot of time under DOS/Win32
If gblCount AND $FFF = 0 then
write(gblCount:10,#8#8#8#8#8#8#8#8#8#8);
// IF n< 9 then
IF n < 0 then
begin
For i := 1 to n do
write(FreeCol[i]:4);
writeln;
end;
end;
procedure SetQueen(Row:nativeInt);
var
i,Col : nativeInt;
begin
IF row <= n then
begin
For i := row to n do
begin
Col := FreeCol[i];
//check diagonals occupied
If (ORD(pLR[-Col]) AND ORD(pRL[Col]))<>0 then
begin
//a "free" position is found
//mark it
pRL[ Col]:=#0; //RL_Diagonale[ Row +Col] := 0;
pLR[-Col]:=#0; //LR_Diagonale[ Row -Col] := 0;
//swap FreeRow[Row<->i]
FreeCol[i] := FreeCol[Row];
//next row
inc(pRL);
inc(pLR);
FreeCol[Row] := Col;
// check next row
SetQueen(Row+1);
//Undo
dec(pLR);
dec(pRL);
FreeCol[Row] := FreeCol[i];
FreeCol[i] := Col;
pRL[ Col]:=#1;
pLR[-Col]:=#1;
end;
end;
end
else
begin
//solution ist found
inc(gblCount);
//Solution
end;
end;
begin
For i := 0 to nmax-1 do
FreeCol[i] := i;
//diagonals filled with True = #1 , something <>0
fillchar(LR_Diagonale[low(LR_Diagonale)],sizeof(tLR_Diagonale),#1);
fillchar(RL_Diagonale[low(RL_Diagonale)],sizeof(tRL_Diagonale),#1);
For n := 1 to nMax do
begin
t0 := time;
pLR:=@LR_Diagonale[0];
pRL:=@RL_Diagonale[0];
gblCount := 0;
SetQueen(1);
t1:= time;
WriteLn(n:6,gblCount:12,FormatDateTime(' NN:SS.ZZZ',T1-t0),' secs');
end;
WriteLn('Fertig');
end.

View file

@ -1,23 +1,16 @@
% 8 queens problem.
% q(Row) represents a queen, allocated one per row. No rows ever clash.
% The columns are chosen iteratively from available columns held in a
% list, reduced with each allocation, so we need never check verticals.
% For diagonals, we check prior to allocation whether each newly placed
% queen will clash with any of the prior placements. This prevents
% most invalid permutations from ever being attempted.
can_place(_, []) :- !. % success for empty board
can_place(q(R,C),Board) :- % check diagonals against allocated queens
member(q(Ra,Ca), Board), abs(Ra-R) =:= abs(Ca-C), !, fail.
can_place(_,_). % succeed if no diagonals failed
:- initialization(main).
queens([], [], Board, Board). % found a solution
queens([q(R)|Queens], Columns, Board, Solution) :-
nth0(_,Columns,C,Free), can_place(q(R,C),Board), % find all solutions
queens(Queens,Free,[q(R,C)|Board], Solution). % recursively
queens :-
findall(q(N), between(0,7,N), Queens), findall(N, between(0,7,N), Columns),
findall(B, queens(Queens, Columns, [], B), Boards), % backtrack over all
length(Boards, Len), writef('%w solutions:\n', [Len]), % Output solutions
member(R,Boards), reverse(R,Board), writef(' - %w\n', [Board]), fail.
queens.
queens(N,Qs) :- bagof(X, between(1,N,X), Xs), place(Xs,[],Qs).
place(Xs,Qs,Res) :-
Xs = [] -> Res = Qs
; select(Q,Xs,Ys), not_diag(Q,Qs,1), place(Ys,[Q|Qs],Res)
.
not_diag(_, [] , _).
not_diag(Q, [Qh|Qs], D) :-
abs(Q - Qh) =\= D, D1 is D + 1, not_diag(Q,Qs,D1).
main :- findall(Qs, (queens(8,Qs), write(Qs), nl), _), halt.

View file

@ -0,0 +1,23 @@
% 8 queens problem.
% q(Row) represents a queen, allocated one per row. No rows ever clash.
% The columns are chosen iteratively from available columns held in a
% list, reduced with each allocation, so we need never check verticals.
% For diagonals, we check prior to allocation whether each newly placed
% queen will clash with any of the prior placements. This prevents
% most invalid permutations from ever being attempted.
can_place(_, []) :- !. % success for empty board
can_place(q(R,C),Board) :- % check diagonals against allocated queens
member(q(Ra,Ca), Board), abs(Ra-R) =:= abs(Ca-C), !, fail.
can_place(_,_). % succeed if no diagonals failed
queens([], [], Board, Board). % found a solution
queens([q(R)|Queens], Columns, Board, Solution) :-
nth0(_,Columns,C,Free), can_place(q(R,C),Board), % find all solutions
queens(Queens,Free,[q(R,C)|Board], Solution). % recursively
queens :-
findall(q(N), between(0,7,N), Queens), findall(N, between(0,7,N), Columns),
findall(B, queens(Queens, Columns, [], B), Boards), % backtrack over all
length(Boards, Len), writef('%w solutions:\n', [Len]), % Output solutions
member(R,Boards), reverse(R,Board), writef(' - %w\n', [Board]), fail.
queens.

View file

@ -0,0 +1,20 @@
def queens(n):
a = list(range(n))
up = [True]*(2*n - 1)
down = [True]*(2*n - 1)
def sub(i):
nonlocal a, up, down
for k in range(i, n):
j = a[k]
p = i + j
q = i - j + n - 1
if up[p] and down[q]:
if i == n - 1:
yield tuple(a)
else:
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)

View file

@ -1,64 +1,51 @@
/*REXX program place N queens on a NxN chessboard (the 8 queens problem)*/
/*REXX program places N queens on a NxN chessboard; the 8 queens problem*/
parse arg N . /*get board size arg (if any). */
if N=='' then N=8 /*No argument? Use the default.*/
file=1; rank=1; q=0 /*starting place, # of queens. */
if N=='' then N=8; if N<1 then call noSol /*No arg? Use the default.*/
rank=1; file=1; q=0 /*starting rank & file; # queens.*/
@.=0; !=left('', 9* (N<18)) /*define empty board, indentation*/
/*═════════════════════════════════════find solution: N queens problem.*/
do while q<N /*keep placing queens until done.*/
@.file.rank=1 /*place a queen on the chessboard*/
do while q<N; @.file.rank=1 /*keep placing queens until done.*/
if safe?(file,rank) then do; q=q+1 /*if not being attacked, eureka! */
file=1 /*another attempt at file #1, */
file=1 /*another attempt at another file*/
rank=rank+1 /*and also bump the rank pointer.*/
end
else do /*¬ safe, so it's a bad placement*/
@.file.rank=0 /* So, remove this queen. */
file=file+1 /*try the next file then. */
do while file>N; rank=rank-1
if rank==0 then call noSol
do j=1 for N
if @.j.rank then do; file=j; @.file.rank=0
q=q-1; file=j+1
leave /*j*/
end
end /*j*/
end /*do while file>N*/
end /*else do*/
end /*while q<N*/
iterate /*go&try another queen placement.*/
end /* [↑] found a good Q placement.*/
@.file.rank=0 /*not 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; q=q-1; file=j+1; leave /*j*/
end /*j*/
end /*while file>N*/
end /*while q<N*/
/*══════════════════════════════════════show chessboard with a solution.*/
say 'A solution for' N "queens:"; _ = substr( copies("┼───", N) ,2)
say 'A solution for' N "queens:"; _ = substr( copies("┼───", N) ,2)
lineT = ''_""; say; say ! translate(lineT,'',"")
lineB = ''_""; lineB = translate(lineB, '', "")
line = ''_"" /*define a line for cell boundry.*/
bar = '' /*kinds: horizonal/vertical/salad*/
Bqueen = '' /*glyph befitting the black queen*/
Wqueen = ' ' /* " " " white " */
/*═══════════════════════==══════════════place the queens on chessboard.*/
do r=1 for N; if r\==1 then say ! line; _= /*process the rank &*/
if 1=='f1'x then do; queenSymbol='Q'; dither='9c'x; end /*for EBCDIC.*/
else do; queenSymbol=''; dither='b0'x; end /* " ASCII.*/
Bqueen = dither||queenSymbol||dither /*glyph befitting the black queen*/
Wqueen = ' 'queenSymbol" " /* " " " white " */
/*═══════════════════════════════════════show chessboard with the queens*/
do r=1 for N; if r\==1 then say ! line; _= /*process the rank &*/
do f=1 for N; black=(f+r)//2 /*the file; is it a black square?*/
qgylph=Wqueen; if black then Qgylph=Bqueen /*use a black queen.*/
Qgylph=Wqueen; if black then Qgylph=Bqueen /*use a black queen.*/
/*is it black sqare?*/
if @.f.r then _=_ || bar || Qgylph /*use the 3-char symbol for queen*/
else if black then _=_ || bar'' /*¼ dithering char. */
else _=_ || bar' ' /*three blanks. */
else if black then _=_||bar||copies(dither,3) /*dithering.*/
else _=_||bar' ' /*3 blanks. */
end /*f*/ /* [↑] preserve square chessboard*/
say ! _ || bar
say ! _ || bar /*show a rank of the chessboard. */
end /*r*/ /*80 cols can view 19x19 chessbrd*/
say ! lineB; say /*show last line, + a blank line.*/
exit 1 /*stick a fork in it, we're done.*/
/*──────────────────────────────────NOSOL subroutine────────────────────*/
noSol: say "No solution for" N 'queens.'; exit 0
/*──────────────────────────────────SAFE? subroutine────────────────────*/
safe?: procedure expose @.; parse arg file,rank
do k=rank-1 to 1 by -1; if @.file.k then return 0
end
f=file-1; r=rank-1
do while f\==0 & r\==0; if @.f.r then return 0
f=f-1; r=r-1
end
f=file+1; r=rank-1
do while f<=n & r\==0; if @.f.r then return 0
f=f+1; r=r-1
end
safe?: procedure expose @. N; 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

View file

@ -11,91 +11,7 @@
;(list (Q 7 4) (Q 6 1) (Q 5 3) (Q 4 6) (Q 3 2) (Q 2 7) (Q 1 5) (Q 0 0))
;(list (Q 7 2) (Q 6 4) (Q 5 1) (Q 4 7) (Q 3 5) (Q 2 3) (Q 1 6) (Q 0 0))
;(list (Q 7 2) (Q 6 5) (Q 5 3) (Q 4 1) (Q 3 7) (Q 2 4) (Q 1 6) (Q 0 0))
;(list (Q 7 4) (Q 6 6) (Q 5 0) (Q 4 2) (Q 3 7) (Q 2 5) (Q 1 3) (Q 0 1))
;(list (Q 7 3) (Q 6 5) (Q 5 7) (Q 4 2) (Q 3 0) (Q 2 6) (Q 1 4) (Q 0 1))
;(list (Q 7 2) (Q 6 5) (Q 5 7) (Q 4 0) (Q 3 3) (Q 2 6) (Q 1 4) (Q 0 1))
;(list (Q 7 4) (Q 6 2) (Q 5 7) (Q 4 3) (Q 3 6) (Q 2 0) (Q 1 5) (Q 0 1))
;(list (Q 7 4) (Q 6 6) (Q 5 3) (Q 4 0) (Q 3 2) (Q 2 7) (Q 1 5) (Q 0 1))
;(list (Q 7 3) (Q 6 0) (Q 5 4) (Q 4 7) (Q 3 5) (Q 2 2) (Q 1 6) (Q 0 1))
;(list (Q 7 2) (Q 6 5) (Q 5 3) (Q 4 0) (Q 3 7) (Q 2 4) (Q 1 6) (Q 0 1))
;(list (Q 7 3) (Q 6 6) (Q 5 4) (Q 4 2) (Q 3 0) (Q 2 5) (Q 1 7) (Q 0 1))
;(list (Q 7 5) (Q 6 3) (Q 5 1) (Q 4 7) (Q 3 4) (Q 2 6) (Q 1 0) (Q 0 2))
;(list (Q 7 5) (Q 6 3) (Q 5 6) (Q 4 0) (Q 3 7) (Q 2 1) (Q 1 4) (Q 0 2))
;(list (Q 7 0) (Q 6 6) (Q 5 3) (Q 4 5) (Q 3 7) (Q 2 1) (Q 1 4) (Q 0 2))
;(list (Q 7 5) (Q 6 7) (Q 5 1) (Q 4 3) (Q 3 0) (Q 2 6) (Q 1 4) (Q 0 2))
;(list (Q 7 5) (Q 6 1) (Q 5 6) (Q 4 0) (Q 3 3) (Q 2 7) (Q 1 4) (Q 0 2))
;(list (Q 7 3) (Q 6 6) (Q 5 0) (Q 4 7) (Q 3 4) (Q 2 1) (Q 1 5) (Q 0 2))
;(list (Q 7 4) (Q 6 7) (Q 5 3) (Q 4 0) (Q 3 6) (Q 2 1) (Q 1 5) (Q 0 2))
;(list (Q 7 3) (Q 6 7) (Q 5 0) (Q 4 4) (Q 3 6) (Q 2 1) (Q 1 5) (Q 0 2))
;(list (Q 7 1) (Q 6 6) (Q 5 4) (Q 4 7) (Q 3 0) (Q 2 3) (Q 1 5) (Q 0 2))
;(list (Q 7 0) (Q 6 6) (Q 5 4) (Q 4 7) (Q 3 1) (Q 2 3) (Q 1 5) (Q 0 2))
;(list (Q 7 1) (Q 6 4) (Q 5 6) (Q 4 3) (Q 3 0) (Q 2 7) (Q 1 5) (Q 0 2))
;(list (Q 7 3) (Q 6 1) (Q 5 6) (Q 4 4) (Q 3 0) (Q 2 7) (Q 1 5) (Q 0 2))
;(list (Q 7 4) (Q 6 6) (Q 5 0) (Q 4 3) (Q 3 1) (Q 2 7) (Q 1 5) (Q 0 2))
;(list (Q 7 5) (Q 6 3) (Q 5 0) (Q 4 4) (Q 3 7) (Q 2 1) (Q 1 6) (Q 0 2))
;(list (Q 7 4) (Q 6 0) (Q 5 3) (Q 4 5) (Q 3 7) (Q 2 1) (Q 1 6) (Q 0 2))
;(list (Q 7 4) (Q 6 1) (Q 5 5) (Q 4 0) (Q 3 6) (Q 2 3) (Q 1 7) (Q 0 2))
;(list (Q 7 5) (Q 6 2) (Q 5 6) (Q 4 1) (Q 3 7) (Q 2 4) (Q 1 0) (Q 0 3))
;(list (Q 7 1) (Q 6 6) (Q 5 2) (Q 4 5) (Q 3 7) (Q 2 4) (Q 1 0) (Q 0 3))
;(list (Q 7 6) (Q 6 2) (Q 5 0) (Q 4 5) (Q 3 7) (Q 2 4) (Q 1 1) (Q 0 3))
;(list (Q 7 4) (Q 6 0) (Q 5 7) (Q 4 5) (Q 3 2) (Q 2 6) (Q 1 1) (Q 0 3))
;(list (Q 7 0) (Q 6 4) (Q 5 7) (Q 4 5) (Q 3 2) (Q 2 6) (Q 1 1) (Q 0 3))
;(list (Q 7 2) (Q 6 5) (Q 5 7) (Q 4 0) (Q 3 4) (Q 2 6) (Q 1 1) (Q 0 3))
;(list (Q 7 5) (Q 6 2) (Q 5 0) (Q 4 6) (Q 3 4) (Q 2 7) (Q 1 1) (Q 0 3))
;(list (Q 7 6) (Q 6 4) (Q 5 2) (Q 4 0) (Q 3 5) (Q 2 7) (Q 1 1) (Q 0 3))
;(list (Q 7 6) (Q 6 2) (Q 5 7) (Q 4 1) (Q 3 4) (Q 2 0) (Q 1 5) (Q 0 3))
;(list (Q 7 4) (Q 6 2) (Q 5 0) (Q 4 6) (Q 3 1) (Q 2 7) (Q 1 5) (Q 0 3))
;(list (Q 7 1) (Q 6 4) (Q 5 6) (Q 4 0) (Q 3 2) (Q 2 7) (Q 1 5) (Q 0 3))
;(list (Q 7 2) (Q 6 5) (Q 5 1) (Q 4 4) (Q 3 7) (Q 2 0) (Q 1 6) (Q 0 3))
;(list (Q 7 5) (Q 6 0) (Q 5 4) (Q 4 1) (Q 3 7) (Q 2 2) (Q 1 6) (Q 0 3))
;(list (Q 7 7) (Q 6 2) (Q 5 0) (Q 4 5) (Q 3 1) (Q 2 4) (Q 1 6) (Q 0 3))
;(list (Q 7 1) (Q 6 7) (Q 5 5) (Q 4 0) (Q 3 2) (Q 2 4) (Q 1 6) (Q 0 3))
;(list (Q 7 4) (Q 6 6) (Q 5 1) (Q 4 5) (Q 3 2) (Q 2 0) (Q 1 7) (Q 0 3))
;(list (Q 7 2) (Q 6 5) (Q 5 1) (Q 4 6) (Q 3 4) (Q 2 0) (Q 1 7) (Q 0 3))
;(list (Q 7 5) (Q 6 1) (Q 5 6) (Q 4 0) (Q 3 2) (Q 2 4) (Q 1 7) (Q 0 3))
;(list (Q 7 2) (Q 6 6) (Q 5 1) (Q 4 7) (Q 3 5) (Q 2 3) (Q 1 0) (Q 0 4))
;(list (Q 7 5) (Q 6 2) (Q 5 6) (Q 4 1) (Q 3 3) (Q 2 7) (Q 1 0) (Q 0 4))
;(list (Q 7 3) (Q 6 1) (Q 5 6) (Q 4 2) (Q 3 5) (Q 2 7) (Q 1 0) (Q 0 4))
;(list (Q 7 6) (Q 6 0) (Q 5 2) (Q 4 7) (Q 3 5) (Q 2 3) (Q 1 1) (Q 0 4))
;(list (Q 7 0) (Q 6 5) (Q 5 7) (Q 4 2) (Q 3 6) (Q 2 3) (Q 1 1) (Q 0 4))
;(list (Q 7 2) (Q 6 7) (Q 5 3) (Q 4 6) (Q 3 0) (Q 2 5) (Q 1 1) (Q 0 4))
;(list (Q 7 5) (Q 6 2) (Q 5 6) (Q 4 3) (Q 3 0) (Q 2 7) (Q 1 1) (Q 0 4))
;(list (Q 7 6) (Q 6 3) (Q 5 1) (Q 4 7) (Q 3 5) (Q 2 0) (Q 1 2) (Q 0 4))
;(list (Q 7 3) (Q 6 5) (Q 5 7) (Q 4 1) (Q 3 6) (Q 2 0) (Q 1 2) (Q 0 4))
;(list (Q 7 1) (Q 6 5) (Q 5 0) (Q 4 6) (Q 3 3) (Q 2 7) (Q 1 2) (Q 0 4))
;(list (Q 7 1) (Q 6 3) (Q 5 5) (Q 4 7) (Q 3 2) (Q 2 0) (Q 1 6) (Q 0 4))
;(list (Q 7 2) (Q 6 5) (Q 5 7) (Q 4 1) (Q 3 3) (Q 2 0) (Q 1 6) (Q 0 4))
;(list (Q 7 5) (Q 6 2) (Q 5 0) (Q 4 7) (Q 3 3) (Q 2 1) (Q 1 6) (Q 0 4))
;(list (Q 7 7) (Q 6 3) (Q 5 0) (Q 4 2) (Q 3 5) (Q 2 1) (Q 1 6) (Q 0 4))
;(list (Q 7 3) (Q 6 7) (Q 5 0) (Q 4 2) (Q 3 5) (Q 2 1) (Q 1 6) (Q 0 4))
;(list (Q 7 1) (Q 6 5) (Q 5 7) (Q 4 2) (Q 3 0) (Q 2 3) (Q 1 6) (Q 0 4))
;(list (Q 7 6) (Q 6 1) (Q 5 5) (Q 4 2) (Q 3 0) (Q 2 3) (Q 1 7) (Q 0 4))
;(list (Q 7 2) (Q 6 5) (Q 5 1) (Q 4 6) (Q 3 0) (Q 2 3) (Q 1 7) (Q 0 4))
;(list (Q 7 3) (Q 6 6) (Q 5 2) (Q 4 7) (Q 3 1) (Q 2 4) (Q 1 0) (Q 0 5))
;(list (Q 7 3) (Q 6 7) (Q 5 4) (Q 4 2) (Q 3 0) (Q 2 6) (Q 1 1) (Q 0 5))
;(list (Q 7 2) (Q 6 4) (Q 5 7) (Q 4 3) (Q 3 0) (Q 2 6) (Q 1 1) (Q 0 5))
;(list (Q 7 3) (Q 6 1) (Q 5 7) (Q 4 4) (Q 3 6) (Q 2 0) (Q 1 2) (Q 0 5))
;(list (Q 7 4) (Q 6 6) (Q 5 1) (Q 4 3) (Q 3 7) (Q 2 0) (Q 1 2) (Q 0 5))
;(list (Q 7 6) (Q 6 3) (Q 5 1) (Q 4 4) (Q 3 7) (Q 2 0) (Q 1 2) (Q 0 5))
;(list (Q 7 7) (Q 6 1) (Q 5 3) (Q 4 0) (Q 3 6) (Q 2 4) (Q 1 2) (Q 0 5))
;(list (Q 7 6) (Q 6 1) (Q 5 3) (Q 4 0) (Q 3 7) (Q 2 4) (Q 1 2) (Q 0 5))
;(list (Q 7 4) (Q 6 0) (Q 5 7) (Q 4 3) (Q 3 1) (Q 2 6) (Q 1 2) (Q 0 5))
;(list (Q 7 3) (Q 6 0) (Q 5 4) (Q 4 7) (Q 3 1) (Q 2 6) (Q 1 2) (Q 0 5))
;(list (Q 7 4) (Q 6 1) (Q 5 7) (Q 4 0) (Q 3 3) (Q 2 6) (Q 1 2) (Q 0 5))
;(list (Q 7 2) (Q 6 6) (Q 5 1) (Q 4 7) (Q 3 4) (Q 2 0) (Q 1 3) (Q 0 5))
;(list (Q 7 2) (Q 6 0) (Q 5 6) (Q 4 4) (Q 3 7) (Q 2 1) (Q 1 3) (Q 0 5))
;(list (Q 7 7) (Q 6 1) (Q 5 4) (Q 4 2) (Q 3 0) (Q 2 6) (Q 1 3) (Q 0 5))
;(list (Q 7 2) (Q 6 4) (Q 5 1) (Q 4 7) (Q 3 0) (Q 2 6) (Q 1 3) (Q 0 5))
;(list (Q 7 2) (Q 6 4) (Q 5 6) (Q 4 0) (Q 3 3) (Q 2 1) (Q 1 7) (Q 0 5))
;(list (Q 7 4) (Q 6 1) (Q 5 3) (Q 4 5) (Q 3 7) (Q 2 2) (Q 1 0) (Q 0 6))
;(list (Q 7 5) (Q 6 2) (Q 5 4) (Q 4 7) (Q 3 0) (Q 2 3) (Q 1 1) (Q 0 6))
;(list (Q 7 4) (Q 6 7) (Q 5 3) (Q 4 0) (Q 3 2) (Q 2 5) (Q 1 1) (Q 0 6))
;(list (Q 7 3) (Q 6 1) (Q 5 4) (Q 4 7) (Q 3 5) (Q 2 0) (Q 1 2) (Q 0 6))
;(list (Q 7 3) (Q 6 5) (Q 5 0) (Q 4 4) (Q 3 1) (Q 2 7) (Q 1 2) (Q 0 6))
;(list (Q 7 5) (Q 6 2) (Q 5 0) (Q 4 7) (Q 3 4) (Q 2 1) (Q 1 3) (Q 0 6))
;(list (Q 7 4) (Q 6 2) (Q 5 0) (Q 4 5) (Q 3 7) (Q 2 1) (Q 1 3) (Q 0 6))
;(list (Q 7 3) (Q 6 1) (Q 5 7) (Q 4 5) (Q 3 0) (Q 2 2) (Q 1 4) (Q 0 6))
;(list (Q 7 5) (Q 6 2) (Q 5 4) (Q 4 6) (Q 3 0) (Q 2 3) (Q 1 1) (Q 0 7))
...
;(list (Q 7 5) (Q 6 3) (Q 5 6) (Q 4 0) (Q 3 2) (Q 2 4) (Q 1 1) (Q 0 7))
;(list (Q 7 3) (Q 6 6) (Q 5 4) (Q 4 1) (Q 3 5) (Q 2 0) (Q 1 2) (Q 0 7))
;(list (Q 7 4) (Q 6 6) (Q 5 1) (Q 4 5) (Q 3 2) (Q 2 0) (Q 1 3) (Q 0 7))

View file

@ -0,0 +1,29 @@
WITH RECURSIVE
positions(i) as (
VALUES(0)
UNION SELECT ALL
i+1 FROM positions WHERE i < 63
),
solutions(board, n_queens) AS (
SELECT '----------------------------------------------------------------', cast(0 AS bigint)
FROM positions
UNION
SELECT
substr(board, 1, i) || '*' || substr(board, i+2),n_queens + 1 as n_queens
FROM positions AS ps, solutions
WHERE n_queens < 8
AND substr(board,1,i) != '*'
AND NOT EXISTS (
SELECT 1 FROM positions WHERE
substr(board,i+1,1) = '*' AND
(
i % 8 = ps.i %8 OR
cast(i / 8 AS INT) = cast(ps.i / 8 AS INT) OR
cast(i / 8 AS INT) + (i % 8) = cast(ps.i / 8 AS INT) + (ps.i % 8) OR
cast(i / 8 AS INT) - (i % 8) = cast(ps.i / 8 AS INT) - (ps.i % 8)
)
LIMIT 1
)
ORDER BY n_queens DESC -- remove this when using Postgres (they don't support ORDER BY in CTEs)
)
SELECT board,n_queens FROM solutions WHERE n_queens = 8;