-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathmain.cpp
231 lines (204 loc) · 8.11 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#include <iostream>
#include <algorithm>
#include <vector>
#include <thread>
#include <cstdlib>
#include <chrono>
using namespace std;
/*
backtracking is a refinement of the brute force (exhaustive enumeration), in which
a good part can be eliminated without being explicitly examined.
It can be used in problems in which the solution can be defined from a sequence of
decisions, and problems in which can be modeled by a tree that represents all possible
sequence of decisions.
Backtracking finds solutions by trying partial solutions and then abandoning them if they
are not suitable.
it's a "brute force" algorithm technique (tries all paths) that is often implemented recursively
Applications:
producing all permutations of a set of values
parsing languages
games: anagrams, crosswords, word jumbles, 8-queens problems
combinatorics and logic programming
escaping from a maze
General pseudo-code:
explore(decisions):
if there are no more decisions:
stop
else
we make one decision and the rest is done by recursion
for each available choice c for this decision
choose c
explore the remaining choices that could follow c
UN-choose c (backtrack)
...
...
...
...
*/
/*
N queens problems:
The N Queen is the problem of placing N chess queens on an N x N
chessboard so that no two queens attack each other.
8 queens problems:
place 8 queens on a chess board such that no queen can attack another queen.
The queens move horizontally, vertically and diagonally
(both main diagonal and secondary diagonal)
For 4 queens, one possible solution would be:
-> 0 1 0 0
-> 0 0 0 1
-> 1 0 0 0
-> 0 0 1 0
OBS: each row has one queen, which means that in a working solution, exactly 1 queen
must appear in each row and in each column.
pseudo-code get from geeks for geeks website:
1) Start in the leftmost column
2) If all queens are placed
return true
3) Try all rows in the current column.
Do following for every tried row.
a) If the queen can be placed safely in this row then mark this [row,
column] as part of the solution and recursively check if placing queen here
leads to a solution.
b) If placing the queen in [row, column] leads to a solution then return
true.
c) If placing queen doesn't lead to a solution then UN-mark this [row,
column] (Backtrack) and go to step (a) to try other rows.
3) If all rows have been tried and nothing worked, return false to trigger
backtracking (there's no solution since if the queen couldn't be placed in this row
since in the N queen problems in a feasible solution all cols have exactly one queen,
then it's not possible to have a good solution for this board).
*/
string& operator * (string& s, int number) {
char c = s[0];
for (int i = 0; i < number; i++) {
s+=c;
}
return s;
}
string& operator *= (string& s, int number) {
return s * number;
}
class ChessBoard {
private:
vector<vector<int> > board;
int boardSize;
int feasibleSolutions = 0;
public:
ChessBoard(int boardSize) : boardSize(boardSize) {
// Creating a chess board of size boardSize of rows and cols
this->board.assign(boardSize, vector<int>(boardSize, 0));
}
// Updating boardSize
void setBoardSize(int boardSize) {
this->boardSize = 0;
board.assign(boardSize, vector<int>(boardSize, 0));
}
int getBoardSize() const {
return this->boardSize;
}
int getFeasibleSolutions() const {
return this->feasibleSolutions;
}
// Checking if the row and col position passed is safe
bool isSafe(int row, int col) {
// since I'm placing the queen in each of the cols starting from 0
// then it's guaranteed that the current col is safe, so we need only to
// check the row and the diagonals, since there's none queen from col to the right
// we can only check from 0 to the number of cols in which queens are placed
// Checking horizontal (row)
for (int i = 0; i < col; i++) {
if(this->board[row][i] == 1) // there's already one queen here
return false; // it's not safe then
}
// checking first diagonal (left since to the right there's any queen placed yet)
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if(this->board[i][j] == 1)
return false; // it's not safe
}
// checking secondary diagonal (left since to the right there's any queen placed yet)
for (int i = row, j = col; i < this->boardSize && j >= 0; i++, j--) {
if(this->board[i][j] == 1)
return false; // it's not safe
}
// If it got here, then any from the queens already placed
// was found on the board
return true;
}
// place queen at the specified position
void placeQueen(int row, int col) {
this->board[row][col] = 1;
}
// remove queen from the specified position
void removeQueen(int row, int col) {
this->board[row][col] = 0;
}
// function to solve the n queens problems where those queens must be
// placed on the board such that any of them attack each other
// if it finds a solution the function should stop
void solveQueensProblem() {
helperSolveQueensProblem(0);
}
// solving N queens problem using the column reference
void helperSolveQueensProblem(int column) {
// if the column is greater of equal to the size of the board
// it means that I've already placed all queen in each column
if(column >= this->boardSize) {
// return true; // if the program only need to check if there's solution or not
feasibleSolutions++;
cout << feasibleSolutions << "th solution:\n";
// print solution found
showBoard();
system("pause");
} else {
// There's must have one queen placed in this column
// check each possible place in this column
for (int row = 0; row < this->boardSize; row++) {
// if this row and column is safe to place a queen
if(this->isSafe(row, column)) {
// place a queen here
this->placeQueen(row, column);
// showing algorithm placing queen
this->showBoard();
this_thread::sleep_for(chrono::milliseconds(1500));
system("cls");
// explore other possible solution
// if(this->helperSolveQueensProblem(column + 1)) // if it return true from here, then stop it too
this->helperSolveQueensProblem(column + 1);
// displace the queen from this current position
// on the board (backtracking)
this->removeQueen(row, column);
}
}
}
// return false; // if the queen cannot be placed in any row in this column, then return false since there's no solution
}
void showBoard() {
cout << " N Queens problem:\n";
string line = "=";
int decrease;
if(this->boardSize % 2 == 0)
decrease = 2;
else
decrease = 1;
line*=this->boardSize + (this->boardSize / 2) * 2 - decrease;
cout << " " << line << endl;
for (int i = 0; i < this->boardSize; i++) {
for(int j = 0; j < this->boardSize; j++) {
cout << " ";
if(this->board[i][j])
cout << "Q";
else
cout << "-";
}
cout << "\n";
}
cout << " " << line << endl;
}
};
int main()
{
ChessBoard queens(10);
queens.solveQueensProblem();
cout << "There were: " << queens.getFeasibleSolutions() << endl;
return 0;
}