Example #1
0
def alphabeta_max_node(board, color, alpha, beta, level, limit):
    if board in dp_alphabeta:
        return dp_alphabeta[board]
    if color == 1:
        opponent_color = 2
    else:
        opponent_color = 1

    if len(get_possible_moves(board, color)) == 0 or level == limit:
        return compute_utility(board, color)

    order = []

    #the PQ should return the lowest utility for this node
    for successor in get_possible_moves(board, color):
        temp_board = play_move(board, color, successor[0],
                               successor[1])  #max node is opponent - AI
        heappush(order,
                 (compute_utility(temp_board, opponent_color), temp_board))

    v = -inf
    while order:
        min_util = heappop(order)  #returns a tuple pair
        new_board = min_util[1]  #get the board
        v = max(
            v,
            alphabeta_min_node(new_board, opponent_color, alpha, beta,
                               level + 1, limit))
        if v >= beta:
            dp_alphabeta.update({board: v})
            return v
        alpha = max(alpha, v)

    dp_alphabeta.update({board: v})
    return v
Example #2
0
def select_move_alphabeta(board, color):
    """
    Given a board and a player color, decide on a move.
    The return value is a tuple of integers (i,j), where
    i is the column and j is the row on the board.
    """
    if is_leaf_node(board, color):
        raise Exception("No legal moves allowed")
    else:
        alpha = -1000
        beta = 1000
        moves = get_possible_moves(board, color)
        moves = get_possible_moves(board, color)
        successors_moves = {}

        for move in moves:
            successors_moves[play_move(board, color, move[0], move[1])] = move
        sorted_successors = sorted(successors_moves.keys(), key=lambda x: compute_utility(x, color), reverse=True)

        max_val = -1000
        max_move = ()

        for successor in sorted_successors:
            # successor = play_move(board, color, move[0], move[1])
            val = alphabeta_min_node(successor, color, alpha, beta, 0, 16)
            if val > max_val:
                max_val = val
                max_move = successors_moves[successor]

    return max_move
Example #3
0
def alphabeta_min_node(board, color, alpha, beta, level, limit): 
    """
    Method for min node using alpha beta pruning.
    If a terminal stage is reached, return current utility.
    Else recursively call method for max node on each possible move and do cutoffs/updates.
    """
    
    if limit == level or len(get_possible_moves(board, other_color(color))) == 0:   # terminal state
        return compute_utility(board, color)
    else:
        # order the child states
        ordered_states = []
        for x in get_possible_moves(board, other_color(color)):              # for every possible move of this min node
            next_board = play_move(board, other_color(color), x[0], x[1])    # get the result board of this move
            # put board state with maximum utility at the root of heap
            heappush(ordered_states, (compute_utility(next_board, color), next_board))    
            
        cur = float('inf')                    # keep record the min_max for this min node       
        while(len(ordered_states) != 0):
            max_value = alphabeta_max_node(heappop(ordered_states)[1], color, alpha, beta, level + 1, limit)
            cur = min(cur, max_value)
            if (cur <= alpha):                # min_max has dropped below parent max node's max_min value, cut off
                return cur
            beta = min(beta, cur)             # update current min_max for this node
        return cur                            # cut off didn't occur, return min_max
Example #4
0
def compute_heuristic(board, color):  #not implemented, optional
    # IMPLEMENT
    # Board size
    d = len(board)

    # Minimize the number of disks the opponent
    result = get_score(board)
    if color == 1:
        utility = result[0] - result[1]
    else:
        utility = result[1] - result[0]

    # Minimize the number of moves the opponent can make
    dark_moves = len(get_possible_moves(board, 1))
    light_moves = len(get_possible_moves(board, 2))
    if color == 1:
        mobility = dark_moves - light_moves
    else:
        mobility = light_moves - dark_moves

    # Check board size to prevent index out of range
    if d < 4:
        return utility + mobility

    # Now the rest satisfies board size >= 4
    dark = 0
    light = 0

    # Highly value taking corner fields
    corners = [(0, 0), (d - 1, 0), (0, d - 1), (d - 1, d - 1)]
    for (column, row) in corners:
        if board[column][row] == 1:
            dark += 500
        elif board[column][row] == 2:
            light += 500

    # Highly penalize taking the fields next to the corners
    near_corners = [(1, 0), (0, 1), (1, d - 1), (d - 1, 1), (0, d - 2),
                    (d - 2, 0), (d - 1, d - 2), (d - 2, d - 1)]
    for (column, row) in near_corners:
        if board[column][row] == 1:
            dark -= 50
        elif board[column][row] == 2:
            light -= 50

    # Value other border tiles than remaining tiles
    for i in range(2, d - 2):
        edges = [(0, i), (i, 0), (i, d - 1), (d - 1, i)]
        for (column, row) in edges:
            if board[column][row] == 1:
                dark += 50
            elif board[column][row] == 2:
                light += 50

    if color == 1:
        weight = dark - light
    else:
        weight = light - dark

    return utility + mobility + weight
Example #5
0
def alphabeta_max_node(board, color, alpha, beta, limit, caching = 0, ordering = 0):
    #IMPLEMENT
    # current player is MIN
    global cache
    if color==1: other_color=2
    else: other_color=1
    state = board
    if caching==1:
        if state in cache:
            return cache[state]
    if limit == 0:
        return None, compute_utility(board,color)
    # name ordering heuristics
    if not ordering_heuristic(board,get_possible_moves(board,color),other_color,color,ordering,True):
        # terminal status, return utility value
        res =  None, compute_utility(board, color)
        if caching == 1:
            cache[state] = res
        return res
    best_score = float('-Inf')
    best_move = None
    limit-=1
    for move in ordering_heuristic(board,get_possible_moves(board,color),color,color,ordering,True):
        tmp_move, score = alphabeta_min_node(play_move(board,color, move[0],move[1]), color, alpha, beta, limit, caching)
        if best_score < score:
            best_score = score
            best_move = move
        if beta < best_score:
            beta = best_score
            if beta <= alpha:
                break
    res = best_move, best_score
    if caching == 1:
        cache[state] = res
    return res
Example #6
0
def select_move_alphabeta(board, color, limit, caching=0, ordering=0):
    """
    Given a board and a player color, decide on a move.
    The return value is a tuple of integers (i,j), where
    i is the column and j is the row on the board.

    Note that other parameters are accepted by this function:
    If limit is a positive integer, your code should enfoce a depth limit that is equal to the value of the parameter.
    Search only to nodes at a depth-limit equal to the limit.  If nodes at this level are non-terminal return a heuristic
    value (see compute_utility)
    If caching is ON (i.e. 1), use state caching to reduce the number of state evaluations.
    If caching is OFF (i.e. 0), do NOT use state caching to reduce the number of state evaluations.
    If ordering is ON (i.e. 1), use node ordering to expedite pruning and reduce the number of state evaluations.
    If ordering is OFF (i.e. 0), do NOT use node ordering to expedite pruning and reduce the number of state evaluations.
    """
    #IMPLEMENT
    if get_possible_moves(board, color) == None or limit == 0:
        return compute_utility(board, color)
    global have_seen_this_before
    infinity = float('inf')
    bestval = -infinity
    beta = infinity
    suc_boards = []
    for m in get_possible_moves(board, color):
        suc_boards.append((play_move(board, color, m[0], m[1]), m))
    for state, m in suc_boards:
        move, value = alphabeta_min_node(state, color, bestval, beta,
                                         limit - 1, caching)
        if value > bestval:
            bestval = value
            bestmove = m

    return bestmove  #change this!
Example #7
0
def minimax_max_node(board,
                     color,
                     limit,
                     caching=0):  #returns highest possible utility
    #IMPLEMENT
    if caching == 1:
        if board in have_seen_this_before:
            return ([], have_seen_this_before[board])
    if get_possible_moves(board, color) == []:
        if not board in have_seen_this_before:
            have_seen_this_before[board] = compute_utility(board, color)
        return ([], compute_utility(board, color))
    if limit == 0:
        if not board in have_seen_this_before:
            have_seen_this_before[board] = compute_heuristic(board, color)
        return ([], compute_heuristic(board, color))
    if limit == -1:
        limit = limit
    else:
        limit = limit - 1
    infinity = float('inf')
    maxval = -infinity
    suc_boards = []
    for m in get_possible_moves(board, color):
        suc_boards.append((play_move(board, color, m[0], m[1]), m))
    for state, m in suc_boards:
        a = maxval
        maxval = max(maxval, minimax_min_node(state, color, limit, caching)[1])
        if a != maxval:  #if maxval changed, we store the move
            move = m
    if not board in have_seen_this_before:
        have_seen_this_before[board] = maxval
    return (move, maxval)
Example #8
0
def compute_mobility(board, color):
    dark, light = len(get_possible_moves(board,
                                         1)), len(get_possible_moves(board, 2))
    mobility = dark - light
    if color == 2:
        mobility = -mobility
    return mobility
Example #9
0
def compute_movability(board, color):
    #this function computes movability as a subtraction in the number of possible moves of the players 
    dark, light = len(get_possible_moves(board, 1)), len(get_possible_moves(board,2))

    if color == 1:
        return dark-light
    else:
        return light-dark
Example #10
0
def minimax_max_node(board, color, level):
    if len(get_possible_moves(board,color)) == 0 or level > 2:
        return compute_utility(board, color)
    else:
        lst = []
        for c in get_possible_moves(board,color):
            lst.append(minimax_min_node(play_move(board,color,c[0],c[1]),color, level+1))
        return max(lst)
Example #11
0
def alphabeta_max_node(board, color, alpha, beta, level):
    if len(get_possible_moves(board,color)) == 0 or level > 3:
        return compute_utility(board, color) 
    else: 
        for c in get_possible_moves(board,color):
            new_board = play_move(board,color,c[0],c[1])
            value = alphabeta_min_node(new_board,color,alpha,math.inf,level+1)
            if value > alpha:
                alpha = value   
            if beta > alpha:
                return alpha
        return alpha
Example #12
0
def compute_heuristic(board, color):  # not implemented, optional
    # IMPLEMENT
    weight = 0
    opp_color = 1
    if color == 1:
        opp_color = 2

    sidelen = len(board)

    # Try to restrain opponent moves - mobility
    my_moves = get_possible_moves(board, color)
    opp_moves = get_possible_moves(board, opp_color)
    if my_moves + opp_moves > 0:
        weight += 100 * ((my_moves - opp_moves) / (my_moves + opp_moves))

    # Parity
    score = get_score(board)
    weight += 100 * (compute_utility(board, color) / (score[0] + score[1]))

    # Corners
    my_corners = 0
    opp_corners = 0
    nw_corner = board[0][0]
    ne_corner = board[0][sidelen - 1]
    sw_corner = board[sidelen - 1][0]
    se_corner = board[sidelen - 1][sidelen - 1]
    if nw_corner == color:
        my_corners += 1
    elif nw_corner == opp_color:
        opp_corners += 1

    if ne_corner == color:
        my_corners += 1
    elif ne_corner == opp_color:
        opp_corners += 1

    if sw_corner == color:
        my_corners += 1
    elif sw_corner == opp_color:
        opp_corners += 1

    if se_corner == color:
        my_corners += 1
    elif se_corner == opp_color:
        opp_corners += 1

    if my_corners + opp_corners > 0:
        weight += 100 * ((my_corners - opp_corners) /
                         (my_corners + opp_corners))

    # Stability

    return weight
Example #13
0
def alphabeta_max_node(board, color, alpha, beta):
    if not get_possible_moves(board, color):
        return compute_utility(board, color)
    v = -math.inf
    for a in get_possible_moves(board, color):  #color
        v = max(
            v,
            alphabeta_min_node(play_move(board, color, a[0], a[1]), color,
                               alpha, beta))
        if v >= beta:
            return v
        alpha = max(alpha, v)
    return v
Example #14
0
def minimax_min_node(board, color, limit, caching=0):
    if color == 1:
        possible_moves = get_possible_moves(board, 2)
        if limit == 0 or len(possible_moves) == 0:
            return (None, compute_utility(board, color))
        best_utility = len(board)**2
        best_move = None
        for move in possible_moves:
            board_ = play_move(board, 2, move[0], move[1])
            if caching != 0 and board_ not in board_utility:
                max_node = minimax_max_node(board_, color, limit - 1, caching)
                board_utility[board_] = max_node
                if max_node[1] < best_utility:
                    best_utility = max_node[1]
                    best_move = move
            elif caching != 0 and board_ in board_utility:
                max_node = board_utility[board_]
                if max_node[1] < best_utility:
                    best_utility = max_node[1]
                    best_move = move
            else:
                max_node = minimax_max_node(board_, color, limit - 1, caching)
                if max_node[1] < best_utility:
                    best_utility = max_node[1]
                    best_move = move
        return (best_move, best_utility)
    else:
        possible_moves = get_possible_moves(board, 1)
        if limit == 0 or len(possible_moves) == 0:
            return (None, compute_utility(board, color))
        best_utility = len(board)**2
        best_move = None
        for move in possible_moves:
            board_ = play_move(board, 1, move[0], move[1])
            if caching != 0 and board_ not in board_utility:
                max_node = minimax_max_node(board_, color, limit - 1, caching)
                board_utility[board_] = max_node
                if max_node[1] < best_utility:
                    best_utility = max_node[1]
                    best_move = move
            elif caching != 0 and board_ in board_utility:
                max_node = board_utility[board_]
                if max_node[1] < best_utility:
                    best_utility = max_node[1]
                    best_move = move
            else:
                max_node = minimax_max_node(board_, color, limit - 1, caching)
                if max_node[1] < best_utility:
                    best_utility = max_node[1]
                    best_move = move
        return (best_move, best_utility)
Example #15
0
def alphabeta_min_node(board, color, alpha, beta, level): 
    opp_color = 1 if color==2 else 2
    
    if len(get_possible_moves(board,opp_color)) == 0 or level > 3:
        return compute_utility(board, color)   
    else:        
        for c in get_possible_moves(board,opp_color):
            new_board = play_move(board,opp_color,c[0],c[1])
            value = alphabeta_max_node(new_board,color,-math.inf,beta,level+1)
            if value < beta: 
                beta = value
            if alpha > beta:
                return beta
        return beta
Example #16
0
def alphabeta_min_node(board,
                       color,
                       alpha,
                       beta,
                       limit,
                       caching=0,
                       ordering=0):
    #IMPLEMENT
    max_color = color
    min_color = 3 - color
    if caching == 1:
        if board in have_seen_this_before:
            return ([], have_seen_this_before[board])
    if get_possible_moves(board, min_color) == []:
        if not board in have_seen_this_before:
            have_seen_this_before[board] = compute_utility(board, max_color)
        return ([], compute_utility(board, max_color))
    if limit == 0:
        if not board in have_seen_this_before:
            have_seen_this_before[board] = compute_heuristic(board, max_color)
        return ([], compute_heuristic(board, max_color))
    if limit == -1:
        limit = limit
    else:
        limit = limit - 1
    infinity = float('inf')
    val = infinity
    suc_boards = []
    move = []
    for m in get_possible_moves(board, min_color):
        new_board = play_move(board, min_color, m[0], m[1])
        suc_boards.append((new_board, m, compute_utility(new_board,
                                                         max_color)))
    if ordering == 1:
        suc_boards = sorted(suc_boards, key=lambda x: x[2], reverse=True)
    for state, m, disks in suc_boards:
        a = val
        val = min(
            val,
            alphabeta_max_node(state, max_color, alpha, beta, limit,
                               caching)[1])
        if val <= alpha:
            return (m, val)
        beta = min(beta, val)
        if a != val:
            move = m
    if not board in have_seen_this_before:
        have_seen_this_before[board] = val
    return (move, val)
Example #17
0
def minimax(board, depth, isMaximize, color):
    if depth == 0 or not get_possible_moves(board, color):
        #if not get_possible_moves(board, color):
        score1, score2 = get_score(board)
        if (color == 1):
            return score1, None
        elif (color == 2):
            return score2, None

    newBoards = list()
    moves = dict()

    possibleMoves = get_possible_moves(board, color)
    for i in range(len(possibleMoves)):
        newBoards.append(
            play_move(board, color, possibleMoves[i][0], possibleMoves[i][1]))
        moves[play_move(board, color, possibleMoves[i][0],
                        possibleMoves[i][1])] = possibleMoves[i]

    if isMaximize:
        maxVal = -(float("inf"))
        bestMove = moves[newBoards[0]]
        for i in range(len(newBoards)):
            val, move = minimax(newBoards[i], depth - 1, False, color)
            maxVal = max(maxVal, val)
            #Add the move for return when the new value is better
            if (max(maxVal, val) == val):
                bestMove = moves[newBoards[i]]
                #currentMove = move
            if (color == 1):
                color = 2
            else:
                color = 1
        return maxVal, bestMove
    else:
        minVal = float('inf')
        bestMove = moves[newBoards[0]]
        for i in range(len(newBoards)):
            val, move = minimax(newBoards[i], depth - 1, True, color)
            minVal = min(minVal, val)
            #Add the move for return when the new value is better
            if (min(minVal, val) == val):
                bestMove = moves[newBoards[i]]
                #currentMove = move
            if (color == 1):
                color = 2
            else:
                color = 1
        return minVal, bestMove
Example #18
0
def minimax_max_node(board, color):
    """
    Return the minimum score the MAX player can achieve 
    with any move starting at board. 
    """
    if not get_possible_moves(board, color):
        return compute_utility(board, color)

    alpha = -math.inf
    for i, j in get_possible_moves(board, color):
        new_board = play_move(board, color, i, j)
        utility = minimax_min_node(new_board, color)
        if utility > alpha:
            alpha = utility
    return alpha
Example #19
0
def alphabeta_max_node(board, color, beta, level, limit):
    if not get_possible_moves(board, color):
        return compute_utility(board, color)

    alpha = -math.inf
    for i, j in get_possible_moves(board, color):
        new_board = play_move(board, color, i, j)
        if level + 1 > limit:
            continue
        utility = alphabeta_min_node(new_board, color, alpha, level + 1, limit)
        if utility > alpha:
            alpha = utility
        if alpha > beta:
            return alpha
    return alpha
Example #20
0
def compute_heuristic(board, color):  # not implemented, optional
    # Utility
    utility = compute_utility(board, color)

    dark, light = len(get_possible_moves(board,
                                         1)), len(get_possible_moves(board, 2))
    if color == 1:
        mobility = dark - light
    else:
        mobility = light - dark
    n = len(board)
    if n < 4:
        return utility + mobility
    dark, light = 0, 0
    corners = [(0, 0), (-1, 0), (0, -1), (-1, -1)]
    for (i, j) in corners:
        if board[i][j] == 1:
            dark += 10000
        elif board[i][j] == 2:
            light += 10000
    corner_neighbors = [
        (1, 0),
        (0, 1),
        (0, -2),
        (1, -1),
        (-2, 0),
        (-1, 1),
        (-1, -2),
        (-2, -1),
    ]
    for (i, j) in corner_neighbors:
        if board[i][j] == 1:
            dark -= 100
        elif board[i][j] == 2:
            light -= 100
    if n > 4:
        for i in range(2, n - 2):
            edge_vales = [(0, i), (i, 0), (i, -1), (-1, i)]
            for (row, col) in edge_vales:
                if board[row][col] == 1:
                    dark += 100
                elif board[row][col] == 2:
                    light += 100
    if color == 1:
        score = dark - light
    else:
        score = light - dark
    return utility + mobility + score
Example #21
0
def alphabeta_max_node(board, color, alpha, beta, depth, maxdepth):
    if depth > maxdepth or len(get_possible_moves(board, color)) <= 0:
        if hash(board) not in seen_boards:
            seen_boards.add(hash(board))
            seen_boards_cost[hash(board)] = compute_utility(board, color)

        return seen_boards_cost[hash(board)]
    else:

        nowAlpha = alpha
        bestVal = -3000000000

        bestCheck = []

        for x in get_possible_moves(board, color):
            playedBoard = play_move(board, color, x[0], x[1])
            if playedBoard not in seen_boards_heuristic:
                seen_boards_heuristic.add(playedBoard)
                seen_boards_heuristic_cost[playedBoard] = get_heuristic(
                    playedBoard, color)
            #toCheck = alphabeta_max_node(playedBoard, color, switch_color(currentColor), alpha, nowBeta, depth + 1, maxdepth )
            bestCheck.append(
                (seen_boards_heuristic_cost[playedBoard], playedBoard))

        bestCheck.sort()
        bestCheck.reverse()

        for x, playedBoard in bestCheck:
            #playedBoard = play_move(board, currentColor, x[0], x[1])
            #toCheck = alphabeta_min_node(playedBoard, color, switch_color(currentColor), nowAlpha, beta, depth + 1, maxdepth )

            toCheck = 0
            if playedBoard not in seen_boards_min:
                seen_boards_min.add(playedBoard)
                seen_boards_min_cost[playedBoard] = alphabeta_min_node(
                    playedBoard, color, nowAlpha, beta, depth + 1, maxdepth)

            toCheck = seen_boards_min_cost[playedBoard]
            toCheck += random.randint(-volatile_level, volatile_level)
            if toCheck > bestVal:
                bestVal = toCheck
            if bestVal > nowAlpha:
                nowAlpha = bestVal
            if nowAlpha >= beta:
                break

        #return max(childrenNodes)
        return bestVal
Example #22
0
    def ab(board, player, maxing, maxDepth, depth=0, alpha=-1000, beta=1000):

        if depth == maxDepth:
            return heuristic2(board, color), []

        boards = get_possible_moves(board, player)

        if len(boards) == 0:
            return heuristic2(board, color), []

        if maxing:
            bestScore = -1000
            bestBoard = 0
            bestMove = boards[0]
            for b in boards:
                if time.perf_counter() - startTime >= maxTime:
                    return bestScore, bestMove

                movetoBoard = play_move(board, player, b[0], b[1])

                score, move = ab(movetoBoard, player % 2 + 1, False, maxDepth,
                                 depth + 1, alpha, beta)

                if score > bestScore:
                    bestBoard = movetoBoard
                    bestScore = score
                    bestMove = b

                alpha = max(alpha, bestScore)

                # Alpha Beta Pruning
                if beta <= alpha:
                    break

            return bestScore, bestMove

        else:
            bestScore = 1000
            bestBoard = 0
            bestMove = boards[0]
            for b in boards:
                if time.perf_counter() - startTime >= maxTime:
                    return bestScore, bestMove

                movetoBoard = play_move(board, player, b[0], b[1])

                score, move = ab(movetoBoard, player % 2 + 1, True, maxDepth,
                                 depth + 1, alpha, beta)
                if score < bestScore:
                    bestBoard = movetoBoard
                    bestScore = score
                    bestMove = b

                beta = min(beta, bestScore)

                # Alpha Beta Pruning
                if beta <= alpha:
                    break

            return bestScore, bestMove
Example #23
0
def minimax_min_node(board, color, depth):
    
    other_color = 1 if color == 2 else 2
    possible_moves = get_possible_moves(board, other_color)
    move_states = {move : play_move(board, other_color, move[0], move[1]) for move in possible_moves}
    best_move = None
    best_value = None
    
    if len(possible_moves) > 0:
        if depth <= 3:
            for move, state in move_states.items():
                
                
                if best_move == None or minimax_max_node(state, color, depth + 1) < best_value:
                    best_move = move
                    best_value = minimax_max_node(state, color, depth + 1)
            
            return best_value
            
        else:        
            for move, state in move_states.items():
                
                if best_value == None or compute_utility(state, color) < best_value:
                    best_value = compute_utility(state, color)
            
            return best_value
    return compute_utility(board, color)
Example #24
0
def minimax_min_node(board, color):
    '''returns the value of the min node'''
    opponent = switch_color(color)
    min_val = 1000

    if is_leaf_node(board, opponent):
        if board not in board_values:
            board_values[board] = compute_utility(board, color)
        return board_values[board]

    # if not a leaf node compute minimum of children's maximum
    moves = get_possible_moves(board, opponent)
    successors = []
    #play the moves and get the states
    map(lambda x: successors.append(play_move(board, opponent, x[0], x[1])), moves)
    successors.sort(key=lambda x: compute_utility(x, color))

    for successor in successors:
        if successor not in board_values:
            board_values[successor] = minimax_max_node(successor, color)
        val = board_values[successor]

        min_val = min(min_val, val)

    return min_val
Example #25
0
def alphabeta_max_node(board, color, alpha, beta, level, limit):
    '''returns the value of the node'''
    max_val = -1000

    if is_leaf_node(board, opponent) or level==limit:
        if board not in board_values:
            board_values[board] = compute_utility(board, color)
        return board_values[board]

    # if not a leaf node. Need to compute the maximum of the mimimum of the children nodes
    moves = get_possible_moves(board, color)
    successors = []

    map(lambda x: successors.append(play_move(board, color, x[0], x[1])), moves)
    successors.sort(key=lambda x: compute_utility(x, color), reverse=True)

    for successor in successors:
        # successor = play_move(board, color, move[0], move[1])
        if successor not in board_values:
            board_values[successor] = alphabeta_min_node(successor, color, alpha, beta, level+1, limit)
        val = board_values[successor]


        max_val = max(max_val, val)
        if max_val >= beta:
            return max_val
        alpha = max(alpha, max_val)

    return max_val
Example #26
0
def alphabeta_min_node(board, color, alpha, beta, level, limit):
    '''returns the value of the min node'''
    opponent = switch_color(color)
    min_val = 1000

    if is_leaf_node(board, opponent) or level == limit:
        if board not in board_values:
            board_values[board] = compute_utility(board, color)
        return board_values[board]

    # if not a leaf node compute minimum of children's maximum
    moves = get_possible_moves(board, opponent)

    successors = []
    #play the moves and get the states
    map(lambda x: successors.append(play_move(board, opponent, x[0], x[1])), moves)
    successors.sort(key=lambda x: compute_utility(x, color))

    for successor in successors:
        # successor = play_move(board, opponent, move[0], move[1])
        if successor not in board_values:
            board_values[successor] = alphabeta_max_node(successor, color, alpha, beta, level+1, limit)
        val = board_values[successor]

        min_val = min(min_val, val)
        if min_val <= alpha:
            return min_val
        beta = min(beta, min_val)

    return min_val
 def ai_move(self):
     player_obj = self.players[self.game.current_player]
     try:
         i, j = player_obj.get_move(self.game)
         player = "Dark" if self.game.current_player == 1 else "Light"
         player = "{} {}".format(player_obj.name, player)
         self.log("{}: {},{}".format(player, i, j))
         self.game.play(i, j)
         self.draw_board()
         if not get_possible_moves(self.game.board,
                                   self.game.current_player):
             if get_score(self.game.board)[0] > get_score(
                     self.game.board)[1]:
                 self.shutdown("Dark wins!")
             elif get_score(self.game.board)[0] < get_score(
                     self.game.board)[1]:
                 self.shutdown("White wins!")
             else:
                 self.shutdown("Tie!")
         elif isinstance(self.players[self.game.current_player],
                         AiPlayerInterface):
             self.root.after(1, lambda: self.ai_move())
         else:
             self.root.bind("<Button-1>", lambda e: self.mouse_pressed(e))
     except AiTimeoutError:
         self.shutdown("Game Over, {} lost (timeout)".format(
             player_obj.name))
Example #28
0
def minimax_max_node(board,
                     color,
                     limit,
                     caching=0):  # returns highest possible utility
    # IMPLEMENT
    if caching == 1 and (board, color) in cache_board:
        return cache_board[(board, color)]

    actions = get_possible_moves(board, color)
    if len(actions) == 0 or limit == 0:
        utility = compute_heuristic(board, color)
        if caching:
            cache_board[(board, color)] = (None, utility)
        return (None, utility)

    best_move = None
    value = float('-inf')
    for move in actions:
        new_board = play_move(board, color, move[0], move[1])
        nxt_move, nxt_val = minimax_min_node(new_board, color, limit - 1)

        if value < nxt_val:
            value, best_move = nxt_val, move

    if caching == 1:
        cache_board[(board, color)] = (best_move, value)

    return (best_move, value)
Example #29
0
def minimax_min_node(board, color, limit, caching=0):
    # IMPLEMENT

    if caching == 1 and (board, color) in cache_board:
        return cache_board[(board, color)]

    opponent_color = 1
    if color == 1:
        opponent_color = 2

    actions = get_possible_moves(board, opponent_color)
    if not actions or limit == 0:
        if caching:
            cache_board[(board, color)] = (None,
                                           compute_heuristic(board, color))
        return (None, compute_heuristic(board, color))

    best_move = None
    value = float('inf')

    for move in actions:
        nxt_board = play_move(board, opponent_color, move[0], move[1])
        nxt_move, nxt_val = minimax_max_node(nxt_board, color, limit - 1)
        if value > nxt_val:
            value, best_move = nxt_val, move

    if caching == 1:
        cache_board[(board, color)] = (best_move, value)

    return (best_move, value)
Example #30
0
def alphabeta_max_node(board, color, alpha, beta, level, limit):
    if board in move_dictionary:
        return move_dictionary[board]  # Retrieval from cached board states
    else:
        max_next_nodes = get_possible_moves(board, color)

        utility_list = []
        if (len(max_next_nodes) == 0 or limit <= level):
            return compute_utility(board, color)  # Leaf node reached

        v = float("-inf")
        next_dict = dict()
        for items in max_next_nodes:
            successor_board = play_move(board, color, items[0], items[1])
            next_dict.update(
                {successor_board: compute_utility(successor_board, color)})

        #alpha-beta pruning logic - with node ordering heuristic
        for key in sorted(next_dict, key=next_dict.get):
            v = max(
                v, alphabeta_min_node(key, color, alpha, beta, level + 1,
                                      limit))
            if v >= beta:
                return v
            alpha = max(alpha, v)

        move_dictionary.update({board: v})  #Caching of the board states
        return v