class StudentAI():

    def __init__(self,col,row,p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col,row,p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1:2,2:1}
        self.color = 2

    def get_move(self, move):
        #print(self.color)
        if len(move) != 0:
            self.board.make_move(move,self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)

        #self.train()
        self.simulate_lr(self.color)

        #index = randint(0,len(moves)-1)
        #inner_index =  randint(0,len(moves[index])-1)
        #move = moves[index][inner_index]

        ql = QLearning()
        move = ql.make_action(self.board, moves)
        self.board.make_move(move, self.color)
        self.movecount += 1
        return move
class StudentAI():

    def __init__(self,col,row,p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col,row,p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1:2,2:1}
        self.color = 2
        self.count = 0
    def get_move(self,move):
        if len(move) != 0:
            self.board.make_move(move,self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)
        # index = randint(0,len(moves)-1)
        # inner_index =  randint(0,len(moves[index])-1)
        # move = moves[index][inner_index]
        if len(moves) == 1 and len(moves[0]) == 1:
            move = moves[0][0]
        if self.count < 15:
            mct = MonteCarloTree(self.board, self.color, self.opponent, (10, 0, -10))
            move = mct.get_action(10, 0)
            self.board.make_move(move, self.color)
        else:
            mct = MonteCarloTree(self.board, self.color, self.opponent, (10, 0, -10))
            move = mct.get_action(10, 0)
            self.board.make_move(move, self.color)
        return move
예제 #3
0
class StudentAI():

    def __init__(self,row,col,p):
        self.row = row
        self.col = col
        self.p = p
        self.board = Board(row,col,p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1:2,2:1}
        self.color = 2

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1

        moves = self.board.get_all_possible_moves(self.color)
        tree_depth = 4
        
		# for beta alpha pruning
		alpha = -math.inf
        beta = math.inf
        
		# best moves list
		best_moves = []
        
		# Get best moves
		for row in moves:
예제 #4
0
class ManualAI():
    """
    This class describes the ManualAI.
    """
    def __init__(self, col, row, p):
        """
        Intializes manualAI
        @param row: no of rows in the board
        @param col: no of columns in the board
        @param k: no of rows to be filled with checker pieces at the start
        @return :
        @raise :
        """
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = 2
        self.opponent = {1: 2, 2: 1}  # to switch turns after each turn

    def get_move(self, move):
        """
        get_move function for manualAI called from the gameloop in the main module.
        @param move: A Move object describing the move.
        @return res_move: A Move object describing the move manualAI wants to make. This move is basically console input.
        @raise :
        """
        if move.seq:
            # if move.seq is not an empty list
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)
        #print(moves)
        while True:
            try:
                for i, checker_moves in enumerate(moves):
                    print(i, ':[', end="")
                    for j, move in enumerate(checker_moves):
                        print(j, ":", move, end=", ")
                    print("]")
                index, inner_index = map(
                    lambda x: int(x),
                    input("Select Move {int} {int}: ").split(
                    ))  # input is from console is handled here.
                res_move = moves[index][inner_index]
            except KeyboardInterrupt:
                raise KeyboardInterrupt
            except:
                print('invalid move')
                continue
            else:
                break
        self.board.make_move(res_move, self.color)
        return res_move
    def simulate_lr(self, color):
        # simulate one time
        # record all X features to feature_matrix
        # update the y value accordingly

        print("entering simulations")
        newboard = Board(self.col, self.row, self.p)
        newboard.initialize_game()

        feature_list_b = []
        feature_list_w = []

        win = 0
        ### TODO: Fixing Current move in a new board
        curr_turn = self.opponent[color]

        for turn in range(50):
            if newboard.is_win(color) == color:
                win = 1
                break
            elif newboard.is_win(self.opponent[color]) == self.opponent[color]:
                break
            move = self.minimax_move(newboard.get_all_possible_moves(curr_turn))
            newboard.make_move(move, curr_turn)

            b, w = self.get_X(self.board)
            feature_list_b.append(b)
            feature_list_w.append(w)

            self.feature_matrix = np.append(self.feature_matrix, np.array([b, w]), axis=0)
            print(self.feature_matrix)
            curr_turn = self.opponent[curr_turn]

        else:
            win = 0.5

        # matrix = np.array([feature_list_b, feature_list_w])
        # feature_matrix = np.hstack((matrix, np.zeros((matrix.shape[0], 1))))

        # TODO: Fixing y value update
        if win == 1 and color == 1:
            for fb in feature_list_b:
                index = np.where(fb in self.feature_matrix[:, 0:self.feature_size])
                if index == []:
                    self.feature_matrix = np.append(self.feature_matrix, np.array([b, w]), axis=0)
                self.feature_matrix[index, self.feature_size] += 1

        elif win == 0 and color == 1:
            for fw in feature_list_w:
                index = np.where(fw in self.feature_matrix[:, 0:self.feature_size])
                if index == []:
                    self.feature_matrix = np.append(self.feature_matrix, np.array([b, w]), axis=0)
                self.feature_matrix[index, self.feature_size] += 1

        return win
예제 #6
0
class StudentAI():
    """
    This class describes randomAI
    """
    def __init__(self, col, row, p):
        """
        Intializes randomAI
        @param row: no of rows in the board
        @param col: no of columns in the board
        @param p: no of rows to be filled with checker pieces at the start
        @return :
        @raise :
        """
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}  # to switch turns after each turn
        self.color = 2

    def get_move(self, move):
        """
        get_move function for randomAI called from the gameloop in the main module.
        @param move: A Move object describing the move.
        @return res_move: A Move object describing the move manualAI wants to make. This move is a random move from the set of valid moves.
        @raise :
        """
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)
        index = randint(0, len(moves) - 1)
        inner_index = randint(0, len(moves[index]) - 1)
        move = moves[index][inner_index]
        self.board.make_move(move, self.color)
        return move
예제 #7
0
class StudentAI():

    def __init__(self,col,row,p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col,row,p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1:2,2:1}
        self.color = 2
    def get_move(self,move):
        if len(move) != 0:
            self.board.make_move(move,self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)
        index = randint(0,len(moves)-1)
        inner_index =  randint(0,len(moves[index])-1)
        move = moves[index][inner_index]
        self.board.make_move(move,self.color)
        return move
예제 #8
0
    def simulate(self, player):
        win = 0
        counter = 0
        fake_board = Board(self.col, self.row, self.p)
        self.copy_board(fake_board)
        # print("DIT ME DIEN")
        # fake_board.show_board()
        # totaltime = 0
        while win == 0:
            moves = fake_board.get_all_possible_moves(player)
            if len(moves) == 1:
                index = 0
            elif len(moves) == 0:
                win = self.opponent[player]
                break
            else:
                index = randint(0, len(moves) - 1)
            if len(moves[index]) == 1:
                inner_index = 0
            else:
                inner_index = randint(0, len(moves[index]) - 1)
            move = moves[index][inner_index]
            fake_board.make_move(move, player)
            counter += 1
            # bt = time.time()
            if fake_board.tie_counter >= fake_board.tie_max:
                win = -1
            # totaltime += time.time() - bt
            # print("self.board.is_win():", time.time() - bt)
            player = self.opponent[player]

        # #print("total time is_win:", totaltime)
        # #bt = time.time()
        # for i in range(counter):
        #     self.board.undo()
        # #rint("total time undo:", time.time() - bt)
        # fake_board.show_board()
        return win
예제 #9
0
class StudentAI():
    
    def __init__(self,col,row,p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col,row,p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1:2,2:1}
        self.color = 2

    def get_move(self,move):
        if len(move) != 0:
            self.board.make_move(move,self.opponent[self.color])
        else:
            self.color = 1

        bestVal = -999
        bestMove = None

        # if there is only one move to make, just make the move without evaluating
        possible_moves = self.board.get_all_possible_moves(self.color)
        if len(possible_moves) == 1 and len(possible_moves[0]) == 1:
            self.board.make_move(possible_moves[0][0], self.color)
            return possible_moves[0][0]

        for moves in possible_moves:
            for move in moves:
                self.board.make_move(move, self.color)
                val = self.search(1, StudentAI.switchColors(self.color), MIN, MAX)
                self.board.undo()

                if val > bestVal:
                    bestVal = val
                    bestMove = move

        self.board.make_move(bestMove, self.color)
        return bestMove

    def search(self, depth, currentColor, alpha, beta):
        if depth == 4 or self.board.is_win('B') or self.board.is_win('W'):
            return self.evaluate(currentColor)

        best = MIN if currentColor == self.color else MAX

        for moves in self.board.get_all_possible_moves(currentColor):
            for move in moves:
                self.board.make_move(move, currentColor)
                val = self.search(depth+1, StudentAI.switchColors(currentColor), alpha, beta)
                self.board.undo()
                
                if currentColor == self.color:
                    best = max(best, val)
                    alpha = max(alpha, best)

                elif currentColor != self.color:
                    best = min(best, val)
                    beta = min(beta, best)

                if beta <= alpha:
                    return best

        return best

    def piece_differential(self, currentColor):
        if currentColor == 'B':
            return self.board.black_count - self.board.white_count
        return self.board.white_count - self.board.black_count

    def evaluate(self, currentColor):
        currentColor = 'B' if currentColor == 1 else 'W'
        oppColor = 'W' if currentColor == 'B' else 'B'
        # if we win in this game state, prefer to choose this path
        # if the opponent wins in this game state, stay away from this path
        if self.board.is_win(currentColor):
            return 500
        elif self.board.is_win(oppColor):
            return -500

        piece_location, kings = 0, 0

        for i in range(self.board.row):
            for j in range(self.board.col):
                if (self.board.board[i][j].color == currentColor):
                    if self.board.board[i][j].is_king:
                        kings += 1
                        # we prefer the king to be in the middle of the board
                        if i <= self.row / 2:
                            piece_location += 7 + i
                        else:
                            piece_location += 7 + (self.board.row - i - 1)
                    else:
                        # we prefer the pawns to go to the opponent's side of the board
                        if self.board.board[i][j].color == 'B':
                            piece_location += 5 + i
                        else:
                            piece_location += 5 + (self.board.row - i - 1)
                elif (self.board.board[i][j].color == oppColor):
                    if self.board.board[i][j].is_king:
                        kings -= 1
                        # we prefer the opponent's king to not be in the middle of the board
                        if i <= self.row / 2:
                            piece_location -= 7 + i
                        else:
                            piece_location -= 7 + (self.board.row - i - 1)
                    else:
                        # we prefer the opponent's pawns to not be on our side of the board
                        if self.board.board[i][j].color == 'B':
                            piece_location -= 5 + i
                        else:
                            piece_location -= 5 + (self.board.row - i - 1)

        # if we have more kings, we prefer to play more aggressive
        if kings > 0:
            return piece_location + self.board.row * self.piece_differential(currentColor)
        else:
            return piece_location + self.piece_differential(currentColor)

    @staticmethod
    def switchColors(color):
        if color == 1:
            return 2
        return 1
예제 #10
0
class StudentAI():

    def __init__(self,col,row,p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col,row,p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1:2,2:1}
        self.color = 2

    def get_move(self,move):
        if len(move) != 0:
            self.board.make_move(move,self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)
        index = randint(0,len(moves)-1)
        inner_index =  randint(0,len(moves[index])-1)
        # move = moves[index][inner_index]
        move = self.min_max_recursion(4, True)[0]
        self.board.make_move(move,self.color)
        return move

    def min_max_recursion(self, depth, maximizingPlayer):

        if depth == 0 and self.color == 1:
            return self.board.black_count - self.board.white_count

        elif depth == 0 and self.color == 2:
            return self.board.white_count - self.board.black_count

        maximum = -100
        max_move = ""
        minimum = 100
        min_move = ""
        if maximizingPlayer:
            selfmoves = self.board.get_all_possible_moves(self.color)
            #maximum = -100
            for s_checker_moves in selfmoves:
                for sm in s_checker_moves:
                    self.board.make_move(sm, self.color)
                    Recurs = self.min_max_recursion(depth - 1, False)
                    # print("Recurs: ",Recurs)
                    temp = maximum
                    if type(Recurs) == type(tuple()):
                        maximum = max(maximum, Recurs[1])
                    else:
                        maximum = max(maximum, Recurs)
                    # print("maximum: ",maximum)
                    if temp != maximum:
                        max_move = sm
                    #alpha = max(alpha, Recurs)
                    # print("alpha",alpha)

                    self.board.undo()

                    #if beta <= alpha:
                    #    break
            return (max_move, maximum)

        else:
            #minimum = 100
            oppmoves = self.board.get_all_possible_moves(self.opponent[self.color])
            for o_checker_moves in oppmoves:
                for om in o_checker_moves:
                    self.board.make_move(om, self.opponent[self.color])
                    Recurs = self.min_max_recursion(depth - 1, True)
                    # print("Recurs: ",Recurs)
                    temp = minimum
                    if type(Recurs) == type(tuple()):
                        minimum = min(minimum, Recurs[1])
                    else:
                        minimum = min(minimum, Recurs)
                    # print("minimum: ",minimum)
                    if temp != minimum:
                        min_move = om
                    #beta = min(beta, Recurs)
                    # print("beta: ", beta)

                    self.board.undo()

                    #if beta <= alpha:
                    #    break
            return (min_move, minimum)
예제 #11
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2

        self.root = Node(self.color, -1)
        self.start = None

    def flatten(self, ini_list) -> list:
        return sum(ini_list, [])

    def isTimeLeft(self):
        time = datetime.datetime.now()
        if (time - self.start).seconds < turnTimer:
            return True
        return False

    def select(
        self
    ) -> Node:  #REMINDER: moves is the flattened list of all available moves
        maxNode = self.root
        maxUct = -1
        ptr = self.root
        uct = None
        found = False

        while len(ptr.children) != 0:  #Node is not a leaf node
            moves = self.flatten(self.board.get_all_possible_moves(ptr.color))
            for m in moves:
                found = False
                for c in ptr.children:
                    if not found and m == c.move:
                        uct = c.UCT()
                        if uct > maxUct:
                            maxUct = uct
                            maxNode = c
                        found = True
                if not found:
                    return ptr  #Node is a leaf node, return parent to expand later

            if maxNode.move != -1:
                self.board.make_move(maxNode.move, ptr.color)
            ptr = maxNode

        # Node is leaf node
        return ptr  #Same thing as line 135

    def expand(self, node) -> Node:
        moves = self.flatten(self.board.get_all_possible_moves(node.color))
        toMove = moves[0]

        childrenMoves = []
        for c in node.children:
            childrenMoves.append(c.move.seq)
        for m in moves:
            if childrenMoves.count(
                    m.seq
            ) == 0:  #Get all available moves for node, then find the leaf node to expand
                toMove = m
                break

        child = Node(self.opponent[node.color], toMove, node)
        node.children.append(child)
        return child

    def simulate(self, child):
        players = {1: "B", 2: "W"}
        winner = None
        counter = 0
        color = child.color

        while self.board.is_win(players[color]) == 0:
            moves = self.flatten(self.board.get_all_possible_moves(color))
            if len(moves) != 0:  #player has moves
                i = randint(0, len(moves) - 1)
                self.board.make_move(moves[i], color)
                color = self.opponent[color]
                counter += 1
            else:  #player doesnt have moves, but game hasn't ended yet
                color = self.opponent[color]

        winner = self.board.is_win(players[color])
        while counter != 0:
            self.board.undo()
            counter -= 1
        return winner

    def backProp(self, result, child):
        while child is not None:
            child.upSims()
            if result != child.color:
                child.upWins()
            child = child.parent

    def MCTS(self, moves) -> Move:
        while (self.isTimeLeft()):
            parent = self.select()
            expand = self.expand(parent)  #TODO check if expand() returns None
            result = self.simulate(expand)
            self.backProp(result, expand)

        bestMove = None  # self.root.children[i].move
        if len(self.root.children) == 0:
            index = randint(0, len(moves) - 1)
            bestMove = moves[index]
        else:
            bestWR = -1
            i = 0
            while i != len(self.root.children):
                if self.root.children[i].getWinRate() > bestWR:
                    bestWR = self.root.children[i].getWinRate()
                    bestMove = self.root.children[i].move
                i += 1

        return bestMove

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])

            if self.root.parent is None:  # len(self.root.children) == 0:
                #what if the root.children doesnt contain the one move we wanted?
                # FIX: checking len of self.root.children to moves of self.root
                self.root.move = move
            else:
                i = 0
                while i != len(self.root.children):
                    if self.root.children[i].move == move:
                        break
                    i += 1
                if i != len(self.root.children):
                    self.root = self.root.children[i]
                else:  #no child node: add it
                    new_root = Node(self.color, move, self.root)
                    self.root.children.append(new_root)
                    self.root = new_root

        else:
            self.color = 1
            self.root.color = 1

        self.start = datetime.datetime.now()
        moves = self.flatten(self.board.get_all_possible_moves(
            self.root.color))
        move = self.MCTS(moves)

        self.board.make_move(move,
                             self.root.color)  # PROBLEM LINE: color mismatch
        # update root to move just picked from MCTS
        i = 0
        while i != len(self.root.children):
            if self.root.children[i].move == move:
                break
            i += 1
        self.root = self.root.children[i]
        return move
예제 #12
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        self.ct = 0
        #self.dif_val = False
        self.size = self.col * self.row
        if self.size < 40:  #6x6
            #print(8)
            self.search_depth = 8
        elif self.size < 50:  #7x7
            #print(7)
            self.search_depth = 5
        elif self.size < 80:  #8x8
            #print(6)
            self.search_depth = 4
        else:
            self.search_depth = 4

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[
                self.color])  # Run opponent's move for self.board
        else:
            self.color = 1

        try:
            self.search_depth
        except NameError:
            print("ERROR")
            search_depth = 5

        if self.size < 40:  #6x6
            if self.ct == 5:
                self.search_depth += 1  #9
            elif self.ct == 10:
                self.search_depth += 1  #10
        elif self.size < 50:  #7x7
            if self.ct == 2:
                self.search_depth += 1  #6
            elif self.ct == 5:
                self.search_depth += 1  #7
            if self.ct == 10:
                self.search_depth += 1  #8
            elif self.ct == 15:
                self.search_depth += 1  #9
            elif self.ct == 20:
                self.search_depth += 1  #10
        elif self.size < 80:  #8x8
            if self.ct == 3:
                self.search_depth += 1  #5
            elif self.ct == 5:
                self.search_depth += 1  #6
            elif self.ct == 7:
                self.search_depth += 1  #7
            elif self.ct == 11:
                self.search_depth += 1  #8
        else:
            if self.ct == 10:
                self.search_depth += 1
            elif self.ct == 20:
                self.search_depth += 2

        root = Tree(self.opponent[self.color])  # Tree root
        #print('Detph', self.search_depth, self.ct)
        self.rec_tree(root, self.search_depth)  # Set up tree

        self.rec_min_max_heuristic(root)

        #self.rec_abp_heuristic(root)

        #self.rec_abp_v2(root)

        avail_moves = root.value[list(root.value)[0]]

        #cur_move = avail_moves[randint(0,len(avail_moves)-1)]
        cur_move = avail_moves[0]
        '''
        print("ALL MOVES")
        moves = self.board.get_all_possible_moves(self.color)
        for i, checker_moves in enumerate(moves):
            print(i, ':[', end="")
            for j, move in enumerate(checker_moves):
                print(j, ":", move, end=", ")
            print("]")
        print("AVAIL MOVES")
        #print(avail_moves)
        for i, checker_moves in enumerate(avail_moves):
            print(i, ':[', end="")
            for j, move in enumerate(checker_moves):
                print(j, ":", move, end=", ")
            print("]")
        '''
        #if self.dif_val:
        if debug: print("##########TREE##########")
        self.print_tree(root)
        if debug: print("##########TREE##########")
        #            self.dif_val = False
        self.board.make_move(cur_move, self.color)  # Make the optimal move
        move = cur_move
        return move

    # Board Heuristic
    def board_points(
            self):  # 5 + row number for pawns, 5 + row number + 2 for kings
        king_pts_value = 5 + (
            self.row - 1
        ) + 5  #5 pts for piece, self.row -1 pts for pts at end of board, + 1 for being king

        pts = 0
        b_pawns = set()
        b_kings = set()
        w_pawns = set()
        w_kings = set()
        for i in range(self.row):
            for j in range(self.col):
                checker = self.board.board[i][j]
                if checker.color == "B":  #Black
                    if checker.is_king:
                        b_kings.add((i, j))
                    else:
                        b_pawns.add((i, j))
                elif checker.color == "W":  #White
                    if checker.is_king:
                        w_kings.add((i, j))
                    else:
                        w_pawns.add((i, j))
        # if b_pawns == set():
        #     print("-" * 20)
        #     self.board.show_board()
        # b_pawns = set()
        # b_kings = set()
        # w_pawns = set()
        # w_kings = set()
        # for i in range(self.row):
        #     for j in range(self.col):
        #         checker = self.board.board[i][j]
        #         if checker.color == "B": #Black
        #             if checker.is_king:
        #                 b_kings.add((i,j))
        #             else:
        #                 b_pawns.add((i,j))
        #         elif checker.color == "W": #White
        #             if checker.is_king:
        #                 w_kings.add((i,j))
        #             else:
        #                 w_pawns.add((i,j))

        for pawn in b_pawns:
            pts += 5 + pawn[0]
        for pawn in w_pawns:
            pts -= (5 + (self.row - pawn[0] - 1))
        for king in b_kings:
            pts += king_pts_value
            dist = 0
            for w in w_kings:
                dist += sqrt((king[0] - w[0])**2 + (king[1] - w[1])**2)
            for w in w_pawns:
                dist += sqrt((king[0] - w[0])**2 + (king[1] - w[1])**2)
            if len(w_kings) + len(w_pawns) != 0:
                pts -= dist / (len(w_kings) + len(w_pawns))
        for king in w_kings:
            pts -= king_pts_value
            dist = 0
            for b in b_kings:
                dist += sqrt((king[0] - b[0])**2 + (king[1] - b[1])**2)
            for b in b_pawns:
                dist += sqrt((king[0] - b[0])**2 + (king[1] - b[1])**2)
            if len(b_kings) + len(b_pawns) != 0:
                pts += dist / (len(b_kings) + len(b_pawns))

        #if abs(pts) > 2:
#            self.dif_val = True
#if debug: print(color(root.color), pts, -pts)
        return pts if self.color == 2 else -pts  #BLACK(1) GOES FIRST, so positive points, if self.color == white(2), then return white pieces as positive points

    def print_tree(self, root, level=0):
        if not debug:
            return
        print("\t" * level, color(root.color), root.value, "->", root.move)
        if len(root.children) != 0:  # Not Leaf node
            for child in root.children:
                self.print_tree(child, level + 1)

    def rec_tree(self, root: Tree, level=1):  # Create tree up to depth level
        if level == 0:
            pass
        else:
            if root.move is not None:  # Not root of tree
                self.board.make_move(root.move, root.color)
            # Check if win here maybe?
            avail_moves = self.board.get_all_possible_moves(
                self.opponent[root.color])
            for i in range(len(avail_moves)):
                for j in range(len(avail_moves[i])):
                    # print(root)
                    root.children.append(
                        Tree(self.opponent[root.color], avail_moves[i][j]))
            for child in root.children:
                self.rec_tree(child, level - 1)

            if root.move is not None:
                self.board.undo()

    # MinMax Functions
    def ftu(self, color):  # Function to use (min vs max by color)
        if color == self.color:  # Calculate Max
            return max
        else:  # Calculate Min
            return min

    def min_max(self, children,
                color):  # Returns dict -> {Max/min value: Moves to get here}
        ftu = self.ftu(
            color)  # Use corresponding min or max depending on color
        value_map = {}
        for child in children:
            for v in child.value.keys():
                value_map.setdefault(v, []).append(
                    child.move
                )  # D: {heuristic value: Move to make to get here}
        # print(value_map)
        return {ftu(value_map): value_map[ftu(value_map)]}

    def rec_min_max_heuristic(self,
                              root: Tree):  # Apply min_max heuristic to tree
        if root.move is not None:  # AKA this is root, the move is what opponent made to get here (none so we don't have to redo move on our board)
            self.board.make_move(root.move, root.color)
        if len(root.children) == 0:  # Passed node has no children
            # Evaluate heuristic for board(and return?)
            root.value = {
                self.board_points(): []
            }  # Value will be dict with key = heuristic points and value = all the moves that result in that many points
        else:  # Evaluate rec_heuristic for children, then retrieve values and apply min/max as appropriate
            for child in root.children:
                self.rec_min_max_heuristic(child)
            root.value = self.min_max(root.children, root.color)

        if root.move is not None:
            self.board.undo(
            )  # Undo move to revert action (done for searching) and return to parent

    # AlphaBeta Functions
    def set_alpha_beta(self, root, child, color):
        ftu = self.ftu(color)
        if child.value is None:
            print(child)
        if root.value is None:
            root.value = {}
        if color == self.color:  # Max aka update alpha (This ai's turn)
            # return ftu(alpha, ftu(child.value)), beta
            if root.alpha < ftu(child.value):
                root.alpha = ftu(child.value)
            root.value.setdefault(root.alpha, []).append(child.move)
        else:  # Min aka update beta (Opponent's turn)
            # return alpha, ftu(beta, ftu(child.value))
            if root.beta > ftu(child.value):
                root.beta = ftu(child.value)
            root.value.setdefault(root.beta, []).append(child.move)

    def rec_abp_heuristic(self,
                          root: Tree,
                          alpha=-999,
                          beta=999,
                          level=0):  # Alpha Beta Pruning
        if debug:
            print("\t" * level, color(root.color), "Enter: ", root.value, "->",
                  root.move)
        old_val = root.value
        if root.move is not None:  # AKA this is root, the move is what opponent made to get here (none so we don't have to redo move on our board)
            self.board.make_move(root.move, root.color)
        #self.board.show_board()
        if len(
                root.children
        ) == 0:  # Passed node has no children aka this is lowest level/leaf
            root.value = {self.board_points(): []}
            if debug:
                print("\t" * level, "LEAF: ", root.value, "->", root.move)
        else:  # Evaluate heuristic for child, retrieve value, update alphabeta, continue with next child if appropriate
            root.alpha = alpha
            root.beta = beta

            if debug: print("\t" * 16, "CHILDREN:", end=" ")
            for child in root.children:
                if debug: print(child.move, end=", ")
            if debug: print("(", color(self.opponent[root.color]), ")", sep="")

            for child in root.children:
                if root.alpha >= root.beta:  # Break out of loop once alpha >= beta (Pruning)
                    if debug: print("PRUNING")
                    break
                self.rec_abp_heuristic(child, root.alpha, root.beta, level + 1)
                self.set_alpha_beta(
                    root, child, root.color
                )  # Apply alpha/beta values based on min/max of child to current node
                if debug:
                    print("\t" * level, color(root.color), "New Value: ",
                          root.value, "->", root.move)
        if root.move is not None:
            self.board.undo()
        if debug:
            print("\t" * level, color(root.color), "Exit: ", root.value, "->",
                  root.move)
        #print(max(list(root.value), key = abs), "\t", root.move, "->", root.value)
        #if abs(max(list(root.value), key = abs)) > 2:
        #print("\t" * level, "Enter: ", old_val, "->", root.move)
        #print("\t" * level, "Exit: ", root.value, "->", root.move)

    def rec_abp_v2(self, root: Tree, alpha=-999, beta=999):
        if root.move is not None:  # AKA this is root, the move is what opponent made to get here (none so we don't have to redo move on our board)
            self.board.make_move(root.move, root.color)
        else:
            root.value = {}
        if len(root.children) == 0:
            root.value = self.board_points()
            if root.move is not None:
                self.board.undo()
            return root.value
        else:
            if color == self.color:  #MaximizingPlayer
                #val = -999
                for child in root.children:
                    '''
                    val = max(val, rec_abp_v2(child, alpha, beta))
                    alpha = max(alpha, val)
                    '''
                    val = self.rec_abp_v2(child, alpha, beta)
                    if alpha > val:  #Alpha > Val
                        root.alpha = alpha
                    else:  #Val > Alpha
                        alpha = val
                        if root.move is None:  #Root node, ie save the move to get here
                            root.value.setdefault(alpha, []).append(child.move)
                        root.alpha = alpha
                    if alpha >= beta:
                        break
                if root.move is not None:
                    self.board.undo()
                return alpha
            else:  #Minimizing Player
                #val = 999
                for child in root.children:
                    '''
                    val = min(val, alphabeta(child, alpha, beta))
                    beta = min(val, beta)
                    '''
                    val = self.rec_abp_v2(child, alpha, beta)
                    if beta < val:  #Beta < Val
                        root.beta = beta
                    else:
                        beta = val
                        if root.move is None:
                            root.value.setdefault(beta, []).append(child.move)
                        root.beta = beta
                    if alpha >= beta:
                        break
                if root.move is not None:
                    self.board.undo()
                return beta
예제 #13
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        #---------------------------------#
        self.area = self.row * self.col
        self.count = 0
        if self.area <= 39:
            self.depth = 8
        elif self.area <= 49:
            self.depth = 5
        elif self.area <= 79:
            self.depth = 4
        else:
            self.depth = 4

    #get move of current game state
    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
        #----------------------------------------------------------#
        # MINIMAX GAME TREE SEARCH AGENT
        #----------------------------------------------------------#
        root = MinimaxTree(self.opponent[self.color])
        self.recursive_dfs(root, self.depth)
        self.recursive_minimax(root)
        move_list = root.data[list(root.data)[0]]
        current = move_list[0]
        #self.board.make_move(current, self.color)
        best_mcts_move = current
        move = current
        #----------------------------------------------------------#
        '''
        #returns some random move from the list
        #--- DEBUGGING PURPOSES ---
        moves_user = self.board.get_all_possible_moves(self.color)
        moves_opponent = self.board.get_all_possible_moves(self.opponent[self.color])
        print("---USER MOVES---")
        for item in moves_user:
            for i in item:
                print(i.seq)
        print("---OPPONENT  MOVES---")
        for item in moves_opponent:
            for i in item:
                print(i.seq)

        board_sim = copy.deepcopy(self.board)
        move_sim = moves_user[0]
        print("Simulation Making move:" + str(move_sim))
        board_sim.make_move(move_sim[0], self.color)
        print("----- SIMULATION B -----")
        board_sim.show_board()
        print("Simulation score =" + str(self.board_heuristic(board_sim)))
        print("Terminal? :" + str(board_sim.is_win(self.color)))
        print("----------------------")

        #current2 = Move(moves_user[randint(0, len(moves_user) - 1)])
        #self.board.make_move(list(current2[0]), self.color)
        #print(current2)
        print("AI Making Move:" + str(move))'''
        #----------------------------------------------------------#
        # MONTE CARLO TREE SEARCH AGENT
        #----------------------------------------------------------#
        m_list = self.board.get_all_possible_moves(self.color)
        if len(m_list) == 1:
            self.board.make_move(m_list[0][0], self.color)
            return m_list[0][0]
        root = MonteCarloTree(self.board, self.color, m_list)
        self.board.make_move(best_mcts_move, self.color)
        move = best_mcts_move
        #----------------------------------------------------------#

        return move

        # -------- CHECKERS BOARD HEURISTIC FUNCTION --------#
        #Sources Referred:
        #https://github.com/techwithtim/Python-Checkers-AI/blob/master/checkers/board.py
        #https://www.cs.huji.ac.il/~ai/projects/old/English-Draughts.pd

    @staticmethod
    def check_distance(p1, p2):
        #for two given checker pieces return the distance
        #using the distance formula sqrt((x2-x1)^2 + (y2-y1)^2)
        dist = sqrt(((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2))
        return dist

    def board_heuristic(self, board):
        score = 0
        king_score = 10 + (self.col - 1)

        pawns_b = []  #black pawns
        pawns_w = []  #white pawns
        kings_b = []  #black kings
        kings_w = []  #white kings
        for r in range(self.row):
            for c in range(self.col):
                piece = board.board[r][c]
                if piece.color == "B":
                    if piece.is_king:
                        kings_b.append((r, c))
                    else:
                        pawns_b.append((r, c))
                elif piece.color == "W":
                    if piece.is_king:
                        kings_w.append((r, c))
                    else:
                        pawns_w.append((r, c))

        for pb in pawns_b:
            score = score + pb[0] + 10
        for pw in pawns_w:
            score = score - (10 + (self.row - 1 - pw[0]))

        for kb in kings_b:
            score = score + king_score
            distance = 0

            for kw in kings_w:
                distance = distance + self.check_distance(kb, kw)
            for pw in pawns_w:
                distance = distance + self.check_distance(kb, pw)
            if len(kings_w) + len(pawns_w) != 0:
                score = score - (distance / (len(kings_w) + len(pawns_w)))

        for kw in kings_w:
            score = score + king_score
            distance = 0

            for kb in kings_b:
                distance = distance + self.check_distance(kw, kb)
            for pb in pawns_b:
                distance = distance + self.check_distance(kw, pb)
            if len(kings_b) + len(pawns_b) != 0:
                score = score - (distance / (len(kings_b) + len(pawns_b)))

        if self.color == 2:
            return score
        else:
            return -score

    #Sources Referred:
    #https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/
    def recursive_dfs(self, root: MinimaxTree, depth=1):
        if depth == 0:
            pass
        else:
            if root.move is not None:
                self.board.make_move(root.move, root.color)
            all_moves_list = self.board.get_all_possible_moves(
                self.opponent[root.color])
            for r in range(len(all_moves_list)):
                for c in range(len(all_moves_list[r])):
                    root.child_nodes.append(
                        MinimaxTree(self.opponent[root.color],
                                    all_moves_list[r][c]))
            for node in root.child_nodes:
                self.recursive_dfs(node, depth - 1)
            if root.move is not None:
                self.board.undo()

    #-------- MINIMAX ALGORITHM-------#
    #Sources Referred:
    #https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-1-introduction/?ref=lbp
    #https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-4-alpha-beta-pruning/
    #https://github.com/techwithtim/Python-Checkers-AI/blob/master/minimax/algorithm.py

    def min_or_max(self, color):
        if color == self.color:
            return max
        else:
            return min

    def minimax(self, color, children):
        min_or_max = self.min_or_max(color)
        hash_table = {}
        for child in children:
            for val in child.data.keys():
                hash_table.setdefault(val, []).append(child.move)
        return {min_or_max(hash_table): hash_table[min_or_max(hash_table)]}

    def recursive_minimax(self, root: MinimaxTree):
        if root.move is not None:
            self.board.make_move(root.move, root.color)
        if len(root.child_nodes) == 0:
            root.data = {self.board_heuristic(self.board): []}
        else:
            for node in root.child_nodes:
                self.recursive_minimax(node)
            root.data = self.minimax(root.color, root.child_nodes)

        if root.move is not None:
            self.board.undo()

    # -------- MONTE CARLO TREE SEARCH ALGORITHM-------#
    # Sources Referred:
    # https://www.geeksforgeeks.org/ml-monte-carlo-tree-search-mcts/
    # https://int8.io/monte-carlo-tree-search-beginners-guide/
    # https://www.analyticsvidhya.com/blog/2019/01/monte-carlo-tree-search-introduction-algorithm-deepmind-alphago/

    def simulate(self, board, move):
        #print("SIMULATE")
        #board_sim = copy.deepcopy(board)
        #board_sim.make_move(move, self.color)
        board.make_move(move, self.color)
        score = self.board_heuristic(board)  #board_sim
        return score, board  #,board_sim

    def expansion(self, node: MonteCarloTree):
        #print("EXPANSION")
        #print(node)
        if node.board.is_win(self.color) > 0 or node.board.is_win(
                self.opponent[self.color]) > 0:
            node.expanded = True
            return

        for move_set in node.move_list:
            for move in move_set:
                score, new_board = self.simulate(node.board, move)
                m_list = new_board.get_all_possible_moves(self.color)
                new_mcts_node = MonteCarloTree(new_board, self.color, m_list)
                new_mcts_node.move = move
                new_mcts_node.parent_node = node
                new_mcts_node.board_eval = score
                node.child_nodes.append(new_mcts_node)
                node.board.undo()

        #print("FINAL EXPANSION:")
        #print(node)

    def rollout(self, node: MonteCarloTree, steps=0):
        #print("ROLLOUT")
        #print(node)
        if node.board.is_win(self.color) > 0 or node.board.is_win(
                self.opponent[self.color]) > 0:  #or steps > 1000:
            node.no_of_wins += int(node.board.is_win(self.color))
            node.no_of_steps = steps
            #print("Roll-BACKPROPOGATE")
            self.backpropogate(node)
            return

        while node.board.is_win(self.color) < 1 or node.board.is_win(
                self.opponent[self.color]) < 1:
            self.expansion(node)
            #Recursive Expansion
            children = node.child_nodes
            for child in children:
                if not child.expanded:
                    #print("ROLLOUT RECURSE")
                    self.rollout(child, steps + 1)
                    #print("END ROLLOUT RECURSE")
                    return
                else:
                    pass

    def backpropogate(self, node: MonteCarloTree):
        #print("BACKPROPOGATE")
        #print(node)

        #update UCB1 value too

        if node.parent_node is None:
            #print("reached root node")
            return

        if node.parent_node is not None:
            node.parent_node.ucb1_eval += node.ucb1_eval
            node.parent_node.no_of_wins += node.no_of_wins
            node.parent_node.no_of_steps += node.no_of_steps
            node.board.undo()
            #print("Recurse-BACKPROPOGATE")
            self.backpropogate(node.parent_node)
            #print("End Recurse Backpropogate")

    def monte_carlo_tree_search(self, node: MonteCarloTree):
        #print("MCTS SEARCH START")
        self.expansion(node)
        #print(node)
        for nd in node.child_nodes:  #should be a while loop, and always start from the root
            self.rollout(nd)
            root_wins = node.no_of_wins
            self.ucb1_evaluation(root_wins, nd)
        best_child = self.choose_best_child(node)
        return best_child.move

    def choose_best_child(self, node: MonteCarloTree):
        children = sorted(node.child_nodes,
                          key=attrgetter('ucb1_eval'),
                          reverse=True)
        return children[0]

    def ucb1_evaluation(self, no_of_wins_r, node: MonteCarloTree):
        #print("No. of steps = " + str(node.no_of_steps))
        #print("No. of wins at root = " + str(no_of_wins_r))
        #print("No. of wins at this node = " + str(node.no_of_wins))
        node.ucb1_eval = node.no_of_steps + 2 * math.sqrt(
            (math.log(no_of_wins_r)) / (node.no_of_wins + 1))
        return

    '''
예제 #14
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        self.movecount = 1

        self.file = f"{self.col}-{self.row}-{self.color}-{randint(0, 500)}-test.txt"
        self.start = time.time()

        self.theta1, self.theta2 = self.get_theta()
        self.cutoff = self.get_cutoff()

        # self.theta = [8.61043154e+00,  4.48291855e+00,  7.78473553e+00, -7.07767178e-14,2.06230092e+00,  1.18768964e+00]#, 0]
        # self.theta = [-24.13, -7.87, -17.89, -16.67, -6.99, 7.22, 1.19, 0.72,
        #               -4.2, -4.52, -2.49, -3.14, 5.69, 0.02, 3.53, -3.58, 9.37,
        #               -3.81, -1.58, -1.75, 2.51, 0.26, 18.3, 10.25, 3.63,
        #               3.69, 1.32, -4.03]
        # self.theta = [-57.35, -6.41, -2.09, -38.9, -3.91, 6.48, 11.97, -0.39, 27.23, 11.11, -22.04, -11.36, 39.62, -41.32,
        #    55.17, 24.54, 16.05, 12.08, 10.46, -17.8, 5.61, -7.38, 48.46, 20.26, 4.3, 2.54, 0.0, 0.0]
        # self.theta77 = [-1.49, 0.41, 0.0, -0.19, -0.07, 0.25, 0.13, 0.0, 0.0, 0.09, -0.28, -0.53, 3.83, -3.95,
        #     1.88, 0.93, 0.08, 0.25, 0.17, 0.0, -0.22, 0.0, -0.24, -0.2, -0.02, 0.03, 0.0, 0.0]
        # self.theta98 = [-1.76, -0.4, 0.03, -0.08, 0.16, 0.3, 0.16, 0.55, -0.38, -0.17, -0.12, 0.28, 2.8, -2.77,
        #     1.82, 0.82, 0.22, 0.1, 0.09, -0.38, -0.09, -1.31, 0.78, 0.42, -0.02, 0.15, 0.0, 0.0]

    def get_move(self, move):
        print(self.color)

        self.time = time.time()
        # if self.time - self.start > 400:
        #     self.depth = 4
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)

        self.depth = self.get_depth()
        # index = randint(0,len(moves)-1)
        # inner_index =  randint(0,len(moves[index])-1)
        # move = moves[index][inner_index]
        # print(moves)
        move = moves[0][0] if len(moves) == 1 and len(
            moves[0]) == 1 else self.minimax_move(moves)
        self.board.make_move(move, self.color)
        self.movecount += 1
        # with open(self.file, 'a') as f:
        #     f.write(f"Movecount:{self.movecount} Total time:{time.time()-self.start} This move takes:{time.time()-self.time} Depth:{self.depth}\n")
        return move

    def get_cutoff(self):
        if self.row == 7 and self.col == 7:
            return (5, 3)
        else:
            return (6, 3)

    def get_depth(self):
        if self.row == 7 and self.col == 7:
            return 0
        else:
            return 4

    def get_theta(self):
        theta771_start = [
            -3.05, -1.9, 0.04, -0.85, -0.06, 0.43, 0.21, 0.0, -0.18, 0.56,
            -0.32, -0.25, 2.9, -2.56, 1.23, 0.06, 0.44, 0.89, 0.67, 0.27, -0.0,
            0.0, 0.64, 0.56, 0.07, 0.91, 0.0, 0.0
        ]
        theta771_mid = [
            -2.84, -1.09, -0.05, -0.67, 0.22, 0.42, 0.24, 0.0, -0.18, 0.72,
            0.26, 0.38, 3.44, -2.88, 1.83, 0.04, 0.3, 0.79, 0.11, -0.02, -0.14,
            0.0, 0.36, 0.3, -0.45, 0.9, 0.0, 0.0
        ]
        theta771_last = [
            -3.01, -1.01, -0.06, 0.13, 0.42, 0.18, 0.03, 0.0, -0.51, 0.75,
            1.31, 1.26, 2.86, -2.55, 1.5, 0.22, 0.05, 0.42, 0.2, -0.06, -0.16,
            0.0, 0.53, 0.45, -0.26, 0.44, 0.0, 0.0
        ]

        theta772_start = [
            2.07, -0.44, 0.29, 0.45, 0.32, -0.46, -0.04, 0.0, 0.37, -0.25,
            0.16, 0.17, 0.0, 0.0, -2.18, -0.62, -0.16, -1.0, 0.24, 0.72, 0.2,
            0.0, 0.12, 0.04, 0.75, -1.29, 3.36, -2.93
        ]
        theta772_mid = [
            1.93, 0.09, 0.16, 0.37, 0.28, -0.18, -0.17, 0.0, 0.02, -0.28, 0.02,
            0.13, 0.0, 0.0, -2.3, -1.12, -0.07, -0.63, 0.38, 0.08, 0.16, 0.0,
            -0.4, 0.43, 0.54, -0.74, 3.47, -3.05
        ]
        theta772_last = [
            1.51, 0.44, -0.01, 0.11, 0.16, -0.16, -0.14, 0.0, -0.17, 0.47,
            -0.16, 0.02, 0.0, 0.0, -2.79, -0.98, 0.0, 0.14, 0.4, -0.08, 0.0,
            0.0, -0.26, 1.25, 0.06, -0.07, 2.32, -2.19
        ]

        theta981_start = [
            -2.85, -0.22, 0.11, -0.54, 0.31, -0.03, 0.07, 0.0, -0.19, 0.45,
            -0.17, 0.45, 2.09, -1.88, 2.46, 1.24, -0.04, 0.64, 0.41, -0.36,
            0.11, 0.25, -0.01, 0.09, -0.34, 0.96, 0.0, 0.0
        ]
        theta981_mid = [
            -1.95, -1.35, 0.11, -0.44, 0.11, 0.16, 0.02, 0.0, -0.18, 0.57,
            0.26, 0.54, 2.37, -2.06, 1.22, -0.19, 0.3, 0.9, 0.43, 0.09, 0.05,
            -0.06, 0.19, 0.19, -0.04, 0.69, 0.0, 0.0
        ]
        theta981_last = [
            -3.22, -1.85, 0.18, 0.48, 0.23, 0.14, -0.18, 0.0, -0.53, 1.25,
            0.93, 0.03, 3.33, -3.01, 2.08, 0.05, 0.15, 0.65, 0.27, 0.03, -0.13,
            -1.0, -0.24, -0.25, 0.01, 0.03, 0.0, 0.0
        ]

        theta982_start = [
            1.47, -0.0, 0.21, 0.5, 0.09, -0.09, 0.05, 0.0, 0.12, -0.45, 0.15,
            0.55, 0.0, 0.0, -2.5, -0.49, 0.05, -0.45, 0.24, 0.24, 0.29, 0.29,
            0.02, 0.12, 0.26, -0.26, 2.31, -2.11
        ]
        theta982_mid = [
            1.22, -0.16, 0.29, 0.22, 0.28, -0.21, -0.05, 0.0, 0.38, -0.24,
            -0.31, 0.59, 0.0, 0.0, -2.04, -1.22, 0.14, -0.54, 0.12, -0.07,
            0.05, -0.04, 0.31, 0.57, 0.41, -0.88, 3.14, -2.84
        ]
        theta982_last = [
            2.12, -0.19, 0.19, -0.23, 0.33, -0.17, -0.11, 0.0, -0.44, 0.32,
            0.16, 0.0, 0.0, 0.0, -2.06, -1.58, 0.09, -0.16, 0.46, -0.19, 0.0,
            -0.94, -0.7, 0.74, 1.33, -0.08, 4.14, -3.98
        ]

        if self.row == 7 and self.col == 7:
            return (theta771_start, theta771_mid,
                    theta771_last), (theta772_start, theta772_mid,
                                     theta772_last)
        else:
            return (theta981_start, theta981_mid,
                    theta981_last), (theta982_start, theta982_mid,
                                     theta982_last)

    def minimax_move(self, moves: [list]):
        best = []
        max_value = -math.inf
        for chess in moves:
            for move in chess:
                val = self.min_value(move, self.depth, -math.inf, math.inf)
                if val > max_value:
                    best = [move]
                    max_value = val
                elif val == max_value:
                    best.append(move)
        return best[0]

    def min_value(self, move, depth, alpha, beta):
        self.board.make_move(move, self.color)

        if depth == 0:
            u = self.utility(self.board, self.color)
            print(u)
            self.board.undo()
            return u

        moves = self.board.get_all_possible_moves(self.opponent[self.color])
        moves = [m for sub in moves for m in sub]
        # moves = self.reorder(self.get_u_list(moves, self.board, self.opponent[self.color]), reverse = False)

        if len(moves) == 0:
            u = +1000
            self.board.undo()
            return u

        min_val = math.inf
        for move in moves:
            min_val = min(self.max_value(move, depth - 1, alpha, beta),
                          min_val)
            beta = min(beta, min_val)
            if alpha >= beta:
                self.board.undo()
                return min_val
        self.board.undo()
        return min_val

    def max_value(self, move, depth, alpha, beta):
        self.board.make_move(move, self.opponent[self.color])

        if depth == 0:
            u = self.utility(self.board, self.opponent[self.color])
            print(u)
            self.board.undo()
            return u

        moves = self.board.get_all_possible_moves(self.color)
        moves = [m for sub in moves for m in sub]
        # moves = self.reorder(self.get_u_list(moves, self.board, self.color), reverse = True)

        if len(moves) == 0:
            u = -1000
            self.board.undo()
            return u

        max_val = -math.inf
        for move in moves:
            max_val = max(self.min_value(move, depth - 1, alpha, beta),
                          max_val)
            alpha = max(alpha, max_val)
            if alpha >= beta:
                self.board.undo()
                return max_val
        self.board.undo()
        return max_val

    def u_after_move(self, move, board, color):
        board.make_move(move, color)
        u = self.utility(board, color)
        board.undo()
        return u

    def get_u_list(self, moves, board, color):
        u_list = {}
        for chess in moves:
            for move in chess:
                u_list[move] = self.u_after_move(move, board, color)
        return u_list

    def reorder(self, u_list, reverse):
        return sorted(u_list, key=lambda x: u_list[x], reverse=reverse)

    def utility(self, board, color):
        wking, bking = self.wking_bking(board)
        wcount, bcount = self.wcount_bcount(board)
        wdis, bdis = self.wdis_bdis(board)
        wedge, bedge = self.wedge_bedge(board)
        wcenter, bcenter = self.wcenter_bcenter(board)
        wback, bback = self.wback_bback(board)

        wdiag, bdiag = self.wdiag_bdiag(board)
        wdog, bdog = self.wdog_bdog(board)
        wbridge, bbridge = self.wbridge_bbridge(board)
        wuptriangle, buptriangle = self.wuptriangle_buptriangle(board)
        wdowntriangle, bdowntriangle = self.wdowntriangle_bdowntriangle(board)
        woreo, boreo = self.woreo_boreo(board)
        board.show_board()
        if color == 1:
            wmoveable, weatable = self.moveables(board, 2)
            bmoveable, beatable = 0, 0
        else:
            wmoveable, weatable = 0, 0
            bmoveable, beatable = self.moveables(board, 1)

        if self.color == 1:
            features = [
                wcount, wking, wdis, wback, wedge, wcenter, wdiag, wdog,
                wbridge, wuptriangle, wdowntriangle, woreo, wmoveable,
                weatable, bcount, bking, bdis, bback, bedge, bcenter, bdiag,
                bdog, bbridge, buptriangle, bdowntriangle, boreo, bmoveable,
                beatable
            ]
            print(str([i for i in features]))
            if bcount > self.cutoff[0]:
                return sum(x * t for x, t in zip(features, self.theta1[0]))
            elif self.cutoff[1] < bcount <= self.cutoff[0]:
                return sum(x * t for x, t in zip(features, self.theta1[1]))
            else:
                return sum(x * t for x, t in zip(features, self.theta1[2]))

        else:
            features = [
                wcount, wking, wdis, wback, wedge, wcenter, wdiag, wdog,
                wbridge, wuptriangle, wdowntriangle, woreo, wmoveable,
                weatable, bcount, bking, bdis, bback, bedge, bcenter, bdiag,
                bdog, bbridge, buptriangle, bdowntriangle, boreo, bmoveable,
                beatable
            ]
            print(str([i for i in features]))
            if wcount > self.cutoff[0]:
                return sum(x * t for x, t in zip(features, self.theta2[0]))
            elif self.cutoff[1] < wcount <= self.cutoff[0]:
                return sum(x * t for x, t in zip(features, self.theta2[1]))
            else:
                return sum(x * t for x, t in zip(features, self.theta2[2]))

    def features(self, board, color):
        '''
        :param board:
        :return: white_features, black_features
            features order = [count, king, dis, back, edge,
                            center, diag, dog, bridge, uptriangle,
                            downtriangle, oreo, moveable, eatable]
        '''
        wfeature = [0 for _ in range(14)]
        bfeature = [0 for _ in range(14)]
        wfeature[0], bfeature[0] = board.white_count, board.black_count

        for r in range(board.row):
            # count edge
            wfeature[4] += (board.board[r][0].color == "W") + (
                board.board[r][board.col - 1].color == "W")
            bfeature[4] += (board.board[r][0].color == "B") + (
                board.board[r][board.col - 1].color == "B")

            for c in range(board.col):
                wfeature[3] += (board.board[board.row - 1][c].color == "B"
                                )  # count back
                bfeature[3] += (board.board[0][c].color == "B")  # count back

                wfeature[5] += (board.board[int(
                    board.row / 2)][c].color == "W") + (
                        board.board[int(board.row / 2) + 1][c].color == "W"
                    )  # count center
                bfeature[5] += (board.board[int(
                    board.row / 2)][c].color == "B") + (
                        board.board[int(board.row / 2) + 1][c].color == "B"
                    )  # count center

                if board.board[r][c].color == 'W':
                    if board.board[r][c].is_king:
                        wfeature[1] += 1  # count king
                    wfeature[2] += board.row - 1 - r  # count dis
                elif board.board[r][c].color == 'B':
                    if board.board[r][c].is_king:
                        bfeature[1] += 1  # count king
                    bfeature[2] += r  # count dis

    def wcount_bcount(self, board):
        return board.white_count, board.black_count

    def wking_bking(self, board):
        bking, wking = 0, 0
        for r in range(self.board.row):
            for c in range(self.board.col):
                if self.board.board[r][c].color == "B":
                    bking += self.board.board[r][c].is_king
                elif self.board.board[r][c].color == "W":
                    wking += self.board.board[r][c].is_king
        return wking, bking

    def moveables(self, board, color):
        moves = [
            m for chess in board.get_all_possible_moves(color) for m in chess
        ]
        eatable = 0
        for m in moves:
            if len(m.seq) > 2:
                eatable += (len(m.seq) - 1)
                continue
            if math.sqrt((m.seq[0][0] - m.seq[1][0])**2 +
                         (m.seq[0][1] - m.seq[1][1])**2) > 1:
                eatable += 1
        # print(f"len(moves): {len(moves)}, eatable: {eatable}")
        return len(moves), eatable

    def wback_bback(self, board):
        bback = sum(board.board[0][i].color == "B" for i in range(board.col))
        wback = sum(board.board[board.row - 1][i].color == "W"
                    for i in range(board.col))
        return wback, bback

    def wedge_bedge(self, board):
        bedge = sum((board.board[i][0].color == "B") +
                    (board.board[i][board.col - 1].color == "B")
                    for i in range(board.row))
        wedge = sum((board.board[i][0].color == "W") +
                    (board.board[i][board.col - 1].color == "W")
                    for i in range(board.row))
        # print(f"wedge: {wedge}, bedge: {bedge}")
        return wedge, bedge

    def wcenter_bcenter(self, board):
        wcenter = sum((board.board[int(board.row / 2)][i].color == "W") + \
                      (board.board[int(board.row / 2) + 1][i].color == "W") for i in range(board.col))
        bcenter = sum((board.board[int(board.row / 2)][i].color == "B") + \
                      (board.board[int(board.row / 2) + 1][i].color == "B") for i in range(board.col))
        # print(f"wcenter: {wcenter}, bcenter: {bcenter}")
        return wcenter, bcenter

    def wdiagonal_bdiagonal(self, board):
        bdiagonal = sum(board.board[i][i].color == "B" for i in range(board.row // 4, 3 * board.row // 4)) + \
                    sum(board.board[board.row - 1 - i][board.row - 1 - i].color == "B" for i in range(board.row))
        wdiagonal = sum(board.board[i][i].color == "W" for i in range(board.row)) + \
                    sum(board.board[board.row - 1 - i][board.row - 1 - i].color == "W" for i in range(board.row))
        # print(f"wdiagonal: {wdiagonal}, bdiagonal: {bdiagonal}")
        return wdiagonal, bdiagonal

    def wdiag_bdiag(self, board):
        bc, wc = 0, 0
        for r in range(board.row - 1):
            bc += (board.board[r][r].color == "B") + (board.board[r + 1][r].color == "B") + (
                    board.board[r][r + 1].color == "B") \
                  + (board.board[r][board.col - 1 - r].color == "B") + (
                          board.board[r + 1][board.col - 1 - r].color == "B") + \
                  (board.board[r][board.col - 2 - r].color == "B")

            wc += (board.board[r][r].color == "W") + (board.board[r + 1][r].color == "W") + (
                    board.board[r][r + 1].color == "W") \
                  + (board.board[r][board.col - 1 - r].color == "W") + (
                          board.board[r + 1][board.col - 1 - r].color == "W") + \
                  (board.board[r][board.col - 2 - r].color == "W")
        bc += (board.board[board.row - 1][0].color == "B") + (
            board.board[board.row - 1][board.row - 1].color == "B")
        wc += (board.board[board.row - 1][0].color == "W") + (
            board.board[board.row - 1][board.row - 1].color == "W")

        # print(f"wdiag: {wc}, bdiag: {bc}")
        return wc, bc

    def wdog_bdog(self, board):
        wc = (board.board[board.row - 1][board.col - 1].color == "." and board.board[board.row - 1][
            board.col - 2].color == "W" \
              and board.board[board.row - 2][board.col - 1].color == "B") + \
             (board.board[board.row - 1][0].color == "." and board.board[board.row - 1][1].color == "W" \
              and board.board[board.row - 2][0].color == "B")

        bc = (board.board[0][0].color == "." and board.board[0][1].color == "B" \
              and board.board[1][0].color == "W") + \
             (board.board[0][board.col - 1].color == "." and board.board[0][board.col - 2].color == "B" \
              and board.board[1][board.col - 1].color == "W")
        # print(f"wdog: {wc}, bdog: {bc}")
        return wc, bc

    def wbridge_bbridge(self, board):
        bc = sum(
            board.board[0][c].color == "B" and board.board[0][c +
                                                              2].color == "B"
            for c in range(1, board.col - 3))
        wc = sum(board.board[board.row - 1][c].color == "W"
                 and board.board[board.row - 1][c + 2].color == "W"
                 for c in range(1, board.col - 3))
        # print(f"wbridge: {wc}, bbridge: {bc}")
        return wc, bc

    def wuptriangle_buptriangle(self, board):
        bcount, wcount = 0, 0
        for r in range(1, board.row - 1):
            for c in range(board.col - 2):
                if board.board[r][c].color == "B" and board.board[r - 1][
                        c + 1].color == "B" and board.board[r][c +
                                                               2].color == "B":
                    bcount += 1
                if board.board[r][c].color == "W" and board.board[r - 1][
                        c + 1].color == "W" and board.board[r][c +
                                                               2].color == "W":
                    wcount += 1
        # print(f"wuptriangle: {wcount}, buptriangle: {bcount}")
        return wcount, bcount

    def wdowntriangle_bdowntriangle(self, board):
        bcount, wcount = 0, 0
        for r in range(board.row - 1):
            for c in range(board.col - 2):
                if board.board[r][c].color == "B" and board.board[r + 1][
                        c + 1].color == "B" and board.board[r][c +
                                                               2].color == "B":
                    bcount += 1
                if board.board[r][c].color == "W" and board.board[r + 1][
                        c + 1].color == "W" and board.board[r][c +
                                                               2].color == "W":
                    wcount += 1
        # print(f"wdowntriangle: {wcount}, bdowntriangle: {bcount}")
        return wcount, bcount

    def woreo_boreo(self, board):
        '''
        :param board:
        :return: triangle pattern in the last row
        '''
        boreo = sum(board.board[0][c].color == "B" and board.board[1][c + 1].color == "B" \
                    and board.board[0][c + 2].color == "B" for c in range(0, board.col - 2))
        woreo = sum(board.board[board.row - 1][c].color == "W" and board.board[board.row - 2][c + 1].color == "W" \
                    and board.board[board.row - 1][c + 2].color == "W" for c in range(0, board.col - 2))
        # print(f"woreo: {woreo}, boreo: {boreo}")
        return woreo, boreo

    def wdis_bdis(self, board):
        wdis = sum(board.row - 1 - i for i in range(board.row)
                   for j in range(board.col) if board.board[i][j].color == "W")
        bdis = sum(i for i in range(board.row) for j in range(board.col)
                   if board.board[i][j].color == "B")
        return wdis, bdis
예제 #15
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[
                self.color])  # Run opponent's move for self.board
        else:
            self.color = 1

        root = Tree(self.opponent[self.color])  #Tree root
        self.rec_tree(root, search_depth)  #Set up tree
        self.rec_min_max_heuristic(root)

        avail_moves = root.value[list(root.value)[0]]
        #cur_move = avail_moves[0]
        cur_move = avail_moves[randint(0, len(avail_moves) - 1)]
        #print(avail_moves)

        self.board.make_move(cur_move, self.color)  # Make the optimal move
        move = cur_move
        return move

    def ftu(self, color):  #Function to use (min vs max by color)
        if color == self.color:  # Calculate Min
            return max
        else:  # Calculate Max
            return min

    def min_max(self, children,
                color):  # Returns dict -> {Max/min value: Moves to get here}
        ftu = self.ftu(color)  #Use corresponding min or max depending on color
        value_map = {}
        for child in children:
            for v in child.value.keys():
                value_map.setdefault(v, []).append(
                    child.move
                )  # D: {heuristic value: Move to make to get here}
        # print(value_map)
        return {ftu(value_map): value_map[ftu(value_map)]}

    def board_points(
            self):  # 5 + row number for pawns, 5 + row number + 2 for kings
        '''
        def board_points(self):  # 5 + row number for pawns, 5 + row number + 2 for kings
            king_pts_value = 5 + (
                        self.row - 1) + 2  # 5 pts for piece, self.row -1 pts for pts at end of board, + 1 for being king
            pts = 0
            for i in range(self.row):
                for j in range(self.col):
                    checker = self.board.board[i][j]
                    if checker.color == 'B':  # For black side pieces
                        if checker.is_king:
                            pts += king_pts_value
                        else:
                            pts += 5 + checker.row
                    elif checker.color == 'W':  # FOr white side pieces
                        # pts -= (11 - checker.row)  # 5 + (6 - Row)
                        if checker.is_king:
                            pts -= king_pts_value
                        else:
                            pts -= (5 + (
                                        self.row - checker.row - 1))  # 5 + (Num of rows - Row - 1) eg. 5x5 board, 5th row is 5(num) - 4(row) -1 = 0

            if abs(pts) > 2:
                self.dif_val = True
            # if debug: print(color(root.color), pts, -pts)
            return pts if self.color == 1 else -pts  # BLACK(1) GOES FIRST, so positive points, if self.color == white(2), then return white pieces as positive points
            '''
        pts = 0
        for i in range(self.row):
            for j in range(self.col):
                checker = self.board.board[i][j]
                if checker.color == 'B':  # For black side pieces
                    pts += 5 + checker.row
                    if checker.is_king:  # 2 additional pts for king
                        pts += 2
                elif checker.color == 'W':  # FOr white side pieces
                    pts -= 11 - checker.row  # 5 + (6 - Row)
                    if checker.is_king:  # 2 additional pts for king
                        pts -= 2
        return pts if self.color == 1 else -pts

    def print_tree(self, root, level=0):
        # print("PRINTING TREE")

        print("\t" * level, root.value, "->", root.move)
        if len(root.children) != 0:  # Not Leaf node
            for child in root.children:
                self.print_tree(child, level + 1)

    def rec_tree(self, root: Tree, level=1):  #Create tree up to depth level
        if level == 0:
            pass
        else:
            if root.move is not None:  # Not root of tree
                self.board.make_move(root.move, root.color)
            #Check if win here maybe?
            avail_moves = self.board.get_all_possible_moves(
                self.opponent[root.color])
            for i in range(len(avail_moves)):
                for j in range(len(avail_moves[i])):
                    #print(root)
                    root.children.append(
                        Tree(self.opponent[root.color], avail_moves[i][j]))
            for child in root.children:
                self.rec_tree(child, level - 1)

            if root.move is not None:
                self.board.undo()

    def rec_min_max_heuristic(self,
                              root: Tree):  #Apply min_max heuristic to tree
        if root.move is not None:  #If not root of tree, make the move required to get here
            self.board.make_move(root.move, root.color)
        if len(root.children) == 0:  #Passed node has no children
            pass  #Evaluate heuristic for board(and return?)
            root.value = {self.board_points(): []}
        else:  #Evaluate rec_heuristic for children, then retrieve values and apply min/max as appropriate
            for child in root.children:
                self.rec_min_max_heuristic(child)
            root.value = self.min_max(root.children, root.color)

        if root.move is not None:
            self.board.undo()
예제 #16
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2

    def get_move(self, move):
        # make opponents move
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        # switch turn
        else:
            self.color = 1
        # find player 1 next move
        moves = self.board.get_all_possible_moves(self.color)
        alpha = -INFINITY
        beta = INFINITY
        result = self.move_ordering(self.color)
        for move in moves:
            for m in move:
                limit = 0
                self.board.make_move(m, self.color)
                val = self.min_value(limit + 1, alpha, beta)
                if val > alpha:
                    alpha = val
                    result = m
                self.board.undo()
        self.board.make_move(result, self.color)
        return result

    def max_value(self, limit, alpha, beta):
        if limit == MINIMAX_DEPTH or self.board.is_win(
                self.color) == self.color:
            return self.heuristic()
        #alpha = -INFINITY               # result = -infinity
        # move = self.move_ordering(self.color)
        # if not move:
        #     return alpha
        # self.board.make_move(move,self.color)
        # v = self.min_value(limit+1,alpha,beta)
        # self.board.undo()
        # if v >= beta:
        #     return INFINITY
        # alpha = max(alpha,v)
        val = -INFINITY
        moves = self.board.get_all_possible_moves(self.color)
        for move in moves:
            for m in move:
                self.board.make_move(m, self.color)
                val = max(val, self.min_value(limit + 1, alpha, beta))
                self.board.undo()
                alpha = max(alpha, val)
                if alpha >= beta:
                    return val
        return val

    def min_value(self, limit, alpha, beta):
        if limit == MINIMAX_DEPTH or self.board.is_win(
                self.color) == self.opponent[self.color]:
            return self.heuristic()
        #beta = INFINITY               # result = infinity
        # move = self.move_ordering(self.opponent[self.color])
        # if not move:
        #     return beta
        # self.board.make_move(move,self.opponent[self.color])
        # v = self.max_value(limit+1,alpha,beta)
        # self.board.undo()
        # if alpha >= v:
        #     return -INFINITY
        # beta = min(beta,v)
        # return beta
        val = INFINITY
        moves = self.board.get_all_possible_moves(self.opponent[self.color])
        for move in moves:
            for m in move:
                self.board.make_move(m, self.opponent[self.color])
                val = min(val, self.max_value(limit + 1, alpha, beta))
                self.board.undo()
                beta = min(beta, val)
                if alpha >= beta:  # pruning - go to next move (?)
                    return val
        return val

    def heuristic(self):
        black = 0
        white = 0
        #if (self.board.black_count+self.board.white_count) > (0.4* self.board.p * self.board.col):  # Decide between early game and mid,end game
        for row in range(self.board.row):
            for col in range(self.board.col):
                if self.board.board[row][col].color == "B":
                    if self.board.board[row][col].is_king:  # King = 10
                        black += self.board.row
                    else:
                        black += (5 + self.board.board[row][col].row -
                                  (0.5 * self.board.row)
                                  )  # reg piece = 5 + rows on oponent side

                elif self.board.board[row][col].color == "W":
                    if self.board.board[row][col].is_king:  # King = 10
                        white += self.board.row
                    else:
                        white += (5 + (self.board.row * 0.5) -
                                  self.board.board[row][col].row
                                  )  # reg piece = 5 + rows on oponent s
        if self.color == 1:
            return black - white
        else:
            return white - black

    def move_ordering(self, player):
        best_move_value = -INFINITY if (player == self.color) else INFINITY
        moves = self.board.get_all_possible_moves(player)
        if moves:
            best_move = moves[0][0]
        else:
            return False
        for move in moves:
            for m in move:
                self.board.make_move(m, player)
                v = self.heuristic()
                if v > best_move_value if (
                        player == self.color) else v < best_move_value:
                    best_move_value = v
                    best_move = m
                self.board.undo()
        return best_move
예제 #17
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2

        # ---------- What we added -----------

        self.calc_time = datetime.timedelta(seconds=3)
        self.max_moves = 35
        self.wins = {}
        self.plays = {}
        self.max_depth = 0
        self.C = 1.4
        self.colors = {1: "B", 2: "W"}
        self.letters = {"B": 1, "W": 2}
        self.states = []

    def run_sim(self, board):
        player = self.colors[self.color]
        number = self.letters[player]
        visited_states = set()

        expand = True

        for i in range(self.max_moves):

            moves = board.get_all_possible_moves(number)

            if len(moves) == 0:
                return

            if all(
                    self.plays.get((player, x)) for move in moves
                    for x in move):
                max_move = self.selection(moves, player)
            else:
                index = randint(0, len(moves) - 1)
                inner_index = randint(0, len(moves[index]) - 1)
                max_move = moves[index][inner_index]

            board.make_move(max_move, number)

            if expand == True and (player, max_move) not in self.plays:
                expand = False
                self.expand(player, max_move)

            visited_states.add((player, max_move))

            winner = board.is_win("W")
            if winner == 1 or winner == 2 or winner == -1:
                break

            if player == "W":
                player = "B"
                number = 1
            else:
                player = "W"
                number = 2

        if winner == 0:
            return
        elif winner == -1:
            winner == self.colors[self.color]
        else:
            winner = self.colors[winner]

        self.back_propagate(visited_states, winner)

    def selection(self, moves, player):
        max = -100000
        max_move = ""
        sum_plays = 0
        for g in moves:
            for x in g:
                sum_plays = sum_plays + self.plays.get((player, x), 0)
        for g in moves:
            for x in g:
                try:
                    one = self.wins[(player, x)] / self.plays[(player, x)]
                    score = one + self.C * sqrt(
                        log(sum_plays) / self.plays[(player, x)])
                except:
                    score = -100000
                if score > max:
                    max = score
                    max_move = x
        return max_move

    def back_propagate(self, visited_states, winner):
        for player, move in visited_states:
            if (player, move) not in self.plays:
                continue
            self.plays[(player, move)] += 1
            if player == winner:
                self.wins[(player, move)] += 1

    def expand(self, player, move):
        self.plays[(player, move)] = 0
        self.wins[(player, move)] = 0

    def get_move(self, move):
        first = False
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
            first = True

        player = self.colors[self.color]
        moves = self.board.get_all_possible_moves(self.color)
        index = randint(0, len(moves) - 1)
        inner_index = randint(0, len(moves[index]) - 1)
        move = moves[index][inner_index]

        if first:
            self.board.make_move(move, self.color)
            return move

        games = 0
        begin = datetime.datetime.utcnow()
        new_board = deepcopy(self.board)
        while datetime.datetime.utcnow() - begin < self.calc_time:
            self.run_sim(new_board)
            games += 1

        max_move = self.selection(moves, player)
        if max_move == "":
            max_move = move

        self.board.make_move(max_move, self.color)
        if max_move == "":
            return move

        return max_move
예제 #18
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = 2
        self.mcts = MCTS(TreeNode(self.board, self.color, None, None))
        self.total_time_remaining = 479
        self.time_divisor = row * col * 0.5
        self.timed_move_count = 2
        
    def get_move(self, move) -> Move:
        '''
        prune tree with opponent move
        MCTS
        '''
        # Start timer
        start_time = time()
        
        # Check if opponent gave a turn and execute it
        if len(move) != 0:
            self.play_move(move, OPPONENT[self.color])
        # If first move of game, change self.color and make random move
        else:
            self.color = 1
            self.mcts.root = TreeNode(self.board, self.color, None, None)

            moves = self.board.get_all_possible_moves(self.color)
            first_move = moves[0][1]
            self.play_move(first_move, self.color)
            return first_move
        
        # Check if only one move is possible
        moves = self.board.get_all_possible_moves(self.color)
        if len(moves) == 1 and len(moves[0]) == 1:
            self.play_move(moves[0][0], self.color)
            return moves[0][0]
        
        # Set up time limit
        time_limit = self.total_time_remaining / self.time_divisor
        
        # MCTS
        move_chosen = self.mcts.search(time_limit)
        self.play_move(move_chosen, self.color)
        
        # Change time divisor
        self.time_divisor -= 0.5 - 1/self.timed_move_count
        self.timed_move_count += 1
        
        # Decrement time remaining and return
        self.total_time_remaining -= time() - start_time
        return move_chosen
    
    def play_move(self, move, color):
        """
        Updates board and tree root using Move given,
        either Move we just played or Move given by opponent.
        """
        self.board.make_move(move, color)
        
        for child in self.mcts.root.children.items():
            if str(move) == str(child[0]) and child[1] is not None:
                self.mcts.root = child[1]
                self.mcts.root.parent = None
                return

        self.mcts.root = TreeNode(self.board, OPPONENT[color], None, None)
예제 #19
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        # Returns optimal value for current player

    def get_move(self, move):
        alpha = -1000
        value = -1000
        beta = 1000
        bestMove = None

        if len(move) != 0:  # If the opponent started first
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1

        # Make a list of all possible moves that our AI can make
        our_moves = self.board.get_all_possible_moves(self.color)

        # Iterate through list of all our moves
        for x in range(len(our_moves)):
            for y in range(len(our_moves[x])):
                # Make a move on the copy/theoretical board
                self.board.make_move(our_moves[x][y], self.color)
                currentScore = self.alphaBetaMin(alpha, beta, 1)
                self.board.undo()

                if currentScore >= value:
                    value = currentScore
                    bestMove = our_moves[x][y]
                    #print("New bestMove", bestMove, "current best score:", currentScore)
                    alpha = currentScore

        #print("Decision?", bestMove)
        self.board.make_move(bestMove, self.color)
        return bestMove

    def alphaBetaMin(self, alpha, beta, depth):
        '''
        # Check if our AI is black and we won
        #if self.color == self.board.is_win(self.color):
        if self.color == self.board.is_win("B"):
            return 1000
        # Check if our AI (black) lost
        #elif self.color == 1 and self.board.is_win(self.color) == 2:
        elif self.color == 1 and self.board.is_win("B") == 2:
            return -1000
        # Check if our AI (white) lost
        #elif self.color == 2 and self.board.is_win(self.color) == 1:
        elif self.color == 2 and self.board.is_win("W") == 1:
            return -1000
        
        # Check if opponent will tie
        #if self.board.is_win(self.color) == -1:
        if self.board.is_win("B") == -1:
            return 0
        '''
        if depth == 3:
            return self.get_heuristic_score2()
        else:
            value = 1000
            # Go through every possible move
            opponent_moves = self.board.get_all_possible_moves(
                self.opponent[self.color])
            for x in opponent_moves:
                for move in x:
                    # Make move for opponent
                    self.board.make_move(move, self.opponent[self.color])
                    value = min(value,
                                self.alphaBetaMax(alpha, beta, depth + 1))
                    self.board.undo()
                    beta = min(beta, value)
                    if alpha >= beta:
                        return value
            return value

    def alphaBetaMax(self, alpha, beta, depth):
        '''
        # Check if our AI is black and we won
        #if self.color == self.board.is_win(self.opponent[self.color]):
        if self.color == self.board.is_win("B"):
            return 1000
        # Check if our AI (black) lost
        #elif self.color == 1 and self.board.is_win(self.opponent[self.color]) == 2:
        elif self.color == 1 and self.board.is_win("B") == 2:
            return -1000
        # Check if our AI (white) lost
        #elif self.color == 2 and self.board.is_win(self.opponent[self.color]) == 1:
        elif self.color == 2 and self.board.is_win("W") == 1:
            return -1000
        
        # Check if opponent will tie
        #if self.board.is_win(self.opponent[self.color]) == -1:
        if self.board.is_win("B") == -1:
            return 0
        '''
        if depth == 3:
            return self.get_heuristic_score2()
        else:
            value = -1000
            # Go through every possible move
            our_moves = self.board.get_all_possible_moves(self.color)
            for x in our_moves:
                for move in x:
                    self.board.make_move(move, self.color)
                    value = max(value,
                                self.alphaBetaMin(alpha, beta, depth + 1))
                    self.board.undo()
                    alpha = max(alpha, value)
                    if alpha >= beta:
                        return value
            return value

    def closeToBecomingKing(self, color, row_position):
        if self.color == 1:  # Our color is black
            return row_position
        else:  # our color is white
            return (self.board.row - row_position - 1)

    def get_heuristic_score2(self):

        num_black_kings = 0
        num_white_kings = 0
        num_safe_piece_black = 0
        num_safe_piece_white = 0
        num_back_black = 0
        num_back_white = 0
        closer_black = 0
        closer_white = 0
        #score = 0
        for x in range(len(self.board.board)):
            for y in range(len(self.board.board[x])):
                # Check if it's our checker piece
                if (self.board.board[x][y].get_color() == 'B'):
                    # Check if it's a king
                    if (self.board.board[x][y].is_king == True):
                        num_black_kings += 1
                    else:  # Check how close checker piece is to becoming King
                        closer_black += self.closeToBecomingKing(self.color, x)

                    cp = self.board.board[x][y].get_location()

                    # Check if black checker piece is in the back
                    if (cp[0] == 0):
                        num_back_black += 1

                    # Check if it's an edge piece row 0, row n, col 0, col n
                    if (cp[0] == 0 or cp[0] == self.board.row - 1):
                        num_safe_piece_black += 1
                    if (cp[1] == 0 or cp[1] == self.board.col - 1):
                        num_safe_piece_black += 1
                    if (cp[0] == 0 and cp[1] == 0):
                        num_safe_piece_black -= 1
                    if (cp[0] == 0 and cp[1] == self.board.col - 1):
                        num_safe_piece_black -= 1
                    if (cp[0] == self.board.row - 1 and cp[1] == 0):
                        num_safe_piece_black -= 1
                    if (cp[0] == self.board.row - 1
                            and cp[1] == self.board.col - 1):
                        num_safe_piece_black -= 1

                    # Check for safe pieces that are not part of the edge
                    if (cp[0] != 0 and cp[0] != self.board.row - 1):
                        if (cp[1] != 0 and cp[1] != self.board.col - 1):
                            is_safe = True
                            if (self.board.board[x + 1][y -
                                                        1].get_color() == 'W'):
                                if (self.board.board[x -
                                                     1][y +
                                                        1].get_color() == '.'):
                                    is_safe = False
                            if (self.board.board[x + 1][y +
                                                        1].get_color() == 'W'):
                                if (self.board.board[x -
                                                     1][y -
                                                        1].get_color() == '.'):
                                    is_safe = False
                            if (self.board.board[x - 1][y + 1].get_color()
                                    == 'W' and
                                    self.board.board[x - 1][y + 1].is_king):
                                if (self.board.board[x +
                                                     1][y -
                                                        1].get_color() == '.'):
                                    is_safe = False
                            if (self.board.board[x - 1][y - 1].get_color()
                                    == 'W' and
                                    self.board.board[x - 1][y - 1].is_king):
                                if (self.board.board[x +
                                                     1][y +
                                                        1].get_color() == '.'):
                                    is_safe = False
                            if (is_safe == True):
                                #print("safe piece counted")
                                num_safe_piece_black += 1
                            #else:
                            #print(x, y)
                            #print("safe piece not counted")
                            #score -= 2
                    '''
                    # Check for safe pieces that are part of the edges
                    is_safe = True
                    # Check for safe piece on edge (column - 1)
                    if (cp[1] == self.board.col - 1):
                        if(self.board.board[x + 1][y - 1].get_color() == 'W'):
                            is_safe = False
                        # Check for safe piece on edge (0)
                    if (cp[1] == 0):
                        if(self.board.board[x + 1][y + 1].get_color() == 'W'):
                            is_safe = False
                    # check for safe piece on edge (column - 1) when a King
                    if (cp[1] == self.board.col - 1 and ((cp[0] > 0) or (cp[0] < self.board.row - 1))):
                        if(self.board.board[x - 1][y - 1].get_color() == 'W'):
                            is_safe = False
                        if(self.board.board[x + 1][y - 1].get_color() == 'W'):
                            is_safe = False
                        # check for safe piece on edge (0) when a King
                        if (cp[1] == 0 and ((cp[0] > 0) or (cp[0] < self.board.row - 1))):
                            if(self.board.board[x - 1][y + 1].get_color() == 'W'):
                                is_safe = False
                            if(self.board.board[x + 1][y + 1].get_color() == 'W'):
                                is_safe = False
                    
                        if (is_safe == True):
                            num_safe_piece_black += 1
                    '''

                elif (self.board.board[x][y].get_color() == 'W'):
                    if (self.board.board[x][y].is_king == True):
                        num_white_kings += 1
                    else:
                        closer_white += self.closeToBecomingKing(2, x)

                    # Check if it's a corner piece either (0, 0), (0, n), (n, 0), or (n, n)
                    cp = self.board.board[x][y].get_location()

                    # Check if white checker piece is in the back
                    if (cp[0] == self.board.row - 1):
                        num_back_white += 1
                    # Check if it's an edge piece row 0, row n, col 0, col n
                    if (cp[0] == 0 or cp[0] == self.board.row - 1):
                        num_safe_piece_white += 1
                    if (cp[1] == 0 or cp[1] == self.board.col - 1):
                        num_safe_piece_white += 1
                    if (cp[0] == 0 and cp[1] == 0):
                        num_safe_piece_white -= 1
                    if (cp[0] == 0 and cp[1] == self.board.col - 1):
                        num_safe_piece_white -= 1
                    if (cp[0] == self.board.row - 1 and cp[1] == 0):
                        num_safe_piece_white -= 1
                    if (cp[0] == self.board.row - 1
                            and cp[1] == self.board.col - 1):
                        num_safe_piece_white -= 1
                    # Check for white safe pieces that are not part of the edge
                    if (cp[0] != 0 and cp[0] != self.board.row - 1):
                        if (cp[1] != 0 and cp[1] != self.board.col - 1):
                            is_safe = True
                            if (self.board.board[x - 1][y -
                                                        1].get_color() == 'B'):
                                if (self.board.board[x +
                                                     1][y +
                                                        1].get_color() == '.'):
                                    is_safe = False
                            if (self.board.board[x - 1][y +
                                                        1].get_color() == 'B'):
                                if (self.board.board[x +
                                                     1][y -
                                                        1].get_color() == '.'):
                                    is_safe = False
                            if (self.board.board[x + 1][y + 1].get_color()
                                    == 'B' and
                                    self.board.board[x + 1][y + 1].is_king):
                                if (self.board.board[x -
                                                     1][y -
                                                        1].get_color() == '.'):
                                    is_safe = False
                            if (self.board.board[x + 1][y - 1].get_color()
                                    == 'B' and
                                    self.board.board[x + 1][y - 1].is_king):
                                if (self.board.board[x -
                                                     1][y +
                                                        1].get_color() == '.'):
                                    is_safe = False
                            if (is_safe == True):
                                num_safe_piece_white += 1
        if self.color == 1:
            score = 10 * (self.board.black_count - self.board.white_count)
            #print("Score after diff in counts:", score)
            #print('safe black:', num_safe_piece_black, 'safe white:', num_safe_piece_white, 'safe score:', num_safe_piece_black - num_safe_piece_white)
            score += 5 * (num_black_kings - num_white_kings)
            #print("Score after diff in Ks:", score)
            #score += 2*(closer_black - closer_white)
            score += 2 * (num_safe_piece_black - num_safe_piece_white)
            #print("Score after diff in safe pieces:", score)
            score += 2 * (num_back_black - num_back_white)
            #print("Score after back row pieces:", score)
        elif self.color == 2:
            score = 10 * (self.board.white_count - self.board.black_count)
            #print("Score after diff in counts:", score)
            #print('safe black:', num_safe_piece_black, 'safe white:', num_safe_piece_white, 'safe score:', num_safe_piece_black - num_safe_piece_white)
            score += 5 * (num_white_kings - num_black_kings)
            #print("Score after diff in Ks:", score)
            #score += 2*(closer_black - closer_white)
            score += 2 * (num_safe_piece_white - num_safe_piece_black)
            #print("Score after diff in safe pieces:", score)
            score += 2 * (num_back_white - num_back_black)
            #print("Score after back row pieces:", score)
        return score
예제 #20
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        self.f = open("debug.txt", "w")

    def heuristic_black(self):
        count_b = 0
        count_w = 0
        for i in range(int(len(self.board.board) / 2)):
            for j in range(len(self.board.board[i])):
                if self.board.board[i][j].color == 1:
                    if self.board.board[i][j].is_king == True:
                        count_b += 10
                    else:
                        count_b += 5
                else:
                    if self.board.board[i][j].is_king == True:
                        count_w += 10
                    else:
                        count_w += 7
        for i in range(int(len(self.board.board) / 2), len(self.board.board)):
            for j in range(len(self.board.board[i])):
                if self.board.board[i][j].color == 1:
                    if self.board.board[i][j].is_king == True:
                        count_b += 10
                    else:
                        count_b += 7
                else:
                    if self.board.board[i][j].is_king == True:
                        count_w += 10
                    else:
                        count_w += 5

        # for i in self.board.board:
        #     for j in i:
        #
        #         if j.color == 1:
        #             if j.is_king == True:
        #                 count_b += 7 + self.row
        #             else:
        #                 count_b += 5 + (self.row - j.row)
        #         elif j.color == 2:
        #             if j.is_king == True:
        #                 count_w += 7 + self.row
        #             else:
        #                 count_w += 5 + j.row
        return count_b - count_w

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)
        self.f.write("Curr Moves: " + str(moves) + '\n')
        if len(moves) == 1 and len(moves[0]) == 1:
            move = moves[0][0]
            self.board.make_move(move, self.color)
            return move
        move = self.minimax(moves)
        self.f.write("Chosen Move: " + str(move) + '\n')
        # index = randint(0,len(moves)-1)
        # inner_index =  randint(0,len(moves[index])-1)
        # move = moves[index][inner_index]
        self.board.make_move(move, self.color)
        return move

    def minimax(self, moves):
        dic_l1 = dict()
        for peice in range(len(moves)):
            for i in range(len(moves[peice])):
                move = moves[peice][i]
                self.board.make_move(move, self.color)

                if self.board.is_win(self.color) == self.color:
                    self.board.undo()
                    return moves[peice][i]

                l2_moves = self.board.get_all_possible_moves(
                    self.opponent[self.color])
                # print("Opponent Moves: \n peice: ",peice, "\n dir: ",i, "\nMoves\n", l2_moves)
                dic_l2 = dict()
                for opp_peice in range(len(l2_moves)):
                    for j in range(len(l2_moves[opp_peice])):
                        move = l2_moves[opp_peice][j]
                        self.board.make_move(move, self.opponent[self.color])
                        l3_moves = self.board.get_all_possible_moves(
                            self.color)
                        dic_l3 = dict()
                        # print("L3 ",l3_moves)
                        for my_peice in range(len(l3_moves)):
                            flag = 0
                            for k in range(len(l3_moves[my_peice])):
                                move = l3_moves[my_peice][k]
                                self.board.make_move(move, self.color)
                                value = -1
                                if self.color == 1:
                                    value = (self.board.black_count /
                                             (self.board.black_count +
                                              self.board.white_count)) * 100
                                else:
                                    value = (self.board.white_count /
                                             (self.board.black_count +
                                              self.board.white_count)) * 100

                                key = str(my_peice) + ' ' + str(k)
                                # print(key, ' ', value)
                                dic_l3[key] = value
                                self.board.undo()
                                if self.board.is_win(self.color) == self.color:
                                    flag = 1
                                    break
                            if flag == 1:
                                break

                        if len(dic_l3) == 0:
                            key = str(opp_peice) + ' ' + str(j)
                            dic_l2[key] = int(0x40000)
                            self.board.undo()
                        else:
                            inverse = [(value, key)
                                       for key, value in dic_l3.items()]
                            l2_value = max(inverse)[0]
                            key = str(opp_peice) + ' ' + str(j)
                            dic_l2[key] = l2_value
                            self.board.undo()
                if len(dic_l2) == 0:
                    key = str(peice) + ' ' + str(i)
                    dic_l1[key] = int(-0x40000)
                    self.board.undo()
                else:
                    inverse = [(value, key) for key, value in dic_l2.items()]
                    l1_value = min(inverse)[0]
                    key = str(peice) + ' ' + str(i)
                    dic_l1[key] = l1_value
                    self.board.undo()

        inverse = [(value, key) for key, value in dic_l1.items()]
        l0_value = max(inverse)[1]
        # print(dic_l1)
        # print(l0_value)
        x, y = l0_value.split(' ')
        return moves[int(x)][int(y)]
예제 #21
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        self.search_lim = 5
        self.current_node = TreeNode(None, self.color)

    def get_move(self, move):
        if len(move) != 0:
            # print("|" + str(move) + "|")
            self.board.make_move(move, self.opponent[self.color])
            #print("Player", self.opponent[self.color], "make move", move)
            if len(self.current_node.child_node) != 0:
                for child in self.current_node.child_node:
                    if str(child.move) == str(move):
                        self.current_node = child
        else:
            self.color = 1
            self.current_node.player = self.color
        for i in range(NS):
            self.mcts(self.current_node)
            #self.board.show_board()
            #print("mcts counter:", i)
        move = self.current_node.child_node[0]
        for child in self.current_node.child_node:
            if move.uct() < child.uct():
                move = child
        self.board.make_move(move.move, self.color)
        # print("Player", self.color, "make move", move.move, "with a winrate of", move.winrate(), "simulated", move.simulation)
        self.current_node = move
        return move.move

    def mcts(self, node):
        if node.simulation >= minVisit:
            #print("depth:", depth)
            node.simulation += 1
            if not len(node.child_node):
                moves = self.board.get_all_possible_moves(node.player)
                for move in moves:
                    for eachmove in move:
                        node.child_node.append(
                            TreeNode(eachmove, self.opponent[node.player],
                                     node))
            # proceed
            next = self.mcts_selection(node)
            self.board.make_move(next.move, node.player)
            result = self.board.is_win(node.player)
            if result:
                if result == self.opponent[node.player]: node.win += 1
                elif result == node.player:
                    next.win += 1
                    next.simulation += 1
                self.board.undo()
                return result
                #self.board.show_board()
            result = self.mcts(next)
            self.board.undo()
            # propagate up
            if result == self.opponent[node.player]:
                node.win += 1
            return result
        else:
            result = self.simulate(node.player)
            node.simulation += 1
            if result == self.opponent[node.player]:
                node.win += 1
            #print("simulating", result)
            return result

    def mcts_selection(self, node):  # Select optimal UCB node
        current = node.child_node[0]
        for child in node.child_node:
            #print(current.uct())
            if current.uct() < child.uct():
                current = child
        #print("player", node.player, "pick", current.move)
        return current

    def simulate(self, player):
        win = 0
        counter = 0
        fake_board = Board(self.col, self.row, self.p)
        self.copy_board(fake_board)
        # print("DIT ME DIEN")
        # fake_board.show_board()
        # totaltime = 0
        while win == 0:
            moves = fake_board.get_all_possible_moves(player)
            if len(moves) == 1:
                index = 0
            elif len(moves) == 0:
                win = self.opponent[player]
                break
            else:
                index = randint(0, len(moves) - 1)
            if len(moves[index]) == 1:
                inner_index = 0
            else:
                inner_index = randint(0, len(moves[index]) - 1)
            move = moves[index][inner_index]
            fake_board.make_move(move, player)
            counter += 1
            # bt = time.time()
            if fake_board.tie_counter >= fake_board.tie_max:
                win = -1
            # totaltime += time.time() - bt
            # print("self.board.is_win():", time.time() - bt)
            player = self.opponent[player]

        # #print("total time is_win:", totaltime)
        # #bt = time.time()
        # for i in range(counter):
        #     self.board.undo()
        # #rint("total time undo:", time.time() - bt)
        # fake_board.show_board()
        return win

    def copy_board(self, board):
        """
        EZ game
        :return: ez board
        """
        board.tie_counter = self.board.tie_counter
        board.tie_max = self.board.tie_max
        board.board = copy.deepcopy(self.board.board)
        board.saved_move = copy.deepcopy(self.board.saved_move)
        board.black_count = self.board.black_count
        board.white_count = self.board.white_count
예제 #22
0
파일: CA.py 프로젝트: GaryZLi/checkers_ai
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        self.bestMove = None
        self.blackVal = 0  #-------
        self.whiteVal = 0  #-------

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1

        moves = self.board.get_all_possible_moves(self.color)
        cloneBoard = copy.deepcopy(self.board)
        self.minimax(cloneBoard, 2, True)
        move = self.bestMove
        self.board.make_move(move, self.color)
        return move

    def minimax(self, cloneBoard, depth, maximizingPlayer):
        if (depth == 0):
            return self.evaluate(cloneBoard)

        if (maximizingPlayer == True):
            maximizerMoves = cloneBoard.get_all_possible_moves(self.color)
            value = -math.inf
            for move in maximizerMoves:
                for x in move:
                    clone = copy.deepcopy(cloneBoard)
                    clone.make_move(x, self.color)
                    score = self.minimax(clone, depth - 1, False)
                    if (score > value):
                        value = score
                        self.bestMove = x
            return value

        else:
            minimizerMoves = cloneBoard.get_all_possible_moves(
                self.opponent[self.color])
            value = math.inf
            for move in minimizerMoves:
                for x in move:
                    clone = copy.deepcopy(cloneBoard)
                    clone.make_move(x, self.opponent[self.color])
                    score = self.minimax(clone, depth - 1, True)
                    if (score < value):
                        value = score
            return value

    def evaluate(self, board):
        # for x in range(self.row):
        #     for y in range(self.col):
        #         if (self.board.board[x][y].is_king):
        #             if self.board.board[x][y].color == "B":
        #                 # print("%s king row:%d col:%d" % (self.board.board[x][y].color, x,y))
        #                 self.blackVal += 7
        #             else:
        #                 self.whiteVal += 7

        if (self.color == 1):
            return self.blackVal + 5 * board.black_count - 5 * board.white_count
        else:
            return self.whiteVal + 5 * board.white_count - 5 * board.black_count


# class StudentAI():

#     def __init__(self,col,row,p):
#         self.col = col
#         self.row = row
#         self.p = p
#         self.board = Board(col,row,p)
#         self.board.initialize_game()
#         self.color = ''
#         self.opponent = {1:2,2:1}
#         self.color = 2
#         self.bestMove = None

#     def get_move(self,move):
#         if len(move) != 0:
#             self.board.make_move(move,self.opponent[self.color])
#         else:
#             self.color = 1
#         moves = self.board.get_all_possible_moves(self.color)
#         cloneBoard = copy.deepcopy(self.board)
#         self.minimax(cloneBoard, 2, True)
#         move = self.bestMove
#         self.board.make_move(move,self.color)
#         return move

#     def minimax(self, cloneBoard, depth, maximizingPlayer):
#         if(depth == 0):
#             return self.evaluate(cloneBoard)

#         if(maximizingPlayer == True):
#             maximizerMoves = cloneBoard.get_all_possible_moves(self.color)
#             value = -math.inf
#             for move in maximizerMoves:
#                 for x in move:
#                     clone = copy.deepcopy(cloneBoard)
#                     clone.make_move(x, self.color)
#                     score = self.minimax(clone, depth - 1, False)
#                     if(score > value):
#                         value = score
#                         self.bestMove = x
#             return value

#         else:
#             minimizerMoves = cloneBoard.get_all_possible_moves(self.opponent[self.color])
#             value = math.inf
#             for move in minimizerMoves:
#                 for x in move:
#                     clone = copy.deepcopy(cloneBoard)
#                     clone.make_move(x, self.opponent[self.color])
#                     score = self.minimax(clone, depth - 1, True)
#                     if(score < value):
#                         value = score
#             return value

#     def evaluate(self, board):
#         if(self.color == 1):
#             return board.black_count - board.white_count

#         else:
#             return board.white_count - board.black_count
예제 #23
0
class StudentAI():

    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)
        best_move = moves[0][0]
        #self.board.make_move(best_move, self.color)
        #best_score = self.board_score( self.color )
        #self.board.undo()
        move = self.minMax(self.color, 3, -999999999, best_move, 999999999, best_move)[1]
        self.board.make_move(move, self.color)

        return move
    
    def minMax(self, player, depth, best_score, best_move, opponent_score, opponent_move):
        if depth == 0:
            return self.board_score( player ), best_move
        # get all the moves of the current player
        moves = self.board.get_all_possible_moves(player)
        # Itterate through each move
        for i in moves:
            for ii in i:
                # change to new game state
                self.board.make_move(ii, player)
                if (player == self.color):
                    opponent_score = self.minMax(self.opponent[self.color], depth-1, best_score, best_move,opponent_score, opponent_move)[0]
                    if (best_score <  opponent_score):
                        best_score = opponent_score
                        best_move = ii
                # opponent's turn: find the best score based on player's move
                elif (player == self.opponent[self.color]):
                    best_score = self.minMax(self.color, depth-1, best_score, best_move,opponent_score, opponent_move)[0]
                    if (opponent_score > best_score):
                        opponent_score = best_score
                        opponent_move = ii
                self.board.undo()
        return best_score, best_move, opponent_score, opponent_move

    def board_score(self, color):
        ## @param color: color of player making the move
        ## Heuristics to Evaluate with
        ## Normal Piece : 1000 pts
        ## King Piece : 2000 pts
        ## Rows away from enemy end if Normal : (rows - curr_row / rows) * 1000
        ## Amount of Pieces : (Amount of pieces left) / (self.col * self.p / 2) * 100
        ## Randomization : randomInt (0-10)

        player_points = 0
        opponent_points = 0
        for c in range(self.col):
            for r in range(self.row):
                current_piece = self.board.board[c][r]

                if current_piece.get_color() == color:
                    if current_piece.is_king == True:
                        player_points += 2000
                    else:
                        player_points += 1000
                        if color == 1:
                            player_points += ((self.row - r) / self.row) * 1000
                        else:
                            player_points += (r / self.row) * 1000
                elif current_piece.get_color() == self.opponent[color]:
                    if current_piece.is_king == True:
                        opponent_points += 2000
                    else:
                        opponent_points += 1000
                        if self.opponent[color] == 1:
                            opponent_points += ((self.row - r) / self.row) * 1000
                        else:
                            opponent_points += (r / self.row) * 1000
                else:
                    pass
        
        if color == 1:
            player_points += ((self.board.white_count / (self.col * self.p / 2)) * 100)
            opponent_points += ((self.board.black_count / (self.col * self.p / 2)) * 100)
        else:
            player_points += ((self.board.black_count / (self.col * self.p / 2)) * 100)
            opponent_points += ((self.board.white_count / (self.col * self.p / 2)) * 100)
        
        randomization = randint(0, 50)
            
        return player_points - opponent_points + randomization
예제 #24
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        self.depth = 4
        self.a = -math.inf
        self.b = math.inf

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)

        # index = randint(0, len(moves) - 1)
        # inner_index = randint(0, len(moves[index]) - 1)
        # move = moves[index][inner_index]
        move = self.select_move(moves)
        # print(move)
        self.board.make_move(move, self.color)
        return move

    def select_move(self, moves):
        """take a list of moves and select the best one,
        return move"""
        copySelf = copy.deepcopy(self)

        return abPruning(copySelf, 0, self.a, self.b, self.color)
        # return simple_search(copySelf)

    def heuristic_func(self, move, color):
        """take a move, evaluate it's heuristic value
        return the value"""
        result = 0
        colorDict = {"B": 1, "W": 2, ".": 0}
        self.board.make_move(move, color)
        # print (self.board.board)
        black = []
        white = []
        for row in self.board.board:
            for checker in row:
                if colorDict[checker.get_color()] == 1:
                    black.append(checker.get_location())
                else:
                    white.append(checker.get_location())
        # for row in self.board.board:
        #     for checker in row:
        #         add = 1 if colorDict[checker.get_color()] == self.color else -1
        #         y = checker.get_location()[1]
        #         if self.color == 1:
        #             # if getProtected(checker.get_location(), black) and add == 1:
        #             #     result += 5
        #             if checker.is_king:
        #                 result += (self.board.row + 1 + y) * add
        #             else:
        #                 result += (y + 5) * add
        #         else:
        #             # if getProtected(checker.get_location(), white) and add == 1:
        #             #     result += 5
        #             if checker.is_king:
        #                 result += (self.board.row + 1) * add
        #             else:
        #                 result += (4 + self.board.row - y) * add
        for row in self.board.board:
            for checker in row:
                y = checker.get_location()[1]
                x = checker.get_location()[0]
                if colorDict[checker.get_color()] == self.color:
                    if self.color == 2 and y == self.board.row - 1:
                        result += 0.5
                    elif self.color == 1 and y == 0:
                        result += 0.5
                    if x == 0 or x == self.board.col - 1:
                        result += 0.25
                    if checker.is_king:
                        result += 3.0 + 0.5 * abs(y - (self.board.row / 2.0))
                    else:
                        result += 1.5
                else:
                    if checker.is_king:
                        result -= 3.0
                    else:
                        result -= 1.5

        self.board.undo()
        return result
예제 #25
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[
                self.color])  # Run opponent's move for self.board
        else:
            self.color = 1

        root = Tree(self.opponent[self.color])  #Tree root
        self.rec_tree(root, search_depth)
        self.rec_heuristic(root)

        avail_moves = root.value[list(root.value)[0]]
        cur_move = avail_moves[0]
        #print(avail_moves)

        self.board.make_move(cur_move, self.color)  # Make the optimal move
        move = cur_move
        return move

    def ftu(self, color):  #Function to use (min vs max by color)
        if color == self.color:  # Calculate Min
            return max
        else:  # Calculate Max
            return min

    def min_max(self, children,
                color):  # Returns dict -> {Max/min value: Moves to get here}
        ftu = self.ftu(color)  #Use corresponding min or max depending on color
        value_map = {}
        for child in children:
            for v in child.value.keys():
                value_map.setdefault(v, []).append(
                    child.move
                )  # D: {heuristic value: Move to make to get here}
        # print(value_map)
        return {ftu(value_map): value_map[ftu(value_map)]}

    def board_points(
            self):  # 5 + row number for pawns, 5 + row number + 2 for kings
        pts = 0
        for i in range(self.row):
            for j in range(self.col):
                checker = self.board.board[i][j]
                if checker.color == 'B':  # For black side pieces
                    pts += 5 + checker.row
                    if checker.is_king:  # 2 additional pts for king
                        pts += 2
                elif checker.color == 'W':  # FOr white side pieces
                    pts -= 11 - checker.row  # 5 + (6 - Row)
                    if checker.is_king:  # 2 additional pts for king
                        pts -= 2
        return pts if self.color == "B" else -pts

    def print_tree(self, root, level=0):
        # print("PRINTING TREE")

        print("\t" * level, root.value, "->", root.move)
        if len(root.children) != 0:  # Not Leaf node
            for child in root.children:
                self.print_tree(child, level + 1)

    def rec_tree(self, root: Tree, level=1):
        if level == 0:
            pass
        else:
            if root.move is not None:  # Not root of tree
                self.board.make_move(root.move, root.color)
            #Check if win here maybe?
            avail_moves = self.board.get_all_possible_moves(
                self.opponent[root.color])
            for i in range(len(avail_moves)):
                for j in range(len(avail_moves[i])):
                    #print(root)
                    root.children.append(
                        Tree(self.opponent[root.color], avail_moves[i][j]))
            for child in root.children:
                self.rec_tree(child, level - 1)

            if root.move is not None:
                self.board.undo()

    def rec_heuristic(self, root: Tree):
        if root.move is not None:
            self.board.make_move(root.move, root.color)
        if len(root.children) == 0:  #Passed node has no children
            pass  #Evaluate heuristic for board(and return?)
            root.value = {self.board_points(): []}
        else:  #Evaluate rec_heuristic for children, then retrieve values and apply min/max as appropriate
            for child in root.children:
                self.rec_heuristic(child)
            root.value = self.min_max(root.children, root.color)

        if root.move is not None:
            self.board.undo()
예제 #26
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2
        self.halftime = time.time() + 240
        self.endtime = time.time() + 360
        self.finaltime = time.time() + 460
        self.root = Node(0, 0)

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
            self.update_root_tree(move)
        else:
            self.color = 1

        moves = self.board.get_all_possible_moves(self.color)
        if len(moves) == 1 and len(moves[0]) == 1:
            self.board.make_move(moves[0][0], self.color)
            self.update_root_tree(moves[0][0])
            return moves[0][
                0]  # if only one move available, choose immediately

        count = 0
        # decides how long to run the mcts depending on time remaining
        if time.time() > self.finaltime:
            return self.choose_best_move(self.board, moves, self.color)
        elif time.time() > self.endtime:
            t_end = time.time() + 4
        elif time.time() > self.halftime:
            t_end = time.time() + 7
        else:
            t_end = time.time() + 10

        while time.time() < t_end:
            node, board = self.selection()
            node = self.expansion(node, board)
            result = self.simulation(node, board)
            self.backpropagation(node, result)
            count += 1

        max_sim = 0
        max_child = self.root.children[0]
        for each in self.root.children:
            if each.si > max_sim:
                max_child = each
                max_sim = each.si
        self.board.make_move(max_child.move, self.color)
        self.update_root_tree(max_child.move)
        return max_child.move

    def selection(self):
        node_found = False
        board = copy.deepcopy(self.board)
        node = self.root
        color = self.color
        while not node_found:
            if len(node.children) == 0:
                node_found = True
            else:
                max_uct = 0
                max_child = node.children[0]
                for each in node.children:
                    if each.si == 0 or each.parent.si == 0:
                        uct = 9999
                    else:
                        uct = (each.wi / each.si) + each.c * (math.sqrt(
                            math.log(each.parent.si) / each.si))
                    if uct > max_uct:
                        max_child = each
                        max_uct = uct
                node = max_child
                board.make_move(max_child.move, color)
                color = 3 - color

        return node, board

    def expansion(self, node, board):
        new_color = self.color
        if node.depth % 2 == 1:
            new_color = 3 - self.color
        outer_childs = board.get_all_possible_moves(new_color)
        for child in outer_childs:
            for move in child:
                node.children.append(Node(0, 0, move, node))

        if len(outer_childs) == 0:
            return node
        return node.children[randint(0, len(node.children) - 1)]

    def simulation(self, node, board):
        sim_color = self.color
        if node.depth % 2 == 1:
            sim_color = 3 - self.color
        loops = 0
        while not board.is_win(sim_color):
            sim_color = 3 - sim_color
            moves = board.get_all_possible_moves(sim_color)
            index = randint(0, len(moves) - 1)
            inner_index = randint(0, len(moves[index]) - 1)
            board.make_move(moves[index][inner_index], sim_color)

            if loops > 50:  # game takes too long, return based on who has advantage on current board state
                if board.black_count - board.white_count >= 2:
                    return 1
                elif board.white_count - board.black_count >= 2:
                    return 2
                else:
                    return -1
            loops += 1

        if loops == 0:
            sim_color = 3 - sim_color

        return board.is_win(sim_color)

    def backpropagation(self, node, result):
        win = False
        node_color = self.color
        if node.depth % 2 == 0:
            node_color = 3 - self.color
        if result == node_color:
            win = True

        while node is not None:
            node.si += 1
            if win:
                node.wi += 1
            win = not win
            node = node.parent

    def update_root_tree(self, move):
        check = False
        for each in self.root.children:
            if str(each.move) == str(move):
                self.root = each
                self.root.parent = None
                check = True
                break
        if not check:
            self.root = Node(0, 0)

    # essentially attempts to prevent the opponent from capturing a piece, stall the game to a tie
    def choose_best_move(self, board, moves, color):
        best_move = moves[0][0]
        num = 9999
        for i, each in enumerate(moves):
            for j, move in enumerate(each):
                board.make_move(move, color)
                opp_moves = board.get_all_possible_moves(3 - color)
                rank = 0
                for opp in opp_moves:
                    for opp_move in opp:
                        str_move = str(opp_move)
                        if abs(int(str_move[1]) - int(str_move[7])) == 2:
                            rank += 1
                if rank < num:
                    num = rank
                    best_move = move
                board.undo()
        board.make_move(best_move, color)
        return best_move
예제 #27
0
class StudentAI():

    def __init__(self,col,row,p):
        self.row = row
        self.col = col
        self.p = p
        self.board = Board(col,row,p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1:2,2:1}
        self.color = 2
        self.turn_color = {1: "B", 2: "W"}

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1

        moves = self.board.get_all_possible_moves(self.color)

        curr_distance = self.king_distance(self.board, self.turn_color[self.color])
        aggressive = False
        late_game = False
        if self.board.black_count + self.board.white_count <= 8:
            late_game = True

        if self.color == 1 and self.board.black_count >= self.board.white_count:
            aggressive = True
        if self.color == 2 and self.board.white_count >= self.board.black_count:
            aggressive = True

        depth = 4
        alpha = -math.inf
        beta = math.inf
        best_moves = []
        for row in moves:
            for move in row:
                board_copied = copy.deepcopy(self.board)
                board_copied.make_move(move, self.color)
                curr = self.MinValue(board_copied, depth-1, alpha, beta)

                if late_game:
                    distance_diff = self.king_distance(board_copied, self.turn_color[self.color]) - curr_distance
                    if aggressive:
                        curr += distance_diff/1000
                    else:
                        curr -= distance_diff/1000

                if curr > alpha:
                    alpha = curr
                    best_moves = [move]
                elif curr == alpha:
                    best_moves.append(move)

        best_move = random.choice(best_moves)

        self.board.make_move(best_move, self.color)

        return best_move

    def MaxValue(self, board, depth, alpha, beta):
        moves = board.get_all_possible_moves(self.color)
        if depth == 0:
            # print(self.evaluate(board))
            return self.evaluate(board)
        elif len(moves) == 0:
            if self.checkWinner(board.board, self.color):
                # print("1", self.color, depth)
                return 999
            else:
                # print("2", self.color, depth)
                return -999

        val = -math.inf
        for row in moves:
            for move in row:
                board_copied = copy.deepcopy(board)
                board_copied.make_move(move, self.color)
                val = max(val, self.MinValue(board_copied, depth-1, alpha, beta))
                alpha = max(alpha, val)
                if alpha >= beta:
                    return val
        return val

    def MinValue(self, board, depth, alpha, beta):
        moves = board.get_all_possible_moves(self.opponent[self.color])
        if depth == 0:
            # print(self.evaluate(board))
            return self.evaluate(board)
        if len(moves) == 0:
            if self.checkWinner(board.board, self.color):
                # print("3", self.color, depth)
                return 999
            else:
                # print("4", self.color, depth)
                return -999

        val = math.inf
        for row in moves:
            for move in row:
                board_copied = copy.deepcopy(board)
                board_copied.make_move(move, self.opponent[self.color])
                val = min(val, self.MaxValue(board_copied, depth-1, alpha, beta))
                beta = min(beta, val)
                if alpha >= beta:
                    return val
        return val

    def evaluate(self,board):
        if self.color == 1:
            return board.black_count - board.white_count + self.boardEval1(board, "b")/100
        else:
            return board.white_count - board.black_count + self.boardEval1(board, "w")/100

    def boardEval1(self, board, color):
        val = 0
        for i, row in enumerate(board.board):
            for j, col in enumerate(row):

                extra = 0
                if j == 0 or j == len(row):
                    extra = 4

                if color == "b":
                    pawn_val = 5 + i + extra
                    king_val = 5 + len(board.board) + 2 + extra
                    if i == 0:
                        pawn_val = 10 + extra
                else:
                    pawn_val = 5 + (len(board.board) - 1 - i) + extra
                    king_val = 5 + len(board.board) + 2 + extra
                    if i == len(board.board) - 1:
                        pawn_val = 10 + extra

                curr_color = board.board[i][j].get_color().lower()
                if curr_color != '.':
                    if curr_color == color:
                        king = board.board[i][j].is_king
                        if king:
                            val += king_val
                        else:
                            val += pawn_val

                    else:
                        king = board.board[i][j].is_king
                        if king:
                            val -= king_val
                        else:
                            val -= pawn_val

        return val

    def checkWinner(self, board, color):
        my_color = self.turn_color[color]
        oppo_color = self.turn_color[self.opponent[color]]
        for row in range(self.row):
            for col in range(self.col):
                checker = board[row][col]
                if checker.color == my_color:
                    return True
                elif checker.color == oppo_color:
                    return False


    def king_distance(self, board, color):
        k1 = []
        k2 = []
        min_distance = 100
        for row in range(board.row):
            for col in range(board.col):
                checker = board.board[row][col]
                if checker.color != ".":
                    if checker.is_king and checker.color == color:
                        k1.append([row, col])
                    elif checker.color != color:
                        k2.append([row, col])
        for i in k1:
            for j in k2:
                d = self.cal_distance(i,j)
                if self.cal_distance(i,j) < min_distance:
                    min_distance = d
        # print(k1, k2, min_distance)
        return min_distance

    def cal_distance(self, p1, p2):
        return math.sqrt(math.pow(p1[0]-p2[0], 2) + math.pow(p1[1]-p2[1], 2))
예제 #28
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2

        self.search_depth = 5
        self.debug = True
        self.time_used = 0

        self.transposition_table = dict()

    def get_move(self, move):
        if self.debug:
            current_move_elapsed = time.time()

        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1
        moves = self.board.get_all_possible_moves(self.color)

        # index = randint(0,len(moves)-1)
        # inner_index =  randint(0,len(moves[index])-1)
        # move = moves[index][inner_index]

        how_many_moves = 0
        for outer_index in range(len(moves)):
            how_many_moves += len(moves[outer_index])

        if how_many_moves == 1:
            if self.debug:
                self.time_used += (time.time() - current_move_elapsed)
                print("Total elapsed time (in seconds):", self.time_used)
            self.board.make_move(moves[0][0], self.color)
            return moves[0][0]

        depth = round((4 / how_many_moves) + self.search_depth)

        if self.debug:
            print(how_many_moves, "possible moves")
            print("Depth:", depth)

        best_move = None
        best_move_score = -math.inf
        for outer_index in range(len(moves)):
            for inner_index in range(len(moves[outer_index])):
                self.board.make_move(moves[outer_index][inner_index],
                                     self.color)
                move_score = self.search(depth,
                                         moves[outer_index][inner_index],
                                         self.color, -math.inf, math.inf)
                self.board.undo()
                if move_score > best_move_score:
                    best_move_score = move_score
                    best_move = moves[outer_index][inner_index]

        self.board.make_move(best_move, self.color)

        if self.debug:
            self.time_used += (time.time() - current_move_elapsed)
            print("Total elapsed time (in seconds):", self.time_used)

        return best_move

    def search(self, depth, move, turn, alpha, beta):
        current_key = self.get_key()
        if current_key in self.transposition_table.keys(
        ) and depth == self.transposition_table[current_key].depth:
            return self.transposition_table[current_key].value

        winner = self.board.is_win(turn)
        win_return = 1000 + depth
        if winner != 0:
            if winner == -1:
                self.transposition_table[current_key] = TTEntry(0, depth)
                return 0
            if self.color == winner:
                self.transposition_table[current_key] = TTEntry(
                    win_return, depth)
                return win_return
            self.transposition_table[current_key] = TTEntry(-win_return, depth)
            return -win_return
        if depth == 0:
            black = 0
            white = 0
            for x in range(self.board.row):
                for y in range(self.board.col):
                    if self.board.board[x][y].color == "W":
                        white += 5
                        if self.board.board[x][y].is_king:
                            white += self.row + 2
                        else:
                            white += x

                    if self.board.board[x][y].color == "B":
                        black += 5
                        if self.board.board[x][y].is_king:
                            black += self.row + 2
                        else:
                            black += (self.row - x - 1)

            score = black - white
            if self.color == 1:  # 1 = black
                self.transposition_table[current_key] = TTEntry(score, depth)
                return score
            self.transposition_table[current_key] = TTEntry(-score, depth)
            return -score  # 2 = white

        if turn == self.color:  # min
            worst = math.inf
            possible_moves = self.board.get_all_possible_moves(
                self.opponent[self.color])
            for x in range(len(possible_moves)):
                for y in range(len(possible_moves[x])):
                    self.board.make_move(possible_moves[x][y],
                                         self.opponent[self.color])
                    current = self.search(depth - 1, possible_moves[x][y],
                                          self.opponent[self.color], alpha,
                                          beta)
                    self.board.undo()
                    if current < worst:
                        worst = current
                    if current < beta:
                        beta = current
                    if beta <= alpha:
                        break
                else:
                    continue
                break
            self.transposition_table[current_key] = TTEntry(worst, depth)
            return worst

        else:  # max
            best = -math.inf
            possible_moves = self.board.get_all_possible_moves(self.color)
            for x in range(len(possible_moves)):
                for y in range(len(possible_moves[x])):
                    self.board.make_move(possible_moves[x][y], self.color)
                    current = self.search(depth - 1, possible_moves[x][y],
                                          self.color, alpha, beta)
                    self.board.undo()
                    if current > best:
                        best = current
                    if current > alpha:
                        alpha = current
                    if beta <= alpha:
                        break
                else:
                    continue
                break
            self.transposition_table[current_key] = TTEntry(best, depth)
            return best

    def get_key(self):
        key = ""
        for x in range(self.board.row):
            for y in range(self.board.col):
                if self.board.board[x][y].color == "B":
                    key += "1"
                elif self.board.board[x][y].color == "W":
                    key += "2"
                else:
                    key += "0"
        return key
예제 #29
0
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.color = ''
        self.opponent = {1: 2, 2: 1}
        self.color = 2

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1

        moves = self.board.get_all_possible_moves(self.color)
        moveValues = []

        for i in range(len(moves)):
            for j in range(len(moves[i])):
                self.board.make_move(moves[i][j], self.color)
                moveValues.append((moves[i][j],
                                   self.minimax(self.board, 3,
                                                self.opponent[self.color],
                                                float('-inf'), float('inf'))))
                self.board.undo()

        move = max(moveValues, key=lambda x: x[1])[0]
        self.board.make_move(move, self.color)
        return move

    def static_eval(self, boardState):
        blackValue = 0
        whiteValue = 0

        for i in range(boardState.row):
            for j in range(boardState.col):
                checker = boardState.board[i][j]
                if checker.color == '.':
                    continue
                elif checker.color == 'B':
                    if checker.is_king:
                        blackValue += 7 + boardState.row
                    else:
                        blackValue += 5 + checker.row
                else:
                    if checker.is_king:
                        whiteValue += 7 + boardState.row
                    else:
                        whiteValue += 5 + (boardState.row - checker.row)

        if self.color == 1:
            return blackValue - whiteValue
        else:
            return whiteValue - blackValue

    def generate_children(self, player) -> [Board]:
        children = []
        checkers = self.board.get_all_possible_moves(player)

        for moveList in checkers:
            for move in moveList:
                boardCopy = deepcopy(self.board)
                boardCopy.make_move(move, player)
                children.append(boardCopy)
        return children

    def minimax(self, boardState, depth, max_player, alpha, beta):
        if depth == 0 or boardState.is_win(max_player):
            return self.static_eval(boardState)

        if max_player:
            best = float('-inf')
            for child in self.generate_children(self.color):
                candidate = self.minimax(child, depth - 1, False, alpha, beta)
                best = max(best, candidate)
                alpha = max(alpha, candidate)
                if alpha >= beta:
                    break
            return best
        else:
            best = float('inf')
            for child in self.generate_children(self.opponent[self.color]):
                candidate = self.minimax(child, depth - 1, True, alpha, beta)
                best = min(best, candidate)
                beta = min(beta, candidate)
                if alpha >= beta:
                    break
            return best
예제 #30
0
파일: StudentAI.py 프로젝트: emmohac/delmd
class StudentAI():
    def __init__(self, col, row, p):
        self.col = col
        self.row = row
        self.p = p
        self.board = Board(col, row, p)
        self.board.initialize_game()
        self.number_of_move = 0
        self.EARLY_GAME = 10
        self.MID_GAME = 20
        self.END_GAME = 30
        self.run_time_depth = 5
        self.opponent = {1: 2, 2: 1}
        self.color = 2

    def get_move(self, move):
        if len(move) != 0:
            self.board.make_move(move, self.opponent[self.color])
        else:
            self.color = 1

        move = self.best_move()

        if self.board.row == self.board.col:
            self.run_time_depth = self.get_depth(True)
        if self.board.row != self.board.col:
            self.run_time_depth = self.get_depth(False)

        self.board.make_move(move, self.color)
        self.number_of_move += 1
        return move

    # ALPHA BETA PRUNE STARTS HERE
    def best_move(self) -> Move:
        moves = self.board.get_all_possible_moves(self.color)
        smart_move = Move([])
        alpha = -math.inf
        beta = math.inf
        for checkers in moves:
            for move in checkers:
                self.board.make_move(move, self.color)
                heuristic = self.alpha_beta_prune(1, self.opponent[self.color],
                                                  alpha, beta)
                self.board.undo()
                if heuristic > alpha:
                    alpha = heuristic
                    smart_move = Move(move)

        return smart_move

    def alpha_beta_prune(self, depth, player, alpha, beta) -> float:
        all_moves = self.board.get_all_possible_moves(player)

        if depth is self.run_time_depth:
            return self.evaluate()

        if not all_moves:
            winplayer = self.board.is_win(self.opponent[player])
            if winplayer == self.color:
                return 100000
            elif winplayer == self.opponent[self.color]:
                return -100000
            else:
                return 0

        if player is self.color:
            current_score = -math.inf
            for checker in all_moves:
                for move in checker:
                    self.board.make_move(move, player)
                    heuristic = self.alpha_beta_prune(depth + 1,
                                                      self.opponent[player],
                                                      alpha, beta)
                    self.board.undo()
                    current_score = max(heuristic, current_score)
                    alpha = max(current_score, alpha)
                    if alpha >= beta:
                        break
            return current_score
        else:
            current_score = math.inf
            for checker in all_moves:
                for move in checker:
                    self.board.make_move(move, player)
                    heuristic = self.alpha_beta_prune(depth + 1,
                                                      self.opponent[player],
                                                      alpha, beta)
                    self.board.undo()
                    current_score = min(heuristic, current_score)
                    beta = min(current_score, beta)
                    if alpha >= beta:
                        break
            return current_score

    # make new function to evaluate king
    def evaluate(self) -> float:
        white_king = 0
        white_chess = 0
        black_king = 0
        black_chess = 0

        white_king_list = list()
        black_king_list = list()

        white_chess_list = list()
        black_chess_list = list()

        for all_checkers in self.board.board:
            for checker in all_checkers:
                if checker.is_king:
                    if checker.color == "W":
                        white_king += 1
                        white_king_list.append(checker)
                    if checker.color == "B":
                        black_king += 1
                        black_king_list.append(checker)
                else:
                    if checker.color == "W":
                        white_chess += 2
                        white_chess_list.append(checker)
                    if checker.color == "B":
                        black_chess += 2
                        black_chess_list.append(checker)

                white_chess, black_chess = self.get_score(
                    checker, white_chess, black_chess)

        king_dis = 1
        if self.color == 1:
            score = self.board.black_count - self.board.white_count + (
                black_king * 8 + black_chess) - (white_chess + white_king * 5)
            for checker in black_king_list:
                for opponent in white_chess_list:
                    king_dis += self.calculate_distance(
                        checker.row, checker.col, opponent.row, opponent.col)
        else:
            score = 1 + self.board.white_count - self.board.black_count + (
                white_king * 8 + white_chess) - (black_chess + black_king * 5)
            for checker in white_king_list:
                for opponent in black_chess_list:
                    king_dis += self.calculate_distance(
                        checker.row, checker.col, opponent.row, opponent.col)

        return score / king_dis

    def calculate_distance(self, first_row, first_col, second_row,
                           second_col) -> float:
        a = abs(first_row - second_row)
        b = abs(first_col - second_col)
        return max(a, b)

    def get_depth(self, is_equal):
        if self.number_of_move != 0:
            if is_equal:
                if self.number_of_move <= 5:
                    return 3
                if self.number_of_move <= self.EARLY_GAME:
                    return 5
                if self.number_of_move <= self.END_GAME:
                    return 7
                return 3
            else:
                if 1 <= self.number_of_move <= 5:
                    return 3
                if 6 <= self.number_of_move <= 10:
                    return 5
                if self.number_of_move % 2 == 0:
                    return 5
                return 3
        return 3

    def get_score(self, checker, white_chess, black_chess):
        if checker.col == 0 or checker.col == self.col - 1:
            if checker.color == "W":
                white_chess += 1
            if checker.color == "B":
                black_chess += 1
        if checker.col - 1 > 0 and checker.row - 1 > 0:
            if self.board.board[checker.row - 1][checker.col - 1].color == "W":
                white_chess += 0.5
            if self.board.board[checker.row - 1][checker.col - 1].color == "B":
                black_chess += 0.5
        if checker.col - 1 > 0 and checker.row + 1 <= self.row - 1:
            if self.board.board[checker.row + 1][checker.col - 1].color == "W":
                white_chess += 0.5
            if self.board.board[checker.row + 1][checker.col - 1].color == "B":
                black_chess += 0.5
        if checker.col + 1 <= self.col - 1 and checker.row - 1 > 0:
            if self.board.is_in_board(checker.row - 1, checker.col + 1):
                if self.board.board[checker.row - 1][checker.col +
                                                     1].color == "W":
                    white_chess += 0.5
                if self.board.board[checker.row - 1][checker.col +
                                                     1].color == "B":
                    black_chess += 0.5
        if checker.col + 1 < self.col - 1 and checker.row + 1 <= self.row - 1:
            if self.board.is_in_board(checker.row + 1, checker.col + 1):
                if self.board.board[checker.row + 1][checker.col + 1] == "W":
                    white_chess += 0.5
                if self.board.board[checker.row + 1][checker.col + 1] == "B":
                    black_chess += 0.5

        return white_chess, black_chess