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
    def train_one_episode(self):
        new_board = Board()
        new_board.initialize_game()
        turn = ''

        while True:
            if new_board.is_win(self.color):
                break
            elif new_board.is_win(self.opponent[self.color]):
                break

            action = self.explore(new_board, self.color)
            state = new_board
            new_state = new_board.make_move(action, turn)
            self.Q_table[state, action] = self.Q_table[state, action] + self.lr * \
                                          (self.reward(state, action) + self.gamma * np.max(self.Q_tableQ[new_state, :])\
                                           - self.Q_table[state, action])
            state = new_state
Exemple #3
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
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
Exemple #5
0
 def alpha_beta_negamax(self, board: Board, depth: int, max_depth: int, alpha: int, beta: int, start_time: int) -> MoveWithAnalysis:
     if time.time() - start_time > TIME_LIMIT:
         # print("Depth: {}".format(depth))
         return None
     if board.is_win() or depth > max_depth:
         # print("Depth: {}".format(depth))
         if depth % 2 == 0:
             heuristic = self.evaluate_board(board, self.player_number)
             current_move = MoveWithAnalysis(None, None, heuristic)
             return current_move
         else:
             heuristic = self.evaluate_board(board, self.opponent_number)
             current_move = MoveWithAnalysis(None, None, -heuristic)
             return current_move
     best_move = None
     if self.valid_moves.empty() and not self.moves_generated:
         children = self.expand_node(board)
         for child in children:
             result_board = copy.deepcopy(board)
             result_board = result_board.make_move(child, self.player_number)
             current_move = MoveWithAnalysis(child.col, child.row, 0)
             current_move.heuristic = self.evaluate_board(result_board, self.player_number)
             self.valid_moves.put(current_move)
         self.moves_generated = True
         # self.valid_moves.sort(reverse=True)
     if depth == 0:
         temp_queue = PriorityQueue()
         while not self.valid_moves.empty():
             valid_move = self.valid_moves.get()
             result_board = copy.deepcopy(board)
             result_board = result_board.make_move(valid_move, self.player_number)
             current_move = self.alpha_beta_negamax(result_board, depth + 1, max_depth, -beta, -alpha, start_time)
             if current_move is None:
                 return None
             current_move.col = valid_move.col
             current_move.row = valid_move.row
             current_move.heuristic = -current_move.heuristic
             valid_move.heuristic = current_move.heuristic
             temp_queue.put(valid_move)
             # print("({}, {}): {}".format(valid_move.col, valid_move.row, valid_move.heuristic))
             if best_move is None or current_move.heuristic > best_move.heuristic:
                 best_move = current_move
             if current_move.heuristic > alpha:
                 alpha = current_move.heuristic
             if alpha >= beta:
                 # print("PRUNED")
                 return best_move
         self.valid_moves = temp_queue
     else:
         children = self.expand_node(board)
         for child in children:
             result_board = copy.deepcopy(board)
             if depth % 2 == 0:
                 result_board = result_board.make_move(child, self.player_number)
             else:
                 result_board = result_board.make_move(child, self.opponent_number)
             current_move = self.alpha_beta_negamax(result_board, depth + 1, max_depth, -beta, -alpha, start_time)
             if current_move is None:
                 return None
             current_move.col = child.col
             current_move.row = child.row
             current_move.heuristic = -current_move.heuristic
             if best_move is None or current_move.heuristic > best_move.heuristic:
                 best_move = current_move
             if current_move.heuristic > alpha:
                 alpha = current_move.heuristic
             if alpha >= beta:
                 # print("PRUNED")
                 return best_move
     return best_move
Exemple #6
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
Exemple #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.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
Exemple #8
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
Exemple #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):
        # 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
Exemple #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
        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)]