Example #1
0
def next_move(board: GameState) -> Move:
    """
        returns best move calculated till timeout
    """
    global timeout, stime, final_move
    initial_depth = 2
    depth_extension_limit = 0
    timeout = 100  # in seconds
    final_move = None
    stime = time()
    assert not board.is_game_over()

    final_score, final_move = next_move_restricted(board,
                                                   max_depth=initial_depth)
    print(f"depth ({initial_depth}) chosen")

    for extension in range(1, depth_extension_limit):
        if time() - stime >= timeout:
            break
        score, move = next_move_restricted(board,
                                           max_depth=initial_depth + extension)
        if move is not None and score >= final_score:
            final_score, final_move = score, move
            print(f"depth ({initial_depth+extension}) chosen")

    return final_move
Example #2
0
def main():
    screen = p.display.set_mode((WIDTH, HEIGHT))
    clock = p.time.Clock()
    screen.fill(p.Color(WHITE))
    gs = GameState()  # gs is the game state
    validMoves = gs.getValidMoves()
    moveMade = False
    loadImages()  # we are only loading the images once in pygame
    running = True
    sqSelected = ()  # keeps track of the last user mouse clicks
    playerClicks = []  # keeps track of the last player clicks
    while running:
        for e in p.event.get():
            if e.type == p.QUIT:
                running = False
            # mouse key handlers
            elif e.type == p.MOUSEBUTTONDOWN:
                location = p.mouse.get_pos()  # location of x and y
                col = location[0] // SQ_SIZE
                row = location[1] // SQ_SIZE
                if sqSelected == (row, col):
                    sqSelected = ()
                    playerClicks = []
                # if the player clicks on a chess piece
                else:
                    sqSelected = (row, col)
                    playerClicks.append(
                        sqSelected
                    )  # this appends both the 1st and the 2nd clicks
                if len(playerClicks) == 2:  # if the user made 2 mouse clicks
                    move = Move(playerClicks[0], playerClicks[1], gs.board)
                    print(
                        str(move.getChessNotation()) + ' id: ' +
                        str(move.moveID))

                    for i in range(len(validMoves)):
                        if move == validMoves[i]:
                            gs.makeMove(validMoves[i])
                            moveMade = True
                            sqSelected = ()
                            playerClicks = []  # resets user clicks
                    if not moveMade:
                        playerClicks = [sqSelected]

            # keyboard handlers
            elif e.type == p.KEYDOWN:
                if e.key == p.K_z:  # the undo key
                    gs.undoMove()
                    moveMade = True

        if moveMade:
            validMoves = gs.getValidMoves()
            moveMade = False

        drawGameState(screen, gs)
        clock.tick(MAX_FPS)
        p.display.flip()
Example #3
0
def main():
    p.init()
    screen = p.display.set_mode((WIDTH, HEIGHT))
    clock = p.time.Clock()
    screen.fill(p.Color("white"))
    gs = GameState()
    valid_moves = gs.get_valid_moves()
    move_made = False  # flag for when a move is made
    load_images()

    sq_selected = ()
    player_clicks = []
    running = True
    while running:
        for event in p.event.get():
            if event.type == p.QUIT:
                running = False
            # mouse handlers
            elif event.type == p.MOUSEBUTTONDOWN:
                mouse_location = p.mouse.get_pos()
                col = mouse_location[0] // SQ_SIZE
                row = mouse_location[1] // SQ_SIZE
                if sq_selected == (
                        row, col):  # the user clicked the same square twice
                    sq_selected = ()  # clear selection
                    player_clicks = []  # clear player clicks
                else:
                    sq_selected = (row, col)
                    # append for both 1st and 2nd clicks
                    player_clicks.append(sq_selected)

                if len(player_clicks) == 2:
                    move = Move(player_clicks[0], player_clicks[1], gs.board)
                    print(move.get_chess_notation())
                    if move in valid_moves:
                        gs.make_move(move)
                        move_made = True
                        sq_selected = ()  # reset user selection
                        player_clicks = []  # reset player clicks
                    else:
                        player_clicks = [sq_selected]
            # key handlers
            elif event.type == p.KEYDOWN:
                if event.key == p.K_u:
                    gs.undo_move()
                    move_made = True
        if move_made:
            valid_moves = gs.get_valid_moves()
            move_made = False

        draw_game_state(screen, gs)
        clock.tick(MAX_FPS)
        p.display.flip()
Example #4
0
def next_move_restricted(board: GameState, max_depth: int) -> Tuple[float, Move]:
    """
        returns best move calculated till depth given
    """
    depth_stime = time()
    global eval_time, moves_cnt, evals_cnt
    eval_time = 0
    moves_cnt = 0
    evals_cnt = 0
    moves = board.getValidMoves()
    length = len(moves)
    step_size = max(1, length//6)
    moves_sets: List[List[Move]] = []
    procs_list: List[Process] = []
    conn_list: List[Connection] = []

    for start in range(0, length, step_size):
        end = start+step_size
        if length-end < step_size:
            end = length
        moves_sets.append(moves[start: end])

    for moves_sb_set in moves_sets:
        par_conn, ch_conn = Pipe()
        p = Process(target=minimax_handler, args=(
            ch_conn, board, moves_sb_set, max_depth))
        p.start()
        procs_list.append(p)
        conn_list.append(par_conn)

    score, move, line = -inf, None, []
    for conn in conn_list:
        curr_score: int = conn.recv()
        curr_move: Move = conn.recv()
        curr_line: List[Move] = conn.recv()
        if curr_score >= score:
            score, move, line = curr_score, curr_move, curr_line

    for p in procs_list:
        p.join()

    line_str = [" " if not move else move.getChessNotation() for move in line]
    print(
        f"depth [{max_depth}] done in {time()-depth_stime} score: {score}"
        f"\ndepth [{max_depth}] {line_str}"
        # f"evals_time : {eval_time}, eval_cnt: {evals_cnt}, moves_cnt: {moves_cnt}"
    )
    if not move:
        return -inf, None
    return score, move
Example #5
0
def minimax(board: GameState, alpha: float, beta: float, maximizer: bool,
            curDepth: int, max_depth: int) -> Tuple[float, Move]:
    """
        returns an integer score and move which is the best current player can get
    """
    if board.is_game_over():
        if board.staleMate:
            return 0, None
        if board.checkMate:
            return (-inf if maximizer else +inf), None
    if curDepth == max_depth:
        return evaluate(board, not (board.whiteToMove ^ maximizer)), None

    # sending inf so that the branch is ignored by parent
    if final_move is not None and time() - stime > timeout:
        return +inf if maximizer else -inf, None

    moves = list(board.getValidMoves())
    # moves.sort(key=move_score, reverse=True)
    assert moves != []
    best_move = None
    if maximizer:
        best_score = -inf

        def is_better_score(curr, currbest):
            return curr >= currbest

        def update_AB(score):
            nonlocal alpha
            alpha = max(alpha, score)

    else:
        best_score = +inf

        def is_better_score(curr, currbest):
            return curr <= currbest

        def update_AB(score):
            nonlocal beta
            beta = min(beta, score)

    for move in moves:
        board.makeMove(move, by_AI=True)
        global moves_cnt
        moves_cnt += 1
        curr_score, _ = minimax(board, alpha, beta, not maximizer,
                                curDepth + 1, max_depth)
        board.undoMove()
        if is_better_score(curr_score, best_score):
            best_score = curr_score
            best_move = move
            update_AB(best_score)
            if alpha >= beta:
                break

    return best_score, best_move
Example #6
0
def minimax(board: GameState, moves: List[Move], alpha: float, beta: float, maximizer: bool, curDepth: int, max_depth: int, moves_line: List[Move]) -> Tuple[float, Move, List[Move]]:
    """
        returns an integer score and move which is the best current player can get
    """
    if board.is_game_over():
        moves_line.append(None)
        if board.staleMate:
            return 0, None, moves_line
        if board.checkMate:
            return (-inf if maximizer else +inf), None, moves_line
    if curDepth == max_depth:
        return evaluate(board, not(board.whiteToMove ^ maximizer)), None, moves_line

    # sending inf so that the branch is ignored by parent
    if final_move is not None and time() - stime > timeout:
        moves_line.append(None)
        return +inf if maximizer else -inf, None, moves_line

    # moves = list(board.getValidMoves())
    assert moves != []
    best_move = None
    best_line = []
    best_score = -inf if maximizer else +inf

    for move in moves:
        board.makeMove(move, by_AI=True)
        moves_line.append(move)
        global moves_cnt
        moves_cnt += 1
        curr_score, _, curr_line = minimax(
            board, board.getValidMoves(), alpha, beta, not maximizer, curDepth+1, max_depth, moves_line[:])
        board.undoMove()
        moves_line.pop()
        if maximizer:
            if curr_score >= best_score:
                best_score, best_move, best_line = curr_score, move, curr_line
            alpha = max(alpha, best_score)
        else:
            if curr_score <= best_score:
                best_score, best_move, best_line = curr_score, move, curr_line
            beta = min(beta, best_score)

        if alpha >= beta:
            break

    return best_score, best_move, best_line