Latest version of Chess test prog for anyone who might be interested.
It does not do en-passon or castling.
Best Regards
Chris
#!/opt/local/bin/pypy -u -tt
#!/opt/local/bin/pypy -u -tt -m cProfile
# -*- coding: utf-8 -*-
# Copyright (C) 2013-2014 Chris Hinsley, GPL V3 License
import sys, os, time
from operator import itemgetter
from array import array
MAX_PLY = 10
MAX_TIME_PER_MOVE = 10
PIECE_VALUE_FACTOR = 3
KING_VALUE, QUEEN_VALUE, ROOK_VALUE = 1000000, 9 * PIECE_VALUE_FACTOR,
5 * PIECE_VALUE_FACTOR
BISHOP_VALUE, KNIGHT_VALUE, PAWN_VALUE = 3 * PIECE_VALUE_FACTOR, 3 *
PIECE_VALUE_FACTOR, 1 * PIECE_VALUE_FACTOR
EMPTY, WHITE, BLACK = 0, 1, -1
NO_CAPTURE, MAY_CAPTURE, MUST_CAPTURE = 0, 1, 2
piece_type = {' ' : EMPTY, 'K' : BLACK, 'Q' : BLACK, 'R' : BLACK, 'B' :
BLACK, 'N' : BLACK, 'P' : BLACK, \
'k' : WHITE, 'q' : WHITE, 'r' : WHITE, 'b' : WHITE, 'n' : WHITE, 'p'
: WHITE}
def display_board(board):
print
print ' a b c d e f g h'
print '+---+---+---+---+---+---+---+---+'
for row in range(8):
for col in range(8):
print '| %c' % board[row * 8 + col],
print '|', 8 - row
print '+---+---+---+---+---+---+---+---+'
print
def piece_moves(board, index, vectors):
piece = board[index]
type = piece_type[piece]
promote = 'QRBN' if type == BLACK else 'qrbn'
cy, cx = divmod(index, 8)
for dx, dy, length, flag in vectors:
x, y = cx, cy
if length == 0:
if piece == 'P':
length = 2 if (y == 1) else 1
else:
length = 2 if (y == 6) else 1
while length > 0:
x += dx; y += dy; length -= 1
if (x < 0) or (x >=8) or (y < 0) or (y >= 8):
break
newindex = y * 8 + x
newpiece = board[newindex]
newtype = piece_type[newpiece]
if newtype == type:
break
if (flag == NO_CAPTURE) and (newtype != EMPTY):
break
if (flag == MUST_CAPTURE) and (newtype == EMPTY):
break
board[index] = ' '
if (y == 0 or y == 7) and piece in 'Pp':
for promote_piece in promote:
board[newindex] = promote_piece
yield board
else:
board[newindex] = piece
yield board
board[index], board[newindex] = piece, newpiece
if (flag == MAY_CAPTURE) and (newtype != EMPTY):
break
def piece_scans(board, index, vectors):
cy, cx = divmod(index, 8)
for dx, dy, length in vectors:
x, y = cx, cy
while length > 0:
x += dx; y += dy; length -= 1
if (0 <= x < 8) and (0 <= y < 8):
piece = board[y * 8 + x]
if piece != ' ':
yield piece
break
black_pawn_vectors = [(-1, 1, 1), (1, 1, 1)]
white_pawn_vectors = [(-1, -1, 1), (1, -1, 1)]
bishop_vectors = [(x, y, 7) for x, y in [(-1, -1), (1, 1), (-1, 1), (1, -1)]]
rook_vectors = [(x, y, 7) for x, y in [(0, -1), (-1, 0), (0, 1), (1, 0)]]
knight_vectors = [(x, y, 1) for x, y in [(-2, 1), (2, -1), (2, 1), (-2,
-1), (-1, -2), (-1, 2), (1, -2), (1, 2)]]
queen_vectors = bishop_vectors + rook_vectors
king_vectors = [(x, y, 1) for x, y, _ in queen_vectors]
black_pawn_moves = [(0, 1, 0, NO_CAPTURE), (-1, 1, 1, MUST_CAPTURE),
(1, 1, 1, MUST_CAPTURE)]
white_pawn_moves = [(x, -1, length, flag) for x, _, length, flag in
black_pawn_moves]
rook_moves = [(x, y, length, MAY_CAPTURE) for x, y, length in rook_vectors]
bishop_moves = [(x, y, length, MAY_CAPTURE) for x, y, length in bishop_vectors]
knight_moves = [(x, y, length, MAY_CAPTURE) for x, y, length in knight_vectors]
queen_moves = bishop_moves + rook_moves
king_moves = [(x, y, 1, flag) for x, y, _, flag in queen_moves]
moves = {'P' : black_pawn_moves, 'p' : white_pawn_moves, 'R' :
rook_moves, 'r' : rook_moves, \
'B' : bishop_moves, 'b' : bishop_moves, 'N' : knight_moves, 'n' :
knight_moves, \
'Q' : queen_moves, 'q' : queen_moves, 'K' : king_moves, 'k' :
king_moves}
white_scans = [('QB', bishop_vectors), ('QR', rook_vectors), ('N',
knight_vectors), ('K', king_vectors), ('P', white_pawn_vectors)]
black_scans = [('qb', bishop_vectors), ('qr', rook_vectors), ('n',
knight_vectors), ('k', king_vectors), ('p', black_pawn_vectors)]
def in_check(board, colour):
if colour == BLACK:
king_piece, scans = 'K', black_scans
else:
king_piece, scans = 'k', white_scans
king_index = array.index(board, king_piece)
for test_pieces, vectors in scans:
pieces = [piece for piece in piece_scans(board, king_index,
vectors)]
for piece in test_pieces:
if piece in pieces:
return True
return False
def all_moves(board, colour):
for index, piece in enumerate(board):
if piece_type[piece] == colour:
for new_board in piece_moves(board, index,
moves[piece]):
if not in_check(new_board, colour):
yield new_board
piece_values = {'K' : (KING_VALUE, 0), 'k' : (0, KING_VALUE), 'Q' :
(QUEEN_VALUE, 0), 'q' : (0, QUEEN_VALUE), \
'R' : (ROOK_VALUE, 0), 'r' : (0, ROOK_VALUE), 'B' : (BISHOP_VALUE,
0), 'b' : (0, BISHOP_VALUE), \
'N' : (KNIGHT_VALUE, 0), 'n' : (0, KNIGHT_VALUE), 'P' :
(PAWN_VALUE, 0), 'p' : (0, PAWN_VALUE)}
generic_position_values = [0, 0, 0, 0, 0, 0, 0, 0, \
0, 1, 1, 1, 1, 1, 1, 0,
\
0, 1, 2, 2, 2, 2, 1, 0,
\
0, 1, 2, 3, 3, 2, 1, 0,
\
0, 1, 2, 3, 3, 2, 1, 0,
\
0, 1, 2, 2, 2, 2, 1, 0,
\
0, 1, 1, 1, 1, 1, 1, 0,
\
0, 0, 0, 0, 0, 0, 0, 0]
white_king_position_values = [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, 0, 0, \
0, 0, 0, 0, 0,
0, 0, 0, \
0, 0, 0, 0, 0,
0, 0, 0, \
3, 3, 3, 3, 3,
3, 3, 3]
black_king_position_values = [3, 3, 3, 3, 3, 3, 3, 3, \
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, 0, 0, \
0, 0, 0, 0, 0,
0, 0, 0, \
0, 0, 0, 0, 0,
0, 0, 0]
piece_positions = {'K' : black_king_position_values, 'k' :
white_king_position_values, \
'P' : generic_position_values, 'p' :
generic_position_values, \
'N' : generic_position_values, 'n' :
generic_position_values, \
'B' : generic_position_values, 'b' :
generic_position_values, \
'R' : generic_position_values, 'r' :
generic_position_values, \
'Q' : generic_position_values, 'q' :
generic_position_values}
def evaluate(board):
black_score, white_score = 0, 0
for index, piece in enumerate(board):
type = piece_type[piece]
if type != EMPTY:
position_value = piece_positions[piece][index]
if type == BLACK:
black_score += position_value
else:
white_score += position_value
black_value, white_value = piece_values[piece]
black_score += black_value
white_score += white_value
return white_score - black_score
start_time = time.time()
def next_move(board, colour, alpha, beta, ply):
global start_time
if ply <= 0:
return evaluate(board) * colour
for new_board in all_moves(board[:], colour):
alpha = max(alpha, -next_move(new_board, -colour, -beta,
-alpha, ply - 1))
if alpha >= beta:
break
if (time.time() - start_time) > MAX_TIME_PER_MOVE:
break
return alpha
def best_move(board, colour):
global start_time
all_boards = [(evaluate(new_board) * colour, new_board[:]) for
new_board in all_moves(board, colour)]
all_boards = sorted(all_boards, key = itemgetter(0), reverse = True)
best_board, best_ply_board, start_time = board, board, time.time()
for ply in range(1, MAX_PLY):
print '\nPly =', ply
alpha, beta = -KING_VALUE * 10, KING_VALUE * 10
for new_board in all_boards:
score = -next_move(new_board[1], -colour, -beta,
-alpha, ply - 1)
if (time.time() - start_time) > MAX_TIME_PER_MOVE:
return best_board
if score > alpha:
alpha, best_ply_board = score, new_board[1]
print '\b*',
else:
print '\b.',
best_board = best_ply_board
return best_board
def main():
board = array('c', 'RNBQKBNRPPPPPPPP
pppppppprnbqkbnr')
colour = WHITE
os.system(['clear','cls'][os.name=='nt'])
display_board(board)
while True:
print 'White to move:' if colour == WHITE else 'Black to move:'
board = best_move(board, colour)
colour = -colour
os.system(['clear','cls'][os.name=='nt'])
display_board(board)
#raw_input()
if __name__ == '__main__':
main()
--
https://mail.python.org/mailman/listinfo/python-list