Eight Queens Puzzle by Magnus Lie Hetland

Bengt Richter bokr at oz.net
Fri Aug 15 16:32:05 EDT 2003


On Fri, 15 Aug 2003 13:13:43 +0200, Borcis <borcis at users.ch> wrote:

>Grant Edwards wrote:
>
>>>BTW, my version got all 92 solutions in < 155ms on a 300mhz P2 without
>>>attempting to optimize ;-) (just the call to doqueens that is, not including
>>>import time).
>> 
>> 
>> Someday I want to modify it to keep a list of solutions and eliminating all
>> the ones that are mirror images or rotations.
>
>This will give you 12 solutions, one of which possesses an internal
>2-fold symmetry, so 92 = 11*8 + 1*8/2.
>
This version discovers the 12 unique ones: (not too tested, and probably has some redundancies ;-)
This one does use generators ;-)

====< queens.py >========================================================
""" bitmap of board
  00 01 02 03 04 05 06 07
  08 09 10 11 12 13 14 15
  16 17 18 19 20 21 22 23
  24 25 26 27 28 29 30 31
  32 33 34 35 36 37 38 39
  40 41 42 43 44 45 46 47
  48 49 50 51 52 53 54 55
  56 57 58 59 60 61 62 63
"""
threatfrom = {}
queenat = {}
for row in xrange(8):
    for col in xrange(8):
        queenat[row,col] = 1L<<(8*row+col)
        threat = 0L
        for r in xrange(8):
            for c in xrange(8):
                if r==row or c==col or abs(r-row)==abs(c-col):
                    threat |= 1L<<(8*r+c)
        threatfrom[row,col] = threat


def printsol(sol):
    for row in range(8):
        for col in range(8): print '+Q'[(sol>>(row*8+col))&1],
        print
        
def solok(sol):
    """check that each queen doesn't threaten the rest"""
    for row in range(8):
        for col in range(8):
            if (sol>>(row*8+col))&1:
                q = 1L<<(row*8+col)
                if (sol^q) & threatfrom[row,col]: return False
    return True

def doqueens():
    solutions = []
    def tryplace(board, row, cols):
        for col in cols:
            if (board&threatfrom[row,col]): continue
            qboard = board|queenat[row,col]
            if row<7:
                xcols = cols[:]
                xcols.remove(col)
                tryplace(qboard, row+1, xcols)
            else:
                solutions.append(qboard)
    tryplace(0L, 0, range(8))
    return solutions

rotates = (
    ((lambda r,c:(c,   7-r )), 'R+90'), # old->ccw->new
    ((lambda r,c:(7-c, r   )), 'R-90'), # old->cw->new
    ((lambda r,c:(7-r, 7-c )), 'R+-180'),
)
flips = (
    ((lambda r,c:(r,   7-c )), 'E-W'),
    ((lambda r,c:(c,   r   )), 'NE-SW'),
)

def combo():
    for flip in flips: yield flip
    for rot in rotates: yield rot
    for flip in flips:
        for rot in rotates:
            label = '%s, %s'%(flip[1],rot[1])
            def f(r,c,flip=flip[0], rot=rot[0]): return rot(*flip(r,c))
            yield f, label

def transforms(sol):
    for fliprot, label in combo():
        board =0L
        for r in range(8):
            for c in range(8):
                if sol&queenat[r,c]:
                    board |= queenat[fliprot(r,c)]
        yield board, label
     
if __name__ == '__main__':
    solutions = doqueens()
    unique = {}; transformed = {}
    iunique=0
    for sol in solutions:
        if sol in unique or sol in transformed: continue
        iunique+=1
        unique[sol]=iunique
        for tsol, label in transforms(sol):
            if tsol in transformed: continue
            transformed[tsol] = sol,label
    
    loop = ''
    iunique = 0
    for iorig, sol in enumerate(solutions):
        assert solok(sol)   # just for warm fuzzies
        if loop in ['', 'a']:
            if sol in unique:
                iunique+=1
                print '\n====[ Unique Solution %s (orig %s/92) ]====[ bitmap %X ]====\n'%(
                    unique[sol], iorig+1, sol)
                printsol(sol)
            else:
                usol, label = transformed[sol]
                print '\n====[ Orig solution %s/92 is unique solution %s transformed %s ]====\n'%(
                    iorig+1, unique[usol], label)
        if loop=='':
            loop ='x'
            while loop not in ['','a','q','t']:
                loop = raw_input('\nPress Enter for another, a for all,  t for transform, q to quit: ')
            if loop=='t':
                print '\n  Original solution # %s/92:\n'%(iorig+1)
                printsol(sol)
                print '\n  ... is the following unique solution %s transformed by %s:\n'%(
                    unique[usol], label)
                printsol(usol)
                loop = ''
            if loop =='q': break
=========================================================================

Regards,
Bengt Richter




More information about the Python-list mailing list