Home > Software design >  N Queen using C with Dynamic 2D Array
N Queen using C with Dynamic 2D Array

Time:10-05

I have been having difficulty solving the N Queen problem, I am able to implement most of my functions, but the function that places the Queen recursively with backtracking. The placeQueens function is using a provided pseudocode that is required for the project. I had to create the array on the heap that is pointing to boardPtr, which is also required. I have a while loop condition that I have but I am not sure if it's correct. I have tried looking online for similar code but none of them were able to help me.

Here is my code:

#include <iostream>
#include "ChessBoard.h"

int main()
{

    // Create a board
    ChessBoard myBoard;

    /* Loop through board sizes from 3 to 13.
       Since 3 and 13 are invalid you should see
       board sizes 4 and 12 twice. */
    for (int i = 3; i <= 13; i  )
    {
        myBoard.setSize(i);

        /* Attempt to solve the N-Queens Problem. If the solve
           code is working it should find solutions for all
           sizes. */
        if (!myBoard.solve())
            std::cout << "Sorry, no solution was found for board size "
            << myBoard.getSize() << "." << std::endl << std::endl;
        else
        {
            std::cout << "Size " << myBoard.getSize()
                << " solution:" << std::endl;
            myBoard.displayBoard();
            std::cout << std::endl << std::endl;
        }
    }

    return 0;
}
#include "ChessBoard.h"
#include <iostream>

using namespace std;



bool ChessBoard::placeQueens( int column)
{
    
    int row = 0;
    
    if (column >= boardSize)
    {
        // The board is filled, problem is solved.
        return true;
    } 
    
    else
    {
        while (row < boardSize && column < boardSize) // unconsidered rows exist in column 
        {
            if ((canPlace(boardPtr, row, column)) == true) //[row][column] is unattacked
            {
                //Place a queen in the un - attacked square.
                boardPtr[row][column] = 'Q';

                //Do a recursive call to try and place queens in subsequent columns :
                if (!placeQueens(column   1))
                {
                    //If we’re here, placement of the last queen resulted in a dead end; no solution could be found.Remove the last queen placed.
                    boardPtr[row][column] = '*';
                    //Move to next row so search can continue in next iteration.
                    row  ;
                }
                else
                {
                    // If we’re here, recursive calls were able to place queens in all columns to the right of column, the problem is solved.
                    return true;
                }
            }

            else
            {
                //Square is attacked, move to next row.
                row  ;
            }
        }
        //All rows have been considered in column without a successful queen placement.Backtrack by returning false.
        return false;

    }
    
}

bool ChessBoard::canPlace(char** boardPtr, int row, int column) 
{
    int i, j;
    
    // Check row
    for (i = 0; i < column; i  )
        if (boardPtr[row][i] )
            return false;

    // Check upper diagonal
    for (i = row, j = column; i >= 0 && j >= 0; i--, j--)
        if (boardPtr[i][j])
            return false;

    // Check lower diagonal 
    for (i = row, j = column; j >= 0 && i < boardSize; i  , j--)
        if (boardPtr[i][j] )
            return false;
    
    return true;

}


ChessBoard::ChessBoard()
{
    boardSize = 8;
    boardPtr = nullptr;
}


ChessBoard::ChessBoard(int size)
{
    
    if (size < 4)
    {
        boardSize = 4;
    }
    else if (size > 12)
    {
        boardSize = 12;
    }
    
}

ChessBoard::~ChessBoard()
{
}


int ChessBoard::setSize(int size)
{
    delete[] boardPtr;
    //Initialize array at size 4
    if (size < 4)
    {
        boardSize = 4;
        char** chessBoard = new char* [4];

        for (int i = 0; i < 4; i  )
        {
            chessBoard[i] = new char[4];
        }
        
        // Point initialized ChessBoard to boardPtr
        boardPtr = chessBoard;

        // Fill ChessBoard with *
        for (int i = 0; i < boardSize; i  )
        {
            for (int j = 0; j < boardSize; j  )
            {
                boardPtr[i][j] = '*';
            }
        }
        
    }
    //Initialize array at size 12
    else if (size > 12)
    {
        boardSize = 12;
        char** chessBoard = new char* [12];

        for (int i = 0; i < size; i  )
        {
            chessBoard[i] = new char[12];
        }
        
        // Point initialized ChessBoard to boardPtr
        boardPtr = chessBoard;

        // Fill ChessBoard with *
        for (int i = 0; i < boardSize; i  )
        {
            for (int j = 0; j < boardSize; j  )
            {
                boardPtr[i][j] = '*';
            }
        }
        
    }
    //Initialize array at given size
    else
    {
        boardSize = size;
        char** chessBoard = new char* [size];

        for (int i = 0; i < size; i  )
        {
            chessBoard[i] = new char[size];
        }
        
        // Point initialized ChessBoard to boardPtr
        boardPtr = chessBoard;

        // Fill ChessBoard with *
        for (int i = 0; i < boardSize; i  )
        {
            for (int j = 0; j < boardSize; j  )
            {
                boardPtr[i][j] = '*';
            }
        }
        
    }
    
    return 1;
}


int ChessBoard::getSize()
{
    return boardSize;
}


bool ChessBoard::solve()
{
    int column = 0;
    if (placeQueens(column) == false) 
    {
        return false;
    }
    else
    {
        return true;
    }
    
    
}


void ChessBoard::displayBoard()
{   
    for (int i = 0; i < boardSize; i  )
    {
        for (int j = 0; j < boardSize; j  )
        {
            cout << boardPtr[i][j] << " ";
        }
        cout << endl;
    }
}
#ifndef CHESSBOARD_H
#define CHESSBOARD_H


class ChessBoard
{
private:
    char** boardPtr;
    int boardSize;
    bool placeQueens( int column);
    
    bool canPlace(char** boardPtr, int row, int col);
    
public:
    ChessBoard();
    ChessBoard(int size);
    ~ChessBoard();
    int setSize(int size);
    int getSize();
    bool solve();
    void displayBoard();


};


#endif

CodePudding user response:

Interesting task you have! I decided to implement my own code from scratch for solving N Queen problem. Actually I implemented it for any board size N, not just equal to 8.

I didn't fix bugs in your code, but instead implemented my own solution. Although it may be not the answer you want, still it would be a good thing from educational point of view. Hoping that there would be other answers later that are fixing bugs in your code, as you wished.

I made code very optimized, so it is not very simple from first side, but solves task very fast, using BackTracking, with several extra techniques of speeding it up.

After program finishes it prints to console all solutions in a nice form. Please scroll down below the code to see example of console output.

First program has some extra descriptive comments to show what's happenning in program.

Notice that I provided two codes below, first is simplified version, that is more easy to understand, so it is better from educational point of view. Second code is advanced one, it is more difficult, but solves task fast. Please look at first code if you want just to learn basics, and look at second code if you want to learn advanced techniques.

Simplified:

Try it online!

#include <iostream>
#include <vector>
#include <string>

void Output(std::vector<std::vector<bool>> & board, std::vector<std::string> & lines, bool last);

void Solve(std::vector<std::vector<bool>> & board, std::vector<std::string> & lines,
        int N, int & num_sol, int cnt = 0, int start_i = 0, int start_j = 0, int depth = 0) {
    if (cnt >= N) {
        Output(board, lines, false);
        // Increase number of solutions.
          num_sol;
        return;
    }
            
    // Traverse whole board starting from last queen
    for (int i = start_i; i < board.size();   i)
        for (int j = i == start_i ? start_j : 0; j < board[i].size();   j) {
            bool attacked = false;
            // k-loop checks if position [i][j] is being attacked
            for (int k = 0; k < (board.size() > board[i].size() ?
                    board.size() : board[i].size());   k)
                if (
                    // Is there horizontal attack
                    k < board[i].size() && k != j && board[i][k] ||
                    // Is there vertical attack
                    k < board.size() && k != i && board[k][j] ||
                    // Is there main diagonal attack
                    k < board.size() && k != i && 0 <= j - i   k &&
                        j - i   k < board[i].size() && board[k][j - i   k] ||
                    // Is there secondary diagonal attack
                    k < board.size() && k != i && 0 <= j   i - k &&
                        j   i - k < board[i].size() && board[k][j   i - k]
                ) {
                    attacked = true;
                    break;
                }
            if (attacked)
                continue;
            // Position [i][j] is not under attack, hence placing a queen
            board[i][j] = true;
            // Recursive descend to place another queen
            Solve(board, lines, N, num_sol, cnt   1, i, j   1, depth   1);
            // Backtrack, to delete previous queen
            board[i][j] = false;
        }
    if (depth == 0)
        Output(board, lines, true);
}

// Function of outputting solutions to console
void Output(std::vector<std::vector<bool>> & board, std::vector<std::string> & lines, bool last) {
    if (1) {
        if (!last) {
            for (int i = 0; i < board.size();   i) {
                for (int j = 0; j < board[i].size();   j)
                    lines[i].push_back(board[i][j] ? 'Q' : '.');
                lines[i]  = "|";
            }
        }
        if (lines.at(0).size() >= 70 || last && !lines.at(0).empty()) {
            for (int i = 0; i < lines.size();   i)
                std::cout << lines[i] << std::endl;
            for (int j = 0; j < lines.at(0).size();   j)
                std::cout << (lines.at(0)[j] == '|' ? ' ' : '-');
            std::cout << std::endl;
            lines.clear();
            lines.resize(board.size());
        }
    }
}

int main() {    
    // rows - number of rows in a board, cols - number of columns in a board
    // N - number of queens to be placed
    int const rows = 8, cols = 8, N = 8;
    // Filling with empty values board [rows][cols]
    std::vector<std::vector<bool>> board(rows, std::vector<bool>(cols));
    std::vector<std::string> lines(rows);
    // Answer, number of solutions
    int num_sol = 0;
    // Starting a backtracking
    Solve(board, lines, N, num_sol);
    // Outputting answer
    std::cout << "Number of solutions: " << num_sol << std::endl;
}

Advanced:

Try it online!

#include <iostream>
#include <string>

#define MAX(a, b) ((a) >= (b) ? (a) : (b))

enum { max_rows = 32, max_cols = 32, max_max_rows_cols = MAX(max_rows, max_cols) };

void Output(bool (& board)[max_rows][max_cols], std::string (& lines)[max_rows],
    int rows, int cols, bool last);

void Solve(bool (& board)[max_rows][max_cols], std::string (& lines)[max_rows],
        bool (& busy_cols)[max_cols], bool (& busy_diagA)[2 * max_max_rows_cols],
        bool (& busy_diagB)[2 * max_max_rows_cols],
        int rows, int cols, int N, int & num_sol, int cnt = 0, int start_i = 0, int depth = 0) {
            
    if (cnt >= N) {
        Output(board, lines, rows, cols, false);
          num_sol;
        return;
    }
    
    int const max_rows_cols = MAX(rows, cols);
    
    if (rows - start_i < N - cnt)
        return;

    int avail_cols[max_cols];
    int avail_cols_cnt = 0;
    for (int j = 0; j < cols;   j)
        if (!busy_cols[j]) {
            avail_cols[avail_cols_cnt] = j;
              avail_cols_cnt;
        }
    if (avail_cols_cnt < N - cnt)
        return;
    
    for (int i = start_i; i < rows;   i)
        for (int jj = 0; jj < avail_cols_cnt;   jj) {
            int const j = avail_cols[jj];
            
            if (busy_diagA[max_rows_cols   j - i] || busy_diagB[j   i])
                continue;
            
            board[i][j] = true;
            busy_cols[j] = true;
            busy_diagA[max_rows_cols   j - i] = true;
            busy_diagB[j   i] = true;
            
            Solve(board, lines, busy_cols, busy_diagA, busy_diagB,
                rows, cols, N, num_sol, cnt   1, i   1, depth   1);
            
            board[i][j] = false;
            busy_cols[j] = false;
            busy_diagA[max_rows_cols   j - i] = false;
            busy_diagB[j   i] = false;
        }
    if (depth == 0)
        Output(board, lines, rows, cols, true);
}

void Output(bool (& board)[max_rows][max_cols], std::string (& lines)[max_rows],
        int rows, int cols, bool last) {
    if (1) {
        if (!last) {
            for (int i = 0; i < rows;   i) {
                for (int j = 0; j < cols;   j)
                    lines[i].push_back(board[i][j] ? 'Q' : '.');
                lines[i]  = "|";
            }
        }
        if (lines[0].size() >= 70 || last && !lines[0].empty()) {
            for (int i = 0; i < rows;   i)
                std::cout << lines[i] << std::endl;
            for (int j = 0; j < lines[0].size();   j)
                std::cout << (lines[0][j] == '|' ? ' ' : '-');
            std::cout << std::endl;
            for (int i = 0; i < rows;   i)
                lines[i].clear();
        }
    }
}

int main() {    
    int const rows = 8, cols = 8, N = 8;
    bool board[max_rows][max_cols] = {};
    std::string lines[max_rows] = {};
    bool busy_cols[max_cols] = {};
    bool busy_diagA[2 * max_max_rows_cols] = {};
    bool busy_diagB[2 * max_max_rows_cols] = {};
    int num_sol = 0;
    Solve(board, lines, busy_cols, busy_diagA, busy_diagB, rows, cols, N, num_sol);
    std::cout << "Number of solutions: " << num_sol << std::endl;
}

Output:

Q.......|Q.......|Q.......|Q.......|.Q......|.Q......|.Q......|.Q......|
....Q...|.....Q..|......Q.|......Q.|...Q....|....Q...|....Q...|.....Q..|
.......Q|.......Q|...Q....|....Q...|.....Q..|......Q.|......Q.|Q.......|
.....Q..|..Q.....|.....Q..|.......Q|.......Q|Q.......|...Q....|......Q.|
..Q.....|......Q.|.......Q|.Q......|..Q.....|..Q.....|Q.......|...Q....|
......Q.|...Q....|.Q......|...Q....|Q.......|.......Q|.......Q|.......Q|
.Q......|.Q......|....Q...|.....Q..|......Q.|.....Q..|.....Q..|..Q.....|
...Q....|....Q...|..Q.....|..Q.....|....Q...|...Q....|..Q.....|....Q...|
-------- -------- -------- -------- -------- -------- -------- -------- 
.Q......|.Q......|.Q......|.Q......|..Q.....|..Q.....|..Q.....|..Q.....|
.....Q..|......Q.|......Q.|.......Q|Q.......|....Q...|....Q...|....Q...|
.......Q|..Q.....|....Q...|.....Q..|......Q.|.Q......|.Q......|......Q.|
..Q.....|.....Q..|.......Q|Q.......|....Q...|.......Q|.......Q|Q.......|
Q.......|.......Q|Q.......|..Q.....|.......Q|Q.......|.....Q..|...Q....|
...Q....|....Q...|...Q....|....Q...|.Q......|......Q.|...Q....|.Q......|
......Q.|Q.......|.....Q..|......Q.|...Q....|...Q....|......Q.|.......Q|
....Q...|...Q....|..Q.....|...Q....|.....Q..|.....Q..|Q.......|.....Q..|
-------- -------- -------- -------- -------- -------- -------- -------- 
..Q.....|..Q.....|..Q.....|..Q.....|..Q.....|..Q.....|..Q.....|..Q.....|
....Q...|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|
.......Q|.Q......|.Q......|.Q......|...Q....|...Q....|.......Q|.......Q|
...Q....|....Q...|......Q.|......Q.|Q.......|.Q......|Q.......|Q.......|
Q.......|.......Q|Q.......|....Q...|.......Q|.......Q|...Q....|....Q...|
......Q.|Q.......|...Q....|Q.......|....Q...|....Q...|......Q.|......Q.|
.Q......|......Q.|.......Q|.......Q|......Q.|......Q.|....Q...|.Q......|
.....Q..|...Q....|....Q...|...Q....|.Q......|Q.......|.Q......|...Q....|
-------- -------- -------- -------- -------- -------- -------- -------- 
..Q.....|..Q.....|..Q.....|..Q.....|...Q....|...Q....|...Q....|...Q....|
.....Q..|......Q.|......Q.|.......Q|Q.......|Q.......|.Q......|.Q......|
.......Q|.Q......|.Q......|...Q....|....Q...|....Q...|....Q...|......Q.|
.Q......|.......Q|.......Q|......Q.|.......Q|.......Q|.......Q|..Q.....|
...Q....|....Q...|.....Q..|Q.......|.Q......|.....Q..|.....Q..|.....Q..|
Q.......|Q.......|...Q....|.....Q..|......Q.|..Q.....|Q.......|.......Q|
......Q.|...Q....|Q.......|.Q......|..Q.....|......Q.|..Q.....|Q.......|
....Q...|.....Q..|....Q...|....Q...|.....Q..|.Q......|......Q.|....Q...|
-------- -------- -------- -------- -------- -------- -------- -------- 
...Q....|...Q....|...Q....|...Q....|...Q....|...Q....|...Q....|...Q....|
.Q......|.Q......|.Q......|.Q......|.....Q..|.....Q..|.....Q..|......Q.|
......Q.|......Q.|.......Q|.......Q|Q.......|.......Q|.......Q|Q.......|
..Q.....|....Q...|....Q...|.....Q..|....Q...|.Q......|..Q.....|.......Q|
.....Q..|Q.......|......Q.|Q.......|.Q......|......Q.|Q.......|....Q...|
.......Q|.......Q|Q.......|..Q.....|.......Q|Q.......|......Q.|.Q......|
....Q...|.....Q..|..Q.....|....Q...|..Q.....|..Q.....|....Q...|.....Q..|
Q.......|..Q.....|.....Q..|......Q.|......Q.|....Q...|.Q......|..Q.....|
-------- -------- -------- -------- -------- -------- -------- -------- 
...Q....|...Q....|...Q....|...Q....|...Q....|...Q....|....Q...|....Q...|
......Q.|......Q.|......Q.|.......Q|.......Q|.......Q|Q.......|Q.......|
..Q.....|....Q...|....Q...|Q.......|Q.......|....Q...|...Q....|.......Q|
.......Q|.Q......|..Q.....|..Q.....|....Q...|..Q.....|.....Q..|...Q....|
.Q......|.....Q..|Q.......|.....Q..|......Q.|Q.......|.......Q|.Q......|
....Q...|Q.......|.....Q..|.Q......|.Q......|......Q.|.Q......|......Q.|
Q.......|..Q.....|.......Q|......Q.|.....Q..|.Q......|......Q.|..Q.....|
.....Q..|.......Q|.Q......|....Q...|..Q.....|.....Q..|..Q.....|.....Q..|
-------- -------- -------- -------- -------- -------- -------- -------- 
....Q...|....Q...|....Q...|....Q...|....Q...|....Q...|....Q...|....Q...|
Q.......|.Q......|.Q......|.Q......|.Q......|..Q.....|..Q.....|..Q.....|
.......Q|...Q....|...Q....|.....Q..|.......Q|Q.......|Q.......|.......Q|
.....Q..|.....Q..|......Q.|Q.......|Q.......|.....Q..|......Q.|...Q....|
..Q.....|.......Q|..Q.....|......Q.|...Q....|.......Q|.Q......|......Q.|
......Q.|..Q.....|.......Q|...Q....|......Q.|.Q......|.......Q|Q.......|
.Q......|Q.......|.....Q..|.......Q|..Q.....|...Q....|.....Q..|.....Q..|
...Q....|......Q.|Q.......|..Q.....|.....Q..|......Q.|...Q....|.Q......|
-------- -------- -------- -------- -------- -------- -------- -------- 
....Q...|....Q...|....Q...|....Q...|....Q...|....Q...|....Q...|....Q...|
......Q.|......Q.|......Q.|......Q.|......Q.|......Q.|.......Q|.......Q|
Q.......|Q.......|.Q......|.Q......|.Q......|...Q....|...Q....|...Q....|
..Q.....|...Q....|...Q....|.....Q..|.....Q..|Q.......|Q.......|Q.......|
.......Q|.Q......|.......Q|..Q.....|..Q.....|..Q.....|..Q.....|......Q.|
.....Q..|.......Q|Q.......|Q.......|Q.......|.......Q|.....Q..|.Q......|
...Q....|.....Q..|..Q.....|...Q....|.......Q|.....Q..|.Q......|.....Q..|
.Q......|..Q.....|.....Q..|.......Q|...Q....|.Q......|......Q.|..Q.....|
-------- -------- -------- -------- -------- -------- -------- -------- 
.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|
Q.......|.Q......|.Q......|..Q.....|..Q.....|..Q.....|..Q.....|..Q.....|
....Q...|......Q.|......Q.|Q.......|Q.......|Q.......|....Q...|....Q...|
.Q......|Q.......|Q.......|......Q.|.......Q|.......Q|......Q.|.......Q|
.......Q|..Q.....|...Q....|....Q...|...Q....|....Q...|Q.......|Q.......|
..Q.....|....Q...|.......Q|.......Q|.Q......|.Q......|...Q....|...Q....|
......Q.|.......Q|....Q...|.Q......|......Q.|...Q....|.Q......|.Q......|
...Q....|...Q....|..Q.....|...Q....|....Q...|......Q.|.......Q|......Q.|
-------- -------- -------- -------- -------- -------- -------- -------- 
.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|.....Q..|
..Q.....|..Q.....|..Q.....|...Q....|...Q....|...Q....|...Q....|.......Q|
......Q.|......Q.|......Q.|Q.......|.Q......|......Q.|......Q.|.Q......|
.Q......|.Q......|...Q....|....Q...|.......Q|Q.......|Q.......|...Q....|
...Q....|.......Q|Q.......|.......Q|....Q...|..Q.....|.......Q|Q.......|
.......Q|....Q...|.......Q|.Q......|......Q.|....Q...|.Q......|......Q.|
Q.......|Q.......|.Q......|......Q.|Q.......|.Q......|....Q...|....Q...|
....Q...|...Q....|....Q...|..Q.....|..Q.....|.......Q|..Q.....|..Q.....|
-------- -------- -------- -------- -------- -------- -------- -------- 
......Q.|......Q.|......Q.|......Q.|......Q.|......Q.|......Q.|......Q.|
Q.......|.Q......|.Q......|..Q.....|..Q.....|...Q....|...Q....|....Q...|
..Q.....|...Q....|.....Q..|Q.......|.......Q|.Q......|.Q......|..Q.....|
.......Q|Q.......|..Q.....|.....Q..|.Q......|....Q...|.......Q|Q.......|
.....Q..|.......Q|Q.......|.......Q|....Q...|.......Q|.....Q..|.....Q..|
...Q....|....Q...|...Q....|....Q...|Q.......|Q.......|Q.......|.......Q|
.Q......|..Q.....|.......Q|.Q......|.....Q..|..Q.....|..Q.....|.Q......|
....Q...|.....Q..|....Q...|...Q....|...Q....|.....Q..|....Q...|...Q....|
-------- -------- -------- -------- -------- -------- -------- -------- 
.......Q|.......Q|.......Q|.......Q|
.Q......|.Q......|..Q.....|...Q....|
...Q....|....Q...|Q.......|Q.......|
Q.......|..Q.....|.....Q..|..Q.....|
......Q.|Q.......|.Q......|.....Q..|
....Q...|......Q.|....Q...|.Q......|
..Q.....|...Q....|......Q.|......Q.|
.....Q..|.....Q..|...Q....|....Q...|
-------- -------- -------- -------- 
Number of solutions: 92

CodePudding user response:

There are several issues, starting from the multiple memory leaks (see e.g. the empty destructor or the delete[] boardPtr; at the beginning of ChessBoard::setSize), but what prevents the program to solve the problem is this:

bool ChessBoard::canPlace(char** boardPtr, int row, int column) 
{
    int i, j;
    
    // Check row
    for (i = 0; i < column; i  )
        if (boardPtr[row][i] )
        //  ^^^^^^^^^^^^^^^^    
            return false;
    // ...
}

That condition and the following ones should be boardPtr[row][i] == 'Q', because, as written, it just check if the char is not 0, while an empty spot is indicated by a . in this program.

  • Related