def main(): pygame.init() fps_clock = pygame.time.Clock() pygame.display.set_caption('Checkers') main_board = Board() main_display = Display() spoty = 0 spotx = 0 mousex = 0 mousey = 0 mouse_clicked = False board = main_board.get_newboard() human_player = Player(Colour.WHITE.value, True) ai_player = Player(Colour.RED.value, False) computer = Computer(ai_player, human_player, Colour.RED.value) move = Move() while True: # Main game loop current_player = Player.select_player_with_turn( human_player, ai_player) main_display.update_board(board) if human_player.turn is True: # human player turn is_attacked = human_player.is_piece_attacked( board) # checks if piece is attacked main_display.check_for_quit() for event in pygame.event.get( ): # catch mouseclicks and mouse position if event.type == MOUSEMOTION: mousey, mousex = event.pos if event.type == MOUSEBUTTONUP: spoty, spotx = main_display.get_spot_clicked( board, event.pos[0], event.pos[1]) mouse_clicked = True main_display.highlight_while_hovering(board, main_display, mouse_clicked, mousey, mousex) piece = board[spoty][spotx] if isinstance( piece, Piece ) and piece.colour == human_player.colour and mouse_clicked is True: available_moves, attack = piece.get_all_available_moves(board) has_attacked = False # While loop for handling attack moves. If there's no attack available, this loop is skipped. while any(True in sublist for sublist in available_moves) and attack is True: main_display.highlight_available_moves( available_moves) # displays available attacks event = pygame.event.wait() main_display.check_for_quit() if event.type == MOUSEBUTTONUP: field_to_move_y, field_to_move_x = main_display.get_spot_clicked( board, event.pos[0], event.pos[1]) if available_moves[field_to_move_y][ field_to_move_x] is True: main_display.attack_piece_animation( board, field_to_move_y, field_to_move_x, piece.colour, spoty, spotx) piece.attack_piece(board, field_to_move_y, field_to_move_x) spoty, spotx = field_to_move_y, field_to_move_x if isinstance(piece, Pawn): piece.check_for_promotion(board) available_moves, attack = piece.get_all_available_moves( board) has_attacked = True elif has_attacked is False: break # return to piece selection # while loop for handling non attack moves while any(True in sublist for sublist in available_moves ) and not has_attacked and not is_attacked: main_display.highlight_available_moves(available_moves) event = pygame.event.wait() main_display.check_for_quit() if event.type == MOUSEBUTTONUP: # catch mouseclicks field_to_move_y, field_to_move_x = main_display.get_spot_clicked( board, event.pos[0], event.pos[1]) if available_moves[field_to_move_y][ field_to_move_x] is True: main_display.move_piece_animation( board, field_to_move_y, field_to_move_x, piece.colour, spoty, spotx) piece.make_move(board, field_to_move_y, field_to_move_x) spoty, spotx = field_to_move_y, field_to_move_x if isinstance(piece, Pawn): piece.check_for_promotion(board) # end his turn human_player.switch_turns(human_player, ai_player) mousey, mousex = event.pos available_moves = [[]] else: break # return to piece selection if has_attacked: # end his turn human_player.switch_turns(human_player, ai_player) mousey, mousex = event.pos else: # Computer turn value, best_move = computer.alpha_beta(5, True, -math.inf, math.inf, board) if best_move[4] is not None: move.attack(board, best_move[0], best_move[1], best_move[2], best_move[3], best_move[4]) main_display.draw_computer_highlight(best_move[0], best_move[1]) piece = board[best_move[0]][best_move[1]] if isinstance(piece, Pawn): piece.check_for_promotion(board) can_attack_again = piece.can_piece_attack(board) while can_attack_again is True: # can move after multi-attack, check this function value, best_move = computer.alpha_beta( 5, True, math.inf, -math.inf, board) move.attack(board, best_move[0], best_move[1], best_move[2], best_move[3], best_move[4]) main_display.draw_computer_highlight( best_move[0], best_move[1]) piece = board[best_move[0]][best_move[1]] if isinstance(piece, Pawn): piece.check_for_promotion(board) can_attack_again = piece.can_piece_attack(board) else: # non attack touple doesnt have any fifth item move.move(board, best_move[0], best_move[1], best_move[2], best_move[3]) main_display.draw_computer_highlight(best_move[0], best_move[1]) piece = board[best_move[0]][best_move[1]] if isinstance(piece, Pawn): piece.check_for_promotion(board) ai_player.switch_turns(human_player, ai_player) pygame.display.update() pygame.time.wait(300) # Redraw screen and wait a clock tick. current_player.check_for_victory(board, main_display) mouse_clicked = False pygame.display.update() fps_clock.tick()
def alpha_beta(self, depth, is_maximizing, alpha, beta, board): move = Move() best_move = 0 if depth == 0 or best_move is None: return self.evaluate_board(board, depth), best_move if is_maximizing: best_value = -math.inf ply, move_is_attack = self.computer.get_ply(board) value = -math.inf for child in ply: if move_is_attack: move.attack(board, child[0], child[1], child[2], child[3], child[4]) has_to_attack_again = board[child[0]][ child[1]].can_piece_attack(board) if has_to_attack_again: value, ply = self.alpha_beta(depth - 1, True, alpha, beta, board) if value >= best_value: best_value = value best_move = child else: # attacks only once value, ply = self.alpha_beta(depth - 1, False, alpha, beta, board) if value >= best_value: best_value = value best_move = child move.undo_attack(board, child[0], child[1], child[2], child[3], child[4]) else: # move is not attack move.move(board, child[0], child[1], child[2], child[3]) value, ply = self.alpha_beta(depth - 1, False, alpha, beta, board) if value >= best_value: best_value = value best_move = child move.undo_move(board, child[0], child[1], child[2], child[3]) alpha = max(alpha, value) if alpha >= beta: break return value, best_move else: # is minimizer best_value = math.inf value = math.inf ply, move_is_attack = self.human.get_ply(board) for child in ply: if move_is_attack is True: move.attack(board, child[0], child[1], child[2], child[3], child[4]) has_to_attack_again = board[child[0]][ child[1]].can_piece_attack(board) if has_to_attack_again: value, ply = self.alpha_beta(depth - 1, False, alpha, beta, board) if value < best_value: best_value = value best_move = child else: # attacks only once value, ply = self.alpha_beta(depth - 1, True, alpha, beta, board) if value <= best_value: best_value = value best_move = child move.undo_attack(board, child[0], child[1], child[2], child[3], child[4]) else: # move is not attack move.move(board, child[0], child[1], child[2], child[3]) value, ply = self.alpha_beta(depth - 1, True, alpha, beta, board) if value <= best_value: best_value = value best_move = child move.undo_move(board, child[0], child[1], child[2], child[3]) beta = min(beta, value) if alpha >= beta: break return value, best_move