开发者

eight queens problem in Python

8-queens problem in Python.

Hi! I only start teaching Python, so could someone explain the code written below (found in the Internet)? Some pieces of the code are complicated for me. Please, explain them. Thank you. Questions are near the code.

BOARD_SIZE = 8

def under_attack(col, queens): # (col, queens) What is their meaning? What do I need to write it this field? 
    left = right = col
    for r, c in reversed(quee开发者_运维技巧ns): # What does reversed means in this loop? For what reson do we need r and c (their meaning is 0 by default?)?
        left, right = left-1, right+1
        if c in (left, col, right):
            return True
    return False

def solve(n):
    if n == 0: return [[]]
    smaller_solutions = solve(n-1) # For what reasons do we need to write smaller_solutions?
    return [solution+[(n,i+1)] # What is solution (is it a function or what?)? What is value of i? 
        for i in range(BOARD_SIZE)
            for solution in smaller_solutions
                if not under_attack(i+1, solution)]
for answer in solve(BOARD_SIZE): print answer

Thank you!


Your code is wrong (cut and paste error?), but here's the gist:

You want a list of possible solutions. Each solution is a list of queens. Every queen is a tuple - a row (integer) and column (integer). For example, the solution for BOARD_SIZE=1 is [[(1,1)]] - a single solution - [(1,1)] containing a single queen - (1,1) placed on row 1 and column 1.

There are 8 smaller_solutions for BOARD_SIZE=8, and n=1 - [[(1,1)],[(1,2)],[(1,3)],[(1,4)],[(1,5)],[(1,6)],[(1,7)],[(1,8)]] - a single queen placed in every column in the first row.

You understand recursion? If not, google it NOW.

Basically, you start by adding 0 queens to a size 0 board - this has one trivial solution - no queens. Then you find the solutions that place one queen the first row of the board. Then you look for solutions which add a second queen to the 2nd row - somewhere that it's not under attack. And so on.

def solve(n):
    if n == 0: return [[]] # No RECURSION if n=0. 
    smaller_solutions = solve(n-1) # RECURSION!!!!!!!!!!!!!!
    solutions = []
    for solution in smaller_solutions:# I moved this around, so it makes more sense
        for column in range(1,BOARD_SIZE+1): # I changed this, so it makes more sense
            # try adding a new queen to row = n, column = column 
            if not under_attack(column , solution): 
                solutions.append(solution + [(n,column)])
    return solutions

That explains the general strategy, but not under_attack.

under_attack could be re-written, to make it easier to understand (for me, you, and your students):

def under_attack(column, existing_queens):
    # ASSUMES that row = len(existing_queens) + 1
    row = len(existing_queens)+1
    for queen in existing_queens:
        r,c = queen
        if r == row: return True # Check row
        if c == column: return True # Check column
        if (column-c) == (row-r): return True # Check left diagonal
        if (column-c) == -(row-r): return True # Check right diagonal
    return False

My method is a little slower, but not much.

The old under_attack is basically the same, but it speeds thing up a bit. It looks through existing_queens in reverse order (because it knows that the row position of the existing queens will keep counting down), keeping track of the left and right diagonal.


BOARD_SIZE = 8

def under_attack(col, queens): # You do not need to fill in these fields. This is a helper function for the solve function.
    left = right = col
    for r, c in reversed(queens): # Reversing queens causes them to be iterated over in reverse order.
        left, right = left-1, right+1
        if c in (left, col, right):
            return True
    return False

def solve(n):
    if n == 0: return [[]]
    smaller_solutions = solve(n-1) # It appears that in solving this board, it solves all boards smaller than it in a recursive manner.
    return [solution+[(n,i+1)] # This line appears to be in error. Have you run this code and verified that it runs correctly?
        for i in range(BOARD_SIZE)
            for solution in smaller_solutions
                if not under_attack(i+1, solution)]
for answer in solve(BOARD_SIZE): print answer


This is the source program where the output of this code will be generated in the separate file name as "queen.txt"

import json
import sys

BOARD_SIZE = 8

def under_attack(col, queens):
    x = y = col

    for r, c in reversed(queens):
        x , y = x - 1, y + 1 #check for the prev queen location 

        if c in (x , col, y):
            return True
    return False

def solve(n): # n is the number of queens to be placed
    if n == 0:
        return [[]]

    smaller_solutions = solve(n - 1)

    return [solution+[(n,i+1)]
        for i in xrange(BOARD_SIZE)
            for solution in smaller_solutions
                if not under_attack(i+1, solution)] #call the function 

former, sys.stdout = sys.stdout, open('queen.txt','w')

for answer in solve(BOARD_SIZE):
    print answer

results, sys.stdout = sys.stdout, former #former is used for ip & op
print json.dumps(answer) #dumps is used to write in json file

output file will like this [(1, 4), (2, 2), (3, 7), (4, 3), (5, 6), (6, 8), (7, 5), (8, 1)] [(1, 5), (2, 2), (3, 4), (4, 7), (5, 3), (6, 8), (7, 6), (8, 1)] [(1, 3), (2, 5), (3, 2), (4, 8), (5, 6), (6, 4), (7, 7), (8, 1)] . . . . [(1, 4), (2, 7), (3, 5), (4, 2), (5, 6), (6, 1), (7, 3), (8, 8)] [(1, 5), (2, 7), (3, 2), (4, 6), (5, 3), (6, 1), (7, 4), (8, 8)]


Here is my solution. It is much more easier to understand and straighforward:

def under_attack(row, column, existing_queens):
    if not len(existing_queens): return False
    for queen in existing_queens:
        if not len(queen):
            continue
        r,c = queen
        if r == row: return True # Check row
        if c == column: return True # Check column
        if (column-c) == (row-r): return True # Check left diagonal
        if (column-c) == -(row-r): return True # Check right diagonal
    return False

def iter_solve(n):
    solutions = None
    for row in range(1, n+1):
        # for each row, check all valid column
        solutions = check(solutions, row, n)
    return solutions

def check(solutions, row, n):
    new_solutions = []
    for column in range(1, n+1):
        if not solutions or not len(solutions):
            new_solutions.append([] + [(row, column)])
        else:
            for solution in solutions:
                if not under_attack(row, column, solution):
                    new_solutions.append(solution + [(row, column)])
    return new_solutions
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜