eight-queens.py

####################################################################################################
from __future__ import print_function
from sys import stdinstdoutstderrargv
####################################################################################################

NROWS = 8
NCOLS = 8

CFG = [NROWSNCOLS0]

##================================================================================================##
str_accum = lambda acc: ':'.join(map(lambda x: str(x), accum))

##================================================================================================##
def report_solution (fpaccum):
    fp.flush()
    # numerical value...
    fp.write('  %s:\n' % accum)
    # horizontal line...
    fp.write('  +')
    for cx in range(CFG[1]):
        fp.write('---+')
    fp.write('\n')
    for rx in range(CFG[0]):
        row = rx + 1
        # row...
        fp.write('  |')
        for cx in range(CFG[1]):
            col = cx + 1
            if accum[cx] == row:
                fp.write(' Q |')
            else:
                fp.write('   |')
        fp.write('\n')
        # horizontal line...
        fp.write('  +')
        for cx in range(CFG[1]):
            fp.write('---+')
        fp.write('\n')
    fp.write('\n')
    fp.flush()
    # Bump Wins Counter and return value...
    CFG[2] += 1
    return CFG[2]

##================================================================================================##
def test_queen (accumrow):
    # Test for row already occupied...
    for ch in accum:
        if ch == row:
            return 0 # collision!
    # Test for (upper) diagonal already occupied...
    for ix,ch in enumerate(reversed(accum)):
        n = row + (ix + 1)
        if CFG[0] < n:
            break
        if n == ch:
            return 0 # collision!
    # Test for (lower) diagonal already occupied...
    for ix,ch in enumerate(reversed(accum)):
        n = row - (ix + 1)
        if n < 1:
            break
        if n == ch:
            return 0 # collision!
    # Queen can be placed...
    return 1

##================================================================================================##
def place_queen (fpaccum=[], col=1):
    row = 1
    while row <= CFG[0]:
        if test_queen(accumrow):
            # Try this pattern...
            accum.append(row)
            if col == CFG[1]:
                ### Found a Solution! ###
                report_solution(fpaccum)
            else:
                ### RECURSE! ###
                place_queen(fpaccumcol+1)
            # Done trying, remove...
            accum.pop()
        # Next row...
        row += 1
        # Special test to avoid reflected solutions...
        if (col == 1and (int((CFG[0]+1)/2) < row):
            break
    # Return number of solutions...
    return CFG[2]

##================================================================================================##
def do_test (*args):
    print('test/parameters: %d' % len(args))
    CFG[0] = int(args[0]) if 0 < len(argselse NROWS
    CFG[1] = int(args[1]) if 1 < len(argselse NCOLS
    fn = args[2if 2 < len(argselse 'eight-queens.out'
    fp = open(fn'w')
    try:
        place_queen(fp)
        print(file=fp)
        print("%d solution%s!" % (CFG[2], '' if CFG[2]==1 else 's'), file=fp)
        print(file=fp)
    except Exception as e:
        raise
    finally:
        fp.close()
    return 'Done!'
##================================================================================================##
def do_main (*args):
    print('main/parameters: %d' % len(args))
    fn = args[0if 0 < len(argselse 'eight-queens.out'
    fp = open(fn'w')
    try:
        place_queen(fp)
        print(file=fp)
        print("%d solution%s!" % (CFG[2], '' if CFG[2]==1 else 's'), file=fp)
        print(file=fp)
    except Exception as e:
        raise
    finally:
        fp.close()
    return 'Done!'
####################################################################################################
def dispatch (cmd, *args):
    print('command: %s' % cmd)
    print('arguments: %d' % len(args))
    if cmd == 'test': return do_test(*args)
    if cmd == 'main': return do_main(*args)
    return 'Nothing to do!'
####################################################################################################
if __name__ == '__main__':
    print('autorun: %s' % argv[0])
    cmd = argv[1if 1 < len(argvelse ''
    etc = argv[2:if 2 < len(argvelse []
    obj = dispatch(cmd, *etc)
    print("%d solution%s!" % (CFG[2], '' if CFG[2]==1 else 's'))
    print(obj)
####################################################################################################
'''eof'''