|
|
import chess
|
|
|
import chess.svg
|
|
|
import pygame
|
|
|
import engine
|
|
|
from pygame import Vector2
|
|
|
import move_finder
|
|
|
from multiprocessing import Process,Queue
|
|
|
|
|
|
move_width =200
|
|
|
move_height=0
|
|
|
width,height=512,512
|
|
|
dimensions = 8
|
|
|
sq_size = int(height/dimensions)
|
|
|
max_fps=15
|
|
|
images ={}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
load images in global dictionary .
|
|
|
called exactly on the main
|
|
|
'''
|
|
|
def load_images():
|
|
|
peices=['bQ','bK','bB','bN','bR','wQ','wK','wB','wN','wR','bp','wp']
|
|
|
for peice in peices:
|
|
|
images[peice] = pygame.transform.scale(pygame.image.load("./images/"+peice+".png"),(sq_size,sq_size))
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
draw squares on board
|
|
|
always top left square is white
|
|
|
'''
|
|
|
def draw_board(screen):
|
|
|
global colors
|
|
|
colors = [pygame.Color('white'),pygame.Color(194, 194, 194)]
|
|
|
for r in range(dimensions):
|
|
|
for c in range(dimensions):
|
|
|
parity = (r+c) & 1
|
|
|
color = colors[parity]
|
|
|
pygame.draw.rect(screen,color,pygame.Rect(c*sq_size,r*sq_size,sq_size,sq_size))
|
|
|
|
|
|
|
|
|
'''
|
|
|
draw peices using current game state (board)
|
|
|
'''
|
|
|
def draw_peices(screen,board):
|
|
|
for r in range(dimensions):
|
|
|
for c in range(dimensions):
|
|
|
peice = board[r][c]
|
|
|
if peice !='--':
|
|
|
screen.blit(images[peice],pygame.Rect(c*sq_size,r*sq_size,sq_size,sq_size))
|
|
|
|
|
|
import pygame
|
|
|
|
|
|
scroll_offset = 0
|
|
|
|
|
|
def draw_move_log(screen, gs, width, move_width, height):
|
|
|
global scroll_offset
|
|
|
font = pygame.font.SysFont('Arial', 16, False, False)
|
|
|
move_log_rect = pygame.Rect(width, 0, move_width, height)
|
|
|
|
|
|
|
|
|
pygame.draw.rect(screen, pygame.Color('black'), move_log_rect)
|
|
|
|
|
|
moves = gs.moveLog
|
|
|
text_y = 5 - scroll_offset
|
|
|
|
|
|
for j, i in enumerate(moves):
|
|
|
text = f"{j+1}. {str(i)}"
|
|
|
text_object = font.render(text, True, pygame.Color('white'))
|
|
|
text_location = move_log_rect.move(5, text_y)
|
|
|
screen.blit(text_object, text_location)
|
|
|
text_y += text_object.get_height() + 5
|
|
|
|
|
|
|
|
|
def handle_scroll(event):
|
|
|
"""Handles mouse wheel scrolling"""
|
|
|
global scroll_offset
|
|
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
|
if event.button == 4:
|
|
|
scroll_offset = max(0, scroll_offset - 20)
|
|
|
elif event.button == 5:
|
|
|
scroll_offset += 20
|
|
|
|
|
|
|
|
|
'''
|
|
|
rensonsible for graphics in current game state
|
|
|
'''
|
|
|
def draw_game_state(screen,gs,valid_moves,sq_selected):
|
|
|
draw_board(screen)
|
|
|
high_light_squares(screen,gs,valid_moves,sq_selected)
|
|
|
draw_peices(screen,gs.board)
|
|
|
draw_move_log(screen,gs,512,200,512)
|
|
|
'''
|
|
|
hgihlight the square selected and moves for peices selected
|
|
|
'''
|
|
|
|
|
|
def high_light_squares(screen,gs,valid_moves,sqselected):
|
|
|
if sqselected != ():
|
|
|
r,c = sqselected
|
|
|
if gs.board[r][c][0] == ('w' if gs.whiteToMove else 'b'):
|
|
|
|
|
|
|
|
|
s = pygame.Surface((sq_size,sq_size))
|
|
|
|
|
|
s.set_alpha(100)
|
|
|
s.fill(pygame.Color('blue'))
|
|
|
screen.blit(s,(c*sq_size,r*sq_size))
|
|
|
|
|
|
s.fill(pygame.Color('red'))
|
|
|
|
|
|
for move in valid_moves:
|
|
|
if move.start_row == r and move.start_col==c:
|
|
|
pygame.draw.circle(screen,pygame.Color(0,255,0),( int(sq_size*(move.end_col + 0.5)),int(sq_size*(move.end_row + 0.5))),7.5)
|
|
|
if gs.board[move.end_row][move.end_col][0]== ('b' if gs.whiteToMove else 'w'):
|
|
|
screen.blit(s,(sq_size*move.end_col,sq_size*move.end_row))
|
|
|
if len(gs.moveLog)>=1:
|
|
|
prev_move= gs.moveLog[-1]
|
|
|
s.set_alpha(100)
|
|
|
s.fill(pygame.Color('dark green'))
|
|
|
r,c = prev_move.end_row,prev_move.end_col
|
|
|
screen.blit(s,(c*sq_size,r*sq_size))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
pygame.init()
|
|
|
screen = pygame.display.set_mode((width+move_width,height+move_height))
|
|
|
clock = pygame.time.Clock()
|
|
|
screen.fill(pygame.Color('white'))
|
|
|
gs = engine.GameState()
|
|
|
load_images()
|
|
|
running = True
|
|
|
sqselected = ()
|
|
|
player_clicks=[]
|
|
|
valid_moves = gs.get_valid_moves()
|
|
|
game_over=False
|
|
|
player_one = True
|
|
|
player_two = False
|
|
|
ai_thinking = False
|
|
|
move_finder_procee = None
|
|
|
move_undone = False
|
|
|
if len(valid_moves)<=5:
|
|
|
for move in valid_moves:
|
|
|
print(move.peice_captured ,move.peice_moved, move.id)
|
|
|
move_made = False
|
|
|
|
|
|
animate=False
|
|
|
while running:
|
|
|
human_Turn = (gs.whiteToMove and player_one) or (not gs.whiteToMove and player_two)
|
|
|
for e in pygame.event.get():
|
|
|
|
|
|
if e.type == pygame.QUIT:
|
|
|
running=False
|
|
|
elif e.type == pygame.MOUSEBUTTONDOWN:
|
|
|
if not game_over and human_Turn:
|
|
|
location =pygame.mouse.get_pos()
|
|
|
col = int(location[0]//sq_size)
|
|
|
row = int(location[1]//sq_size)
|
|
|
if sqselected == (row,col) or col>=8:
|
|
|
sqselected=()
|
|
|
player_clicks=[]
|
|
|
else:
|
|
|
sqselected = (row,col)
|
|
|
player_clicks.append(sqselected)
|
|
|
if len(player_clicks)==2:
|
|
|
move = engine.Move(player_clicks[0],player_clicks[1],gs.board)
|
|
|
for i in range(len(valid_moves)):
|
|
|
if move==valid_moves[i]:
|
|
|
print("move taken",move.get_chess_notation(),"peice_moved:",gs.board[move.start_row][move.start_col])
|
|
|
gs.make_move(valid_moves[i])
|
|
|
move_made=True
|
|
|
animate=True
|
|
|
sqselected=()
|
|
|
player_clicks=[]
|
|
|
if not move_made:
|
|
|
print("invalid_move",move.get_chess_notation(),move.peice_captured,move.peice_moved)
|
|
|
player_clicks=[sqselected]
|
|
|
if gs.check_mate or gs.steale_mate:
|
|
|
running=False
|
|
|
|
|
|
|
|
|
elif e.type == pygame.KEYDOWN:
|
|
|
if e.key == pygame.K_z:
|
|
|
gs.undo_move()
|
|
|
move_made=True
|
|
|
game_over=False
|
|
|
if ai_thinking:
|
|
|
move_find_process.terminate()
|
|
|
ai_thinking=False
|
|
|
move_undone=True
|
|
|
|
|
|
elif e.key == pygame.K_r:
|
|
|
gs = engine.GameState()
|
|
|
valid_moves=gs.get_valid_moves()
|
|
|
sqselected=()
|
|
|
player_clicks=[]
|
|
|
move_made=False
|
|
|
animate=True
|
|
|
game_over=False
|
|
|
if ai_thinking:
|
|
|
move_find_process.terminate()
|
|
|
ai_thinking=False
|
|
|
move_undone=True
|
|
|
|
|
|
|
|
|
if not game_over and not human_Turn and not move_undone:
|
|
|
if not ai_thinking:
|
|
|
ai_thinking = True
|
|
|
returnQueue = Queue()
|
|
|
move_find_process = Process(target=move_finder.find_best_move,args=(gs,valid_moves,returnQueue))
|
|
|
|
|
|
move_find_process.start()
|
|
|
if not move_find_process.is_alive():
|
|
|
print('done thinking')
|
|
|
move = returnQueue.get()
|
|
|
if move is None:
|
|
|
move = move_finder.random_move(valid_moves)
|
|
|
gs.make_move(move)
|
|
|
move_made = True
|
|
|
animate = True
|
|
|
ai_thinking = False
|
|
|
if move_made:
|
|
|
valid_moves = gs.get_valid_moves()
|
|
|
if animate:
|
|
|
animateMove(gs.moveLog[-1],screen,gs.board,clock)
|
|
|
animate=False
|
|
|
print('valid_moves:',len(valid_moves))
|
|
|
if len(valid_moves)<=5:
|
|
|
for move in valid_moves:
|
|
|
print(move.peice_captured ,move.peice_moved, move.move_id)
|
|
|
|
|
|
move_made=False
|
|
|
move_undone = False
|
|
|
|
|
|
draw_game_state(screen,gs,valid_moves,sqselected)
|
|
|
if gs.check_mate:
|
|
|
game_over=True
|
|
|
if gs.whiteToMove:
|
|
|
draw_end_game_text(screen,'black wins by checkmate')
|
|
|
else:
|
|
|
draw_end_game_text(screen,"white wins by checkmate")
|
|
|
elif gs.steale_mate:
|
|
|
game_over=True
|
|
|
draw_end_game_text(screen,'stealmate no moves for king and no check')
|
|
|
clock.tick(max_fps)
|
|
|
pygame.display.flip()
|
|
|
from pygame.math import Vector2
|
|
|
|
|
|
def animateMove(move, screen, board, clock):
|
|
|
start = Vector2(move.start_col, move.start_row)
|
|
|
end = Vector2(move.end_col, move.end_row)
|
|
|
distance = end.distance_to(start)
|
|
|
frames_per_sq = 10
|
|
|
frame_count = int(distance * frames_per_sq)
|
|
|
|
|
|
for frame in range(frame_count + 1):
|
|
|
t = frame / frame_count
|
|
|
current = start.lerp(end, t)
|
|
|
c, r = current.x, current.y
|
|
|
|
|
|
draw_board(screen)
|
|
|
draw_peices(screen, board)
|
|
|
|
|
|
|
|
|
colour = colors[(move.end_row + move.end_col) & 1]
|
|
|
end_sq = pygame.Rect(move.end_col * sq_size, move.end_row * sq_size, sq_size, sq_size)
|
|
|
pygame.draw.rect(screen, colour, end_sq)
|
|
|
|
|
|
|
|
|
if move.peice_captured != '--':
|
|
|
if move.is_empassant_move:
|
|
|
screen.blit(images[move.peice_captured], end_sq)
|
|
|
else:
|
|
|
screen.blit(images[move.peice_captured], end_sq)
|
|
|
|
|
|
|
|
|
screen.blit(images[move.peice_moved],
|
|
|
pygame.Rect(c * sq_size, r * sq_size, sq_size, sq_size))
|
|
|
|
|
|
pygame.display.flip()
|
|
|
clock.tick(120)
|
|
|
|
|
|
def draw_end_game_text(screen,text):
|
|
|
font = pygame.font.SysFont('Helvitca',32,True,False)
|
|
|
text_object = font.render(text,0,pygame.Color('Gray'))
|
|
|
text_location = pygame.Rect(0,0,width,height).move(width/2,height/2)
|
|
|
screen.blit(text_object,text_location)
|
|
|
text_object = font.render(text,0,pygame.Color('Black'))
|
|
|
screen.blit(text_object,text_location.move(2,2))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__=='__main__':
|
|
|
|
|
|
|
|
|
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|