Just some learnings from doing chess coding problems.
Chessboard Representation
A chessboard can be represented as a two-dimensional array of the Cartesian product to represent a 8x8 grid. More background in the Applications of Cartesian Products article.
import numpy as np
file, rank = "abcdefgh", "12345678"
files, ranks = list(file), list(rank)
board = []
for f in ranks[::-1]:
row = []
for r in files:
row.append(r + f)
board.append(row)
print(np.matrix(board))
We use numpy
to display the 2D-array in matrix form:
[['a8' 'b8' 'c8' 'd8' 'e8' 'f8' 'g8' 'h8']
['a7' 'b7' 'c7' 'd7' 'e7' 'f7' 'g7' 'h7']
['a6' 'b6' 'c6' 'd6' 'e6' 'f6' 'g6' 'h6']
['a5' 'b5' 'c5' 'd5' 'e5' 'f5' 'g5' 'h5']
['a4' 'b4' 'c4' 'd4' 'e4' 'f4' 'g4' 'h4']
['a3' 'b3' 'c3' 'd3' 'e3' 'f3' 'g3' 'h3']
['a2' 'b2' 'c2' 'd2' 'e2' 'f2' 'g2' 'h2']
['a1' 'b1' 'c1' 'd1' 'e1' 'f1' 'g1' 'h1']]
Black/White Cells
If we wanted to add the alternating black/white colors for rank and file to better represent the board:
import numpy as np
file, rank = "abcdefgh", "12345678"
files, ranks = list(file), list(rank)
board = []
for i, f in enumerate(ranks[::-1]):
row = []
i = i % 2 # Even if 0 and odd if 1.
for j, r in enumerate(files):
c = '_b' if j & 1 else '_w' # Odd if j & 1 == 1 else even.
if i:
c = '_w' if j & 1 else '_b'
row.append(f + r + c )
board.append(row)
print(np.matrix(board))
We use modulo (%)
and bitwise and (&)
to determine either even or odd for i
and j
.
[['8a_w' '8b_b' '8c_w' '8d_b' '8e_w' '8f_b' '8g_w' '8h_b']
['7a_b' '7b_w' '7c_b' '7d_w' '7e_b' '7f_w' '7g_b' '7h_w']
['6a_w' '6b_b' '6c_w' '6d_b' '6e_w' '6f_b' '6g_w' '6h_b']
['5a_b' '5b_w' '5c_b' '5d_w' '5e_b' '5f_w' '5g_b' '5h_w']
['4a_w' '4b_b' '4c_w' '4d_b' '4e_w' '4f_b' '4g_w' '4h_b']
['3a_b' '3b_w' '3c_b' '3d_w' '3e_b' '3f_w' '3g_b' '3h_w']
['2a_w' '2b_b' '2c_w' '2d_b' '2e_w' '2f_b' '2g_w' '2h_b']
['1a_b' '1b_w' '1c_b' '1d_w' '1e_b' '1f_w' '1g_b' '1h_w']]
Translation from Algebraic Notation to Index Notation
Sometimes we may want to translate a chess piece position from algebraic notation ("A3") to index notation (cell[0][3]). Note algebraic notation is A/1 based.
Using translate table:
def get_position_translate(piece):
f, r = "abcdefgh", "01234567"
tbl = str.maketrans(c, n)
return (int(piece[0].translate(tbl)), int(piece[1])-1)
Using ASCII code:
def get_position_ascii(piece):
return (ord(piece[0].upper()) - ord('A'), int(piece[1])-1)
Pawn Movement
def pawn_moves(face_north, rank, file):
'''
Returns position of pawn next move. Pawn can only move forward.
If invalid move then returns current cell/squre/position.
param: face_north - bool - Facing north or south.
param: rank - int - The horizontal/row zero-based index.
param: file - int - The vertical/column zero-based index.
'''
if face_north:
if file < 8:
return (rank, file+1)
elif file > 0:
return (rank, file-1)
return (rank, file)
Knight Movement
Best to determine possible 8 positions and then filter by whether or not they are on the board.
def knight_moves(rank, file):
'''
param: rank - int - The horizontal/row zero-based index.
param: file - int - The vertical/column zero-based index.
'''
if (0 > rank or rank > 8) or (0 > file or file > 8):
return (rank, file)
possible_moves = [(1, 2), (2, 1), (-1, 2), (1, -2), (-1, -2), (-2, -1), (2, -1), (-2, 1)]
moves = [(rank + r, file + f) for r, f in possible_moves
if 0 <= rank + r < 8 and 0 <= file + f < 8]
return moves
Alternative
def possible_knight_movesx(rank, file):
'''
param: rank - int - The horizontal/row zero-based index.
param: file - int - The vertical/column zero-based index.
'''
if (0 > rank or rank > 8) or (0 > file or file > 8):
return (rank, file)
possible_moves = [(-2, -1), (-1, -2), (-2, 1), (-1, 2)] # The Top half. Left/Right mirror doesn't work.
possible_moves += ([(x*-1, y*-1) for x,y in possible_moves])
moves = [(rank + r, file + f) for r, f in possible_moves
if 0 <= rank + r < 8 and 0 <= file + f < 8]
return moves
Bishop Movement
TODO
Rook Movement
TODO
Queen Movement
TODO
King Movement
TODO
Amazon Movement
TODO