изменение логических значений массива по формуле для индексов - PullRequest
1 голос
/ 14 июля 2020

Я хочу создать массив из 64 компонентов, показывающий все поля, в которых две ладьи пустой шахматной доски могут двигаться из своего текущего положения. Пока я делаю это с циклами for и while.

Сначала я создаю функцию, чтобы лучше визуализировать доску:

import numpy as np
def from_array_to_matrix(v):
    m=np.zeros((8,8)).astype('int')
    for row in range(8):
        for column in range(8): 
            m[row,column]=v[row*8+column]
    return m

, и здесь я показываю, как я на самом деле построить массив:

# positions of the two rooks

a=np.zeros(64).astype('int')
a[15] = 1
a[25] = 1

print from_array_to_matrix(a)

# attack_a will be all the squares where they could move in the empty board
attack_a=np.zeros(64).astype('int')
for piece in np.where(a)[0]:
    j=0
    square=piece+j*8
    while square<64:
        attack_a[square]=1
        j+=1
        square=piece+j*8
    j=0
    square=piece-j*8
    while square>=0:
        attack_a[square]=1
        j+=1
        square=piece-j*8
    j=0
    square=piece+j
    while square<8*(1+piece//8):
        attack_a[square]=1
        j+=1
        square=piece+j
    j=0
    square=piece-j
    while square>=8*(piece//8):
        attack_a[square]=1
        j+=1
        square=piece-j

print attack_a
print from_array_to_matrix(attack_a)

Мне посоветовали избегать циклов for и while, когда можно использовать другие способы, потому что они обычно отнимают много времени. Есть ли способ достичь того же результата без повторения процесса с циклами for и while? Возможно, используя тот факт, что индексы, которым я хочу присвоить значение 1, могут быть определены функцией.

Ответы [ 2 ]

1 голос
/ 14 июля 2020

Есть несколько способов сделать это. Самым простым, конечно же, является работа с матрицами.

Но вы также можете векторизовать операции над raveled-массивом. Например, скажем, у вас была ладья на позиции 0 <= n < 64 в линейном массиве. Чтобы установить строку равной единице, используйте целочисленное деление:

array[8 * (n // 8):8 * (n // 8 + 1)] = True

Чтобы установить столбец, используйте по модулю:

array[n % 8::8] = True

Вы можете преобразовать в матрицу, используя reshape:

matrix = array.reshape(8, 8)

И обратно, используя ravel:

array = martix.ravel()

Или reshape:

array = matrix.reshape(-1)

Установка единиц в матрице еще проще, учитывая специфику c строка 0 <= m < 8 и столбец 0 <= n < 8:

matrix[m, :] = matrix[:, n] = True

Теперь единственный вопрос - как векторизовать несколько индексов одновременно. Как это бывает, вы можете использовать причудливый индекс на одной оси. Т.е. приведенное выше выражение можно использовать с m и n, содержащими несколько элементов:

m, n = np.nonzero(matrix)
matrix[m, :] = matrix[:, n] = True

Вы даже можете играть в игры и делать это с массивом, также используя причудливую индексацию:

n = np.nonzero(array)[0]
r = np.linspace(8 * (n // 8), 8 * (n // 8 + 1), 8, False).T.ravel()
c = np.linspace(n % 8, n  % 8 + 64, 8, False)
array[r] = array[c] = True

Использование linspace позволяет одновременно генерировать несколько последовательностей одного размера. Каждая последовательность представляет собой столбец, поэтому мы транспонируем перед перемещением, хотя это и не требуется.

1 голос
/ 14 июля 2020

Используйте изменение формы, чтобы преобразовать одномерный массив в двумерную матрицу 8x8, а затем numpy продвинуть индексирование, чтобы выбрать строки и столбцы, которые нужно установить на 1:

import numpy as np
def from_array_to_matrix(v):
    return v.reshape(8,8)

# positions of the two rooks    
a=np.zeros(64).astype('int')
a[15] = 1
a[25] = 1

a = from_array_to_matrix(a)

# attack_a will be all the squares where they could move in the empty board
attack_a=np.zeros(64).astype('int')
attack_a = from_array_to_matrix(attack_a)

#these two lines replace your for and while loops
attack_a[np.where(a)[0],:] = 1
attack_a[:,np.where(a)[1]] = 1

вывод:

a:

[[0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 1]
 [0 0 0 0 0 0 0 0]
 [0 1 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]]

attack_a:

[[0 1 0 0 0 0 0 1]
 [1 1 1 1 1 1 1 1]
 [0 1 0 0 0 0 0 1]
 [1 1 1 1 1 1 1 1]
 [0 1 0 0 0 0 0 1]
 [0 1 0 0 0 0 0 1]
 [0 1 0 0 0 0 0 1]
 [0 1 0 0 0 0 0 1]]
...