import chess import chess.svg import pygame import engine from pygame import Vector2 import move_finder from multiprocessing import Process,Queue from final import get_board move_width =200 move_height=0 width,height=512,512 #can be 768,768 dimensions = 8 #chess board is 64 squares sq_size = int(height/dimensions) max_fps=15 images ={} #load images #loading image sis very expensive so load only once per game # board = chess.Board('rnbqkbnr/8/8/8/8/8/8/8') # svg = chess.svg.board(board) # make engine that recognize legal chess move or not #hopefully 2 player game # with open('b.svg', 'w', encoding="utf-8") as f: # f.write(svg) ''' 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(".src/images/"+peice+".png"),(sq_size,sq_size)) #cenetr peice nicely # we can access an peice by calling image['wp] we added them in the dictionary ''' draw squares on board always top left square is white ''' def draw_board(screen): global colors #so that we can use them globally 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 # global scroll variable 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) # Draw background pygame.draw.rect(screen, pygame.Color('black'), move_log_rect) moves = gs.moveLog text_y = 5 - scroll_offset # apply scroll offset here 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 up scroll_offset = max(0, scroll_offset - 20) elif event.button == 5: # scroll down scroll_offset += 20 ''' rensonsible for graphics in current game state ''' def draw_game_state(screen,gs,valid_moves,sq_selected): draw_board(screen) #draw squares on board 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'): #sq selected is a peice # highlight selected square # use surface s = pygame.Surface((sq_size,sq_size)) s.set_alpha(100) # transparent s.fill(pygame.Color('blue')) screen.blit(s,(c*sq_size,r*sq_size)) # highlist moves from that square 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) # transparent 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)) #what the board does is redraw images when u move #animation is simply slow the change such that u see every frame def main(): pygame.init() screen = pygame.display.set_mode((width+move_width,height+move_height)) clock = pygame.time.Clock() #clock screen.fill(pygame.Color('white')) gs = engine.GameState() #create a game state and craete variables load_images() # load only once before whilw running = True sqselected = () player_clicks=[] #two squares of player clicks valid_moves = gs.get_valid_moves() game_over=False player_one = True # white true , machine is playing false player_two = False # similarly but for player two 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 #until the valid move we need not generate valid moves # make ui changes animate=False while running: human_Turn = (gs.whiteToMove and player_one) or (not gs.whiteToMove and player_two) for e in pygame.event.get(): #mouse handler if e.type == pygame.QUIT: running=False elif e.type == pygame.MOUSEBUTTONDOWN: if not game_over and human_Turn: location =pygame.mouse.get_pos() #location of mouse col = int(location[0]//sq_size) row = int(location[1]//sq_size) if sqselected == (row,col) or col>=8: #user click same square then unmove sqselected=() player_clicks=[] else: sqselected = (row,col) player_clicks.append(sqselected) # append for both first and second cicks if len(player_clicks)==2: #after the second click move = engine.Move(player_clicks[0],player_clicks[1],gs.board) for i in range(len(valid_moves)): if move==valid_moves[i]:#move is pretty cheap 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] #after move is doen reset squares if gs.check_mate or gs.steale_mate: running=False #keyboard handlers 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 #reset the board # best moves if not game_over and not human_Turn and not move_undone: if not ai_thinking: ai_thinking = True # threads wont share data returnQueue = Queue() # used to pass data between threads move_find_process = Process(target=move_finder.find_best_move,args=(gs,valid_moves,returnQueue)) # passing function as parameter move_find_process.start() #creates new thread without waiting this code tun 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) #add mouse hnadlers 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 # in [0, 1] current = start.lerp(end, t) # linear interpolation c, r = current.x, current.y draw_board(screen) draw_peices(screen, board) # erase ending square 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) # draw captured piece if any 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) # draw moving piece at interpolated position 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)) def get_moves(image_path): board,fen = get_board(image_path) gs= engine.GameState(board) moves = move_finder.get_best_n_moves(gs) gs.whiteToMove = not gs.whiteToMove moves2 = move_finder.get_best_n_moves(gs) colour = ('white_moves','black_moves') if not gs.whiteToMove else ('black_moves','white_moves') return fen, {colour[0]:moves,colour[1]:moves2} if __name__=='__main__': #handle and update graphics and input #whenever u import this module else where this wont run this fucntion #main() get_moves('./image.png')