Latest Chess prog

Chris Hinsley chris.hinsley at gmail.com
Wed Sep 3 19:05:37 EDT 2014


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()




More information about the Python-list mailing list