2

I need to place N queen pieces on a MxM board so that no two queens attack each other. The difference from the original is that the queens can only attack up to 5 squares from their location, and not the whole row, column or diagonal as in the original problem.

One idea I'm playing around in my head is to place the first Queen on the board at board[i][j], but then also place it in its 5 neighboring squares as shown in the image below.

Example of placement of the first and second queen on a board

The following snipped is the isSafe function from the original N-Queens problem.

Looking for guidance as to how to check if a queen placement is safe.

def isSafe(board, row, col): 

# Check this row on left side 
for i in range(col): 
    if board[row][i] == 1: 
        return False

# Check upper diagonal on left side 
for i,j in zip(range(row,-1,-1), range(col,-1,-1)): 
    if board[i][j] == 1: 
        return False

# Check lower diagonal on left side 
for i,j in zip(range(row,N,1), range(col,-1,-1)): 
    if board[i][j] == 1: 
        return False

return True

In summary, how do I detect if a queen is safe if I limit the queen's range to 5 squares?

Leonardo Lopez
  • 1,113
  • 6
  • 20
  • 39

2 Answers2

0

There are two main approaches:

1) For every new queen check whether another ones are at horizontals/verticals/diagonals in range. Longer to check, faster to add/remove

2) Mark beaten cells with numbers: 0 for safe one, K for the cell beaten by K queens. In this case you can easily determine if cell is safe, increment beaten cells values for new queen and decrement them if you need to remove a queen. Faster to check, longer to add/remove.

To modify code sample, restrict ranges. For example, left-bottom diagonal:

for i,j in zip(range(row, max(-1, row - 5),-1), range(col, min(N, col + 5), 1)): 
    if board[i][j] == 1: 
         return False
MBo
  • 77,366
  • 5
  • 53
  • 86
0

Here is another approach to solve the problem. It based on a fact that two queens can clashes only and only if they share the same row or column or diagonal, so if this condition is False, it is a safe place for the queen. Here is an implementation :

def share_diagonal(x0, y0, x1, y1):
    """ Check if two coordinates share diagonal or not ? """
    dx = abs(x0 - x1)
    dy = abs(y0 - y1)

    return dy == dx


def col_clashes(bs, c):
    """ Return True if the queen at column c clashes
         with any queen to its left.
    """
    for i in range(c):     # Look at all columns to the left of c
        if share_diagonal(i, bs[i], c, bs[c]):
            return True

    return False


def has_clashes(the_board):
    """ Determine whether we have any queens clashing on the diagonals.
        We're assuming here that the_board is a permutation of column
        numbers, so we're not explicitly checking row or column clashes.
    """
    for col in range(1, len(the_board)):
        if col_clashes(the_board, col):
            return True
    return False


def main():
    import random
    rng = random.Random()   # Instantiate a generator

    bd = list(range(8))     # Generate the initial permutation
    num_found = 0
    tries = 0
    result = []
    while num_found < 10:
        rng.shuffle(bd)
        tries += 1

        if not has_clashes(bd) and bd not in result:
            print("Found solution {0} in {1} tries.".format(bd, tries))
            tries = 0
            num_found += 1
            result.append(list(bd))
    print(result)


main()