|
| 1 | +import QueenPosition from './QueenPosition'; |
| 2 | + |
| 3 | +/** |
| 4 | + * @param {QueenPosition[]} queensPositions |
| 5 | + * @param {number} rowIndex |
| 6 | + * @param {number} columnIndex |
| 7 | + * @return {boolean} |
| 8 | + */ |
| 9 | +function isSafe(queensPositions, rowIndex, columnIndex) { |
| 10 | + // New position to which the Queen is going to be placed. |
| 11 | + const newQueenPosition = new QueenPosition(rowIndex, columnIndex); |
| 12 | + |
| 13 | + // Check if new queen position conflicts with any other queens. |
| 14 | + for (let queenIndex = 0; queenIndex < queensPositions.length; queenIndex += 1) { |
| 15 | + const currentQueenPosition = queensPositions[queenIndex]; |
| 16 | + |
| 17 | + if ( |
| 18 | + // Check if queen has been already placed. |
| 19 | + currentQueenPosition && |
| 20 | + ( |
| 21 | + // Check if there are any queen on the same column. |
| 22 | + newQueenPosition.columnIndex === currentQueenPosition.columnIndex || |
| 23 | + // Check if there are any queen on the same row. |
| 24 | + newQueenPosition.rowIndex === currentQueenPosition.rowIndex || |
| 25 | + // Check if there are any queen on the same left diagonal. |
| 26 | + newQueenPosition.leftDiagonal === currentQueenPosition.leftDiagonal || |
| 27 | + // Check if there are any queen on the same right diagonal. |
| 28 | + newQueenPosition.rightDiagonal === currentQueenPosition.rightDiagonal |
| 29 | + ) |
| 30 | + ) { |
| 31 | + // Can't place queen into current position since there are other queens that |
| 32 | + // are threatening it. |
| 33 | + return false; |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + // Looks like we're safe. |
| 38 | + return true; |
| 39 | +} |
| 40 | + |
| 41 | +/** |
| 42 | + * @param {QueenPosition[][]} solutions |
| 43 | + * @param {QueenPosition[]} previousQueensPositions |
| 44 | + * @param {number} queensCount |
| 45 | + * @param {number} rowIndex |
| 46 | + * @return {boolean} |
| 47 | + */ |
| 48 | +function nQueensRecursive(solutions, previousQueensPositions, queensCount, rowIndex) { |
| 49 | + // Clone positions array. |
| 50 | + const queensPositions = [...previousQueensPositions].map((queenPosition) => { |
| 51 | + return !queenPosition ? queenPosition : new QueenPosition( |
| 52 | + queenPosition.rowIndex, |
| 53 | + queenPosition.columnIndex, |
| 54 | + ); |
| 55 | + }); |
| 56 | + |
| 57 | + if (rowIndex === queensCount) { |
| 58 | + // We've successfully reached the end of the board. |
| 59 | + // Store solution to the list of solutions. |
| 60 | + solutions.push(queensPositions); |
| 61 | + |
| 62 | + // Solution found. |
| 63 | + return true; |
| 64 | + } |
| 65 | + |
| 66 | + // Let's try to put queen at row rowIndex into its safe column position. |
| 67 | + for (let columnIndex = 0; columnIndex < queensCount; columnIndex += 1) { |
| 68 | + if (isSafe(queensPositions, rowIndex, columnIndex)) { |
| 69 | + // Place current queen to its current position. |
| 70 | + queensPositions[rowIndex] = new QueenPosition(rowIndex, columnIndex); |
| 71 | + |
| 72 | + // Try to place all other queens as well. |
| 73 | + nQueensRecursive(solutions, queensPositions, queensCount, rowIndex + 1); |
| 74 | + |
| 75 | + // Remove the queen from the row to avoid isSafe() returning false. |
| 76 | + queensPositions[rowIndex] = null; |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + return false; |
| 81 | +} |
| 82 | + |
| 83 | + |
| 84 | +/** |
| 85 | + * @param {number} queensCount |
| 86 | + * @return {QueenPosition[][]} |
| 87 | + */ |
| 88 | +export default function nQueens(queensCount) { |
| 89 | + // Init NxN chessboard with zeros. |
| 90 | + // const chessboard = Array(queensCount).fill(null).map(() => Array(queensCount).fill(0)); |
| 91 | + |
| 92 | + // This array will hold positions or coordinates of each of |
| 93 | + // N queens in form of [rowIndex, columnIndex]. |
| 94 | + const queensPositions = Array(queensCount).fill(null); |
| 95 | + |
| 96 | + /** @var {QueenPosition[][]} solutions */ |
| 97 | + const solutions = []; |
| 98 | + |
| 99 | + // Solve problem recursively. |
| 100 | + nQueensRecursive(solutions, queensPositions, queensCount, 0); |
| 101 | + |
| 102 | + return solutions; |
| 103 | +} |
0 commit comments