I wrote a kind of N-Queens algorithm, handling only the vertical and horizontal threats detection. Thus, it's rather a N-Towers solutions finder.
To do this, I use recursion. It's a well-known algorithm. For each square of the chessboard, I place a tower. For each placed tower, I try to place another tower (this is the recursive call). If there is not any remaining tower to place, it means the program has found a solution and the recursive level has to return. If all the chessboard has been crossed with remaining tower(s) to place, it means the program didn't find a solution and the recursive level has to return.
My recursive function has two parameters : the number of towers which have to be placed and the chessboard (an array of array of string ; the string equals "T" to indicate a tower has been placed in this chessboard's square and "-" to indicate the square is empty).
The problem
My algorithm seems to find all the solutions and displays them as chessboards, using the "-" (and, if it worked well, "T") notation. This notation is explained above.
However, even if the number of solutions seems to be correct, the displayed solutions/chessboards contain only "-".
I think I don't pass my array of array (ie. : the chessboard) correctly in my recursive call.
Illustration of this problem
For 2 towers and a chessboard of 2*2 squares, two solutions are found and it's normal. But there are only "-" and no "T" appears... That's the problem. Indeed :
--
--
Code : focus on my recursive function
/**
* RECURSIVE FUNCTION. If there are still towers to place, this function tries to place them. If not, it means a
* solution has been found : it's stored in an array (external to this function).
* If this function can't place a tower, nothing happens.
* Else, it places it and makes the recursive call.
* Each recursion level does this for each next (to the placed tower) chessboard's squares.
* @param number_of_left_towers how many remaining towers to place there are (if 0, it means a solution has been
* found)
* @param array_array_chessboard the chessboard
* @returns {Number} the return is not important
*/
function placeTower(number_of_left_towers, array_array_chessboard) {
if (number_of_left_towers == 0) {
return solutions.push(array_array_chessboard);
}
for (var current_x = 0; current_x < number_of_lines; current_x++) {
for (var current_y = 0; current_y < number_of_columns; current_y++) {
if (array_array_chessboard[current_x][current_y] == "-" && canBePlaced(array_array_chessboard, current_x, current_y)) {
array_array_chessboard[current_x][current_y] = "T";
placeTower(number_of_left_towers - 1, array_array_chessboard);
array_array_chessboard[current_x][current_y] = "-";
}
}
}
}
Code : JSFiddle with all the source
https://jsfiddle.net/btcj6uzp/
You can also find the same code below :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Recursive algorithm of the N-Towers</title>
</head>
<body>
<script type="text/javascript">
/**
* Finds all the solutions to the N-Towers algorithm.
*
* @param number_of_towers number of towers to try to place in the chessboard
* @param number_of_lines chessboard's ones
* @param number_of_columns chessboard's ones
* @returns {nTowersSolutions} array containing all the solutions
*/
function nTowersSolutions(number_of_towers, number_of_lines, number_of_columns) {
/*
NB
"T" = "Tower" = presence of a tower in this square of the chessboard
"-" = "nothing" = no tower in this square of the chessboard
(used for both solutions displaying and finding)
*/
var solutions = [];
var array_array_chessboard = []; // Represents the chessboard
for(var i = 0; i < number_of_lines; i++) {
array_array_chessboard[i] = new Array(number_of_columns);
for(var j = 0; j < number_of_columns; j++) {
array_array_chessboard[i][j] = "-"; // We initialize the chessboard with "-"
}
}
/**
* Uses HTML to display the found solutions, in the Web page
*/
this.displaySolutions = function() {
var body = document.body;
solutions.forEach((array_array_chessboard) => {
array_array_chessboard.forEach(function(array_chessboard) {
array_chessboard.forEach((square) => {
body.innerHTML += square; // New cell
});
body.innerHTML += "<br />"; // New line
});
body.innerHTML += "<br /><br />"; // New solution
});
};
/**
* RECURSIVE FUNCTION. If there are still towers to place, this function tries to place them. If not, it means a
* solution has been found : it's stored in an array (external to this function).
* If this function can't place a tower, nothing happens.
* Else, it places it and makes the recursive call.
* Each recursion level does this for each next (to the placed tower) chessboard's squares.
* @param number_of_left_towers how many remaining towers to place there are (if 0, it means a solution has been
* found)
* @param array_array_chessboard the chessboard
* @returns {Number} the return is not important
*/
function placeTower(number_of_left_towers, array_array_chessboard) {
if (number_of_left_towers == 0) {
return solutions.push(array_array_chessboard);
}
for (var current_x = 0; current_x < number_of_lines; current_x++) {
for (var current_y = 0; current_y < number_of_columns; current_y++) {
if (array_array_chessboard[current_x][current_y] == "-" && canBePlaced(array_array_chessboard, current_x, current_y)) {
array_array_chessboard[current_x][current_y] = "T";
placeTower(number_of_left_towers - 1, array_array_chessboard);
array_array_chessboard[current_x][current_y] = "-";
}
}
}
}
/**
* Can this tower be placed ?
* @param array_array_chessboard
* @param new_x
* @param new_y
* @returns {boolean}
*/
function canBePlaced(array_array_chessboard, new_x, new_y) {
for(var i = 0; i < array_array_chessboard.length; i++) {
for(var z = 0; z < array_array_chessboard[i].length; z++) {
if(array_array_chessboard[i][z] == "T"
&& (
new_x == z || new_y == i // Horizontal and vertical checks
)
) {
return false;
}
}
}
return true;
}
placeTower(number_of_towers, array_array_chessboard);
return this;
}
// <!-- CHANGE THESE PARAMETERS' VALUE TO TEST -->
nTowersSolutions(2, 2, 2).displaySolutions();
</script>
</body>
</html>