Last active
October 8, 2015 20:08
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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."); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.