Skip to content

Instantly share code, notes, and snippets.

@weijarz
Created October 28, 2014 13:35
Show Gist options
  • Save weijarz/ded24f0b6949b8f502f8 to your computer and use it in GitHub Desktop.
Save weijarz/ded24f0b6949b8f502f8 to your computer and use it in GitHub Desktop.
eight_queen.py
#!/usr/bin/env python
import sys, itertools
__all__=[]
NUM_QUEENS = 8
MAX = NUM_QUEENS * NUM_QUEENS
# Each position (i.e. square) on the chess board is assigned a number
# (0..63). non_intersecting_table maps each position A to a set
# containing all the positions that are *not* attacked by the position
# A.
intersecting_table = {}
non_intersecting_table = {}
# Utility functions for drawing chess board
def display(board):
"Draw an ascii board showing positions of queens"
assert len(board)==MAX
it = iter(board)
for row in range(NUM_QUEENS):
for col in range(NUM_QUEENS):
print(next(it), end='')
print('\n')
def make_board(l):
"Construct a board (list of 64 items)"
board = [x in l and '*' or '_' for x in range(MAX)]
return board
# Construct the non-intersecting table
for pos in range(MAX):
intersecting_table[pos] = []
for row in range(NUM_QUEENS):
covered = range(row * NUM_QUEENS, (row+1) * NUM_QUEENS)
for pos in covered:
intersecting_table[pos] += covered
for col in range(NUM_QUEENS):
covered = [col + zerorow for zerorow in range(0, MAX, NUM_QUEENS)]
for pos in covered:
intersecting_table[pos] += covered
for diag in range(NUM_QUEENS):
l_dist = diag + 1
r_dist = NUM_QUEENS - diag
covered = [diag + (NUM_QUEENS-1) * x for x in range(l_dist)]
for pos in covered:
intersecting_table[pos] += covered
covered = [diag + (NUM_QUEENS+1) * x for x in range(r_dist)]
for pos in covered:
intersecting_table[pos] += covered
for diag in range(MAX - NUM_QUEENS, MAX):
l_dist = (diag % NUM_QUEENS) + 1
r_dist = NUM_QUEENS - l_dist + 1
covered = [diag - (NUM_QUEENS + 1) * x for x in range(l_dist)]
for pos in covered:
intersecting_table[pos] += covered
covered = [diag - (NUM_QUEENS - 1) * x for x in range(r_dist)]
for pos in covered:
intersecting_table[pos] += covered
universal_set = set(range(MAX))
for k in intersecting_table:
non_intersecting_table[k] = universal_set - set(intersecting_table[k])
# Once the non_intersecting_table is ready, the 8 queens problem is
# solved completely by the following method. Start by placing the
# first queen in position 0. Every time we place a queen, we compute
# the current non-intersecting positions by computing union of
# non-intersecting positions of all queens currently on the
# board. This allows us to place the next queen.
def get_positions(remaining=None, depth=0):
m = depth * NUM_QUEENS + NUM_QUEENS
if remaining is not None:
rowzone = [x for x in remaining if x < m]
else:
rowzone = [x for x in range(NUM_QUEENS)]
for x in rowzone:
if depth==NUM_QUEENS-1:
yield (x,)
else:
if remaining is None:
n = non_intersecting_table[x]
else:
n = remaining & non_intersecting_table[x]
for p in get_positions(n, depth + 1):
yield (x,) + p
return
rl = [x for x in get_positions()]
for i,p in enumerate(rl):
print('=' * NUM_QUEENS * 2, "#%s" % (i+1))
display(make_board(p))
print('%s solutions found for %s queens' % (i+1, NUM_QUEENS))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment