Using exhaustive method and numpy to solve the eight queens problem

Posted by banacan on Tue, 29 Oct 2019 21:12:30 +0100

Generally speaking, when we talk about the eight queens problem, the first thought we think about is the idea of backtracking, which needs to be realized in return.
Computers are good at doing repetitive things, so recursion is right with its appetites, and our brains prefer to see the way of thinking in a straightforward way. When
When we see recursion, we always want to spread recursion horizontally, and then we will cycle in our mind, layer by layer, downward, and then return layer by layer.
Trying to figure out how computers perform every step of the way makes it easy to get around.

I am an example. When using recursion to solve merging or quick sorting, because the problem itself is not very complex, recursive code is relatively simple to write
But eight queens, I read the corresponding code on the Internet, and I always feel like I don't understand it. It's easy to get around it.
So I tried to solve the problem of the eight queens in an exhaustive way.

Ideas are as follows

  • Exhaust every pendulum
  • For each pendulum method, convert it into a nunpy array
  • Judge whether each row, each column, each lower left diagonal and each lower right diagonal meet the requirements respectively.

Look directly at the code:

import numpy as np
import itertools

BOARD_SIZE = 8
result = [0] * BOARD_SIZE   # Subscript for row, value for column

# Turn tuple (2,0,1) into numpy array:
#array([[0, 0, 1],
#       [1, 0, 0],
#       [0, 1, 0]])

def get_np_represent(result):
    two_D = []
    for row in range(BOARD_SIZE):
        one_D = []
        for col in range(BOARD_SIZE):
            if result[row] == col:
                one_D.append(1)
            else:
                one_D.append(0)
        two_D.append(one_D)
    return np.array(two_D)

# Judge whether the corresponding lines (horizontal, vertical, lower left diagonal, lower right diagonal) meet the needs
def line_not_pass(np):
    return (np > 1).any()

# Get the array with the bottom left diagonal added
def left_diag_array(np_array):
    
    left_diag_array = [np.sum(np.diag(np.fliplr(np_array), d)) for d in range(len(np_array) - 1, -len(np_array), -1)]
    
    return np.array(left_diag_array)

# Get the array of the bottom right diagonal addition
def right_diag_array(np_array):
    right_diag_array = [np.sum(np.diag(np_array, d)) for d in range(len(np_array) - 1, -len(np_array), -1)]
    return np.array(right_diag_array)

match_count = 0

# main 
for arr in itertools.product(list(range(0,BOARD_SIZE)),repeat=BOARD_SIZE):
    loop_count +=1
    np_array = get_np_represent(arr)
    
    row_array = np_array.sum(axis=1)
    if line_not_pass(row_array):
        continue
    col_array = np_array.sum(axis=0)
    if line_not_pass(col_array):
        continue
    
    if line_not_pass(left_diag_array(np_array)):
        continue
    
    if line_not_pass(right_diag_array(np_array)):
        continue
    print("right diag line ",loop_count )
    match_count +=1

print("total count:",match_count)

Topics: Erlang