Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
111
Task/N-queens-problem/CoffeeScript/n-queens-problem.coffee
Normal file
111
Task/N-queens-problem/CoffeeScript/n-queens-problem.coffee
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
# Unlike traditional N-Queens solutions that use recursion, this
|
||||
# program attempts to more closely model the "human" algorithm.
|
||||
#
|
||||
# In this algorithm, the function keeps placing queens on the board
|
||||
# until there is no longer a safe square. If the 8th queen has been
|
||||
# placed, the solution is noted. If fewer than 8th queens have been
|
||||
# placed, then you are at a dead end. In either case, backtracking occurs.
|
||||
# The LAST queen placed on the board gets pulled, then it gets moved
|
||||
# to the next safe square. (We backtrack even after a "good" attempt in
|
||||
# order to get to a new solution.) This backtracking may repeat itself
|
||||
# several times until the original misplaced queen finally is proven to
|
||||
# be a dead end.
|
||||
#
|
||||
# Many N-Queens solutions use lazy logic (along with geometry shortcuts)
|
||||
# to determine whether a queen is under attack. In this algorithm, we
|
||||
# are more proactive, essentially updating a sieve every time we lay a
|
||||
# queen down. To make backtracking easier, the sieve uses ref-counts vs.
|
||||
# a simple safe/unsafe boolean.
|
||||
#
|
||||
# We precompute the "attack graph" up front, and then we essentially ignore
|
||||
# the geometry of the problem. This approach, while perhaps suboptimal for
|
||||
# queens, probably is more flexible for general "coexistence" problems.
|
||||
nqueens = (n) ->
|
||||
neighbors = precompute_neighbors(n)
|
||||
|
||||
board = []
|
||||
num_solutions = 0
|
||||
num_backtracks = 0
|
||||
queens = []
|
||||
pos = 0
|
||||
|
||||
for p in [0...n*n]
|
||||
board.push 0
|
||||
|
||||
attack = (pos, delta=1) ->
|
||||
for neighbor in neighbors[pos]
|
||||
board[neighbor] += delta
|
||||
|
||||
backtrack = ->
|
||||
pos = queens.pop()
|
||||
attack pos, -1 # unattack queen you just pulled
|
||||
pos += 1
|
||||
num_backtracks += 1
|
||||
|
||||
# The following loop finds all 92 solutions to
|
||||
# the 8-queens problem (for n=8).
|
||||
while true
|
||||
if pos >= n*n
|
||||
if queens.length == 0
|
||||
break
|
||||
backtrack()
|
||||
continue
|
||||
|
||||
# If a square is empty
|
||||
if board[pos] == 0
|
||||
attack pos
|
||||
queens.push pos
|
||||
if queens.length == n
|
||||
num_solutions += 1
|
||||
show_queens queens, n
|
||||
backtrack()
|
||||
pos += 1
|
||||
|
||||
console.log "#{num_solutions} solutions"
|
||||
console.log "#{num_backtracks} backtracks"
|
||||
|
||||
|
||||
precompute_neighbors = (n) ->
|
||||
# For each board position, build a list of all
|
||||
# the board positions that would be under attack if
|
||||
# you placed a queen on it. This assumes a 1d array
|
||||
# of squares.
|
||||
neighbors = []
|
||||
|
||||
find_neighbors = (pos) ->
|
||||
arr = []
|
||||
row = Math.floor pos / n
|
||||
col = pos % n
|
||||
for i in [0...n]
|
||||
if i != col
|
||||
arr.push row*n + i
|
||||
r1 = row + col - i
|
||||
r2 = row + i - col
|
||||
if 0 <= r1 and r1 < n
|
||||
arr.push r1*n + i
|
||||
if 0 <= r2 and r2 < n
|
||||
arr.push r2*n + i
|
||||
if i != row
|
||||
arr.push i*n + col
|
||||
arr
|
||||
|
||||
for pos in [0...n*n]
|
||||
neighbors.push find_neighbors(pos)
|
||||
neighbors
|
||||
|
||||
|
||||
show_queens = (queens, n) ->
|
||||
# precondition: queens is a sorted array of integers,
|
||||
# and each row is represented
|
||||
console.log "\n------"
|
||||
for q in queens
|
||||
col = q % n
|
||||
s = ''
|
||||
for c in [0...n]
|
||||
if c == col
|
||||
s += "Q "
|
||||
else
|
||||
s += "* "
|
||||
console.log s + "\n"
|
||||
|
||||
nqueens(8)
|
||||
Loading…
Add table
Add a link
Reference in a new issue