Skip to content

Instantly share code, notes, and snippets.

@briangordon
Last active October 8, 2015 20:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save briangordon/3382806 to your computer and use it in GitHub Desktop.
Save briangordon/3382806 to your computer and use it in GitHub Desktop.
JavaScript n-queens solution generator. This was written for an hour-long contest, so it's super sloppy.
var n = 40;
// Each row has exactly one queen. We have to determine which column to place each queen in.
var board = [];
function initBoard() {
// Put one queen in each row
board = [];
for(var row = 0; row < n; row++) {
board[row] = [];
board[row][Math.floor(Math.random()*(n))] = true;
}
}
function countConflicts(row, col) {
var conflicts = 0;
// go up
if(row > 0) {
var r = row;
while(r > 0) {
r--;
if(board[r][col]) conflicts++;
}
}
// go down
if(row < n-1) {
var r = row;
while(r < n-1) {
r++;
if(board[r][col]) conflicts++;
}
}
// go right
if(col > 0) {
var c = col;
while(c > 0) {
c--;
if(board[row][c]) conflicts++;
}
}
// go left
if(col < n-1) {
var c = col;
while(c < n-1) {
c++;
if(board[row][c]) conflicts++;
}
}
// go up-right
if(row > 0 && col < n-1) {
var r = row;
var c = col;
while(r > 0 && c < n-1) {
r--; c++;
if(board[r][c]) conflicts++;
}
}
// go down-left
if(row < n-1 && col > 0) {
var r = row;
var c = col;
while(r < n-1 && c < 0) {
r++; c--;
if(board[r][c]) conflicts++;
}
}
// go down-right
if(row < n-1 && col < n-1) {
var r = row;
var c = col;
while(r < n-1 && c < n-1) {
r++; c++;
if(board[r][c]) conflicts++;
}
}
// go up-left
if(row > 0 && col > 0) {
var r = row;
var c = col;
while(r > 0 && c > 0) {
r--; c--;
if(board[r][c]) conflicts++;
}
}
return conflicts;
}
function oneConflict(row, col) {
// go up
if(row > 0) {
var r = row;
while(r > 0) {
r--;
if(board[r][col]) return true;
}
}
// go down
if(row < n-1) {
var r = row;
while(r < n-1) {
r++;
if(board[r][col]) return true;
}
}
// go right
if(col > 0) {
var c = col;
while(c > 0) {
c--;
if(board[row][c]) return true;
}
}
// go left
if(col < n-1) {
var c = col;
while(c < n-1) {
c++;
if(board[row][c]) return true;
}
}
// go up-right
if(row > 0 && col < n-1) {
var r = row;
var c = col;
while(r > 0 && c < n-1) {
r--; c++;
if(board[r][c]) return true;
}
}
// go down-left
if(row < n-1 && col > 0) {
var r = row;
var c = col;
while(r < n-1 && c < 0) {
r++; c--;
if(board[r][c]) return true;
}
}
// go down-right
if(row < n-1 && col < n-1) {
var r = row;
var c = col;
while(r < n-1 && c < n-1) {
r++; c++;
if(board[r][c]) return true;
}
}
// go up-left
if(row > 0 && col > 0) {
var r = row;
var c = col;
while(r > 0 && c > 0) {
r--; c--;
if(board[r][c]) return true;
}
}
return false;
}
function isConflicted(row) {
// Is the queen in this row conflicted?
var col = scan(row);
//return countConflicts(row, col) > 0;
return oneConflict(row, col) > 0;
}
function scan(row) {
// Find the position of the queen in this row
for(var col = 0; col < n; col++) {
if(board[row][col]) {
return col;
}
}
console.log("no queen?");
}
while(true) {
// Try again from a different starting configuration
initBoard();
var counter = 0;
while(counter < 10000) {
counter++;
// Get a list of all conflicted rows
var allConflicted = [];
for(var row = 0; row < n; row++) {
if(isConflicted(row)) {
allConflicted.push(row);
}
}
if(allConflicted.length === 0) {
console.log("DONE!");
var str = "";
for(var i=0; i<n; i++) {
for(var j=0; j<n; j++) {
// console.log(board[i][j]);
str += board[i][j] != undefined ? "Q " : ". ";
}
str += "\n";
}
console.log(str);
process.exit();
}
// Pick a random conflicted row
var number = allConflicted.length;
var index = Math.floor(Math.random()*(number));
var conflicted = allConflicted[index];
var conflictedCol = scan(conflicted);
// Remove the queen in that row
board[conflicted][conflictedCol] = undefined;
// Find all columns with the fewest conflicts
var minQueens = 99999999999;
var minCols = []
for (var col = 0; col < n; col++) {
var count = countConflicts(conflicted,col);
if(count < minQueens) {
minQueens = count;
minCols = [col];
} else if(count === minQueens) {
minCols.push(col);
}
}
// Pick a random column out of the minimum-conflict columns
var number2 = minCols.length;
var index2 = Math.floor(Math.random()*(number2));
var destination = minCols[index2];
// Move the queen from conflicted,conflictedCol to conflicted,destination
board[conflicted][destination] = true;
}
console.log("Local maximum? Starting over from another random board.");
}
@briangordon
Copy link
Author

It's sloppy because I wrote this in an hour to score first place in a programming contest at work. It generates a 30-queens solution in under a second on my work machine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment