In the previous article, we discussed the eight queens puzzle and developed a mathematical intuition needed for solving it; the rest of the article discussed how to apply recursion and backtracking techniques to solve the general n-queens problem. For completeness, we provide a sample solution in the C++ programming language.
The implementation of the algorithm for solving the n-queens problem is highlighted. This is a complete standalone program that will enumerate all valid solutions to the problem for a given n. The explanation for the algorithm can be found in the link above.
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. *//**
* \author DeepNet42
* \file nqueens3_solutions.cpp
* \version 1
* \date 2022
* \copyright (c) 2022 DeepNet42. All rights reserved.
* This project is released under the Mozilla Public License v. 2.0.
*//* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. *//**
* \author DeepNet42
* \file nqueens3_solutions.cpp
* \version 1
* \date 2022
* \copyright (c) 2022 DeepNet42. All rights reserved.
* This project is released under the Mozilla Public License v. 2.0.
*/#include<print>#include<vector>#include<stdexcept>#include<algorithm>#include<numeric>#include<ranges>constexprconstint DEFAULT_BOARD_SIZE =8;
constexprconstint NONE =-1;
[[nodiscard]]constexprconstint diaSize(constint board_size) {
return2* board_size;
}
classNQueens {
public: NQueens(int n = DEFAULT_BOARD_SIZE) : board(n,NONE),
horizontal(n,false),
diaRise(diaSize(n),false),
diaFall(diaSize(n),false),
n{n},
solutions{0},
solved{false}
{
}
voidenumerate() {
solve(0);
}
[[nodiscard]]auto count() const {
return solutions;
}
private:void placeQueen(int x, int y) {
updateBoard(x,y,true);
}
voidremoveQueen(int x, int y) {
updateBoard(x,y,false);
}
voidupdateBoard(int x, int y, bool state) {
board [x ] = (state? y: NONE);
horizontal [y ] = state;
diaRise [y-x+n] = state;
diaFall [x+y ] = state;
}
voidsolve(int x) {
if(x == n) {
solutions++;
std::println("{}", board | std::views::transform([](int val){ return val +1; }));
} else {
for(auto y : std::views::iota(0,n)) {
if(good(x,y)) {
placeQueen(x,y);
solve(x+1);
removeQueen(x,y);
} else {
}
}
}
}
[[nodiscard]]bool good(int x, int y) const {
return!horizontal[y] and !diaRise[y-x+n] and !diaFall[x+y];
}
private: std::vector<int> board;
std::vector<int> horizontal;
std::vector<int> diaRise;
std::vector<int> diaFall;
int n;
int solutions;
bool solved;
};
intmain(int argc, char* argv[]) {
if(argc <2) {
std::println("usage: nqueens n");
std::println(" 1<=n<=X");
return EXIT_FAILURE;
}
int n;
try {
n = std::stoi(argv[1]);
} catch(std::invalid_argument& x) {
std::println(stderr, "argument n is not a number.");
std::println(stderr, "entered value = {}", argv[1]);
return EXIT_FAILURE;
}
if(n <1) {
std::println(stderr, "argument n cannot be negative");
std::println(stderr, "entered value = {}", argv[1]);
return EXIT_FAILURE;
}
NQueens nq(n);
nq.enumerate();
std::println("n = {} has {} solutions", n, nq.count());
return EXIT_SUCCESS;
}