I have the following code for a numpy array:
import numpy as np
a = np.array([[0,1,2,3,4,5,6,7],
[8,9,10,11,12,13,14,15],
[16,17,18,19,20,21,22,23],
[24,25,26,27,28,29,30,31],
[32,33,34,35,36,37,38,39],
[40,41,42,43,44,45,46,47],
[48,49,50,51,52,53,54,55],
[56,57,58,59,60,61,62,63]])
Given a starting point, I need to move around this board as a knight would on a chess board (2 spaces vertically, 1 horizontally, or vice versa).
I can use np.argwhere to get coordinates of the starting point:
np.argwhere(a==13) returns [[1 5]].
What can I do to move around from there? I'd like to test all possible moves, and return all coordinates.
There would be eight such possible combinations. We could those as offsets in a 8 x 2
array and do broadcasted addition with the starting XY. Additionally, we need to fitter out the ones going beyond the chessboard limits.
Thus, an implementation given the start X,Y as a tuple would be -
def knight_move(start_xy):
offset1 = np.array([[-2,-1],[-2,1],[2,-1],[2,1]])
idx = np.row_stack((offset1, offset1[:,::-1])) + start_xy
return idx[~((idx < 0) | (idx > 7)).any(1)]
Sample run -
In [66]: a # Chessboard as array
Out[66]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30, 31],
[32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47],
[48, 49, 50, 51, 52, 53, 54, 55],
[56, 57, 58, 59, 60, 61, 62, 63]])
In [67]: newXYs = knight_move((1,5)) # 13
In [68]: newXYs
Out[68]:
array([[3, 4],
[3, 6],
[0, 3],
[2, 3],
[0, 7],
[2, 7]])
In [69]: a[newXYs[:,0], newXYs[:,1]]
Out[69]: array([28, 30, 3, 19, 7, 23])
The position of the knight can be represented by [xy]
with 0 <= x,y < 8
. The possible 8 directions of movement can be represented by the vectors [+/-1 +/-2], [+/-2 +/-1]
. But a move is only valid if the resulting field is valid (see the above limits on x,y
). This method works without using an array.
A more efficient way, using a 1-dimensional array, is the following: a border of width 2 is added around the 8x8 chessboard. This enlarged 12x12 board is encoded in a 1-dimensional array where the cell value signals the corresponding field`s validity:
board = [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,
-1,-1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,
-1,-1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,
-1,-1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,
-1,-1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,
-1,-1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,
-1,-1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,
-1,-1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]
The position of the knight is represented by one index (eg 26 for the upper left corner) and the possible movements of the knights by the index offsets +/-1 + 12*(+/-2)
and +/-2 + 12*(+/-1)
, so alltogether 25, -23, 23, -25, 14, -10, 10, -14
. The validity of a move is again checked by the validity of the resulting index which reduces to board[index+move] == 0
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.