コード例 #1
0
    def select_final_move(self, rootnode, rootstate):
        node = max(rootnode.childNodes, key=lambda c: c.visits)
        final_move = max(rootnode.childNodes, key=lambda c: c.visits
                         ).move  # return the move that was most visited

        opponent, guess = None, None
        # play against human player if we can
        if rootstate.real_players and not rootstate.real_players[
                0].lost and not rootstate.real_players[0].defence:
            opponent = rootstate.real_players[0]

        if final_move.name == "Guard":
            # if final move is Guard, then guess card
            opponent, guess = get_guess_card(rootstate.user_ctl.users,
                                             rootstate.playerToMove,
                                             rootstate.seen_cards)
        # control treshold for playing the Baron
        elif len(rootnode.childNodes) > 1 and final_move.name == "Baron" and node.wins / node.visits < 0.6 and \
                rootnode.childNodes[0].move.name != "Princess" and rootnode.childNodes[1].move.name != "Princess":
            if rootnode.childNodes[0].move.name != "Baron":
                return rootnode.childNodes[0].move, opponent, None
            else:
                return rootnode.childNodes[1].move, opponent, None

        return final_move, opponent, None
コード例 #2
0
    def get_move(state):
        # print(state.playerHands[state.playerToMove])
        move, victim, guess = get_move(state, ismcts=True)

        if move:
            return move, victim, guess

        move_counter = defaultdict(int)
        moves = state.get_moves()

        for _ in range(201):
            rootstate = state.clone_and_randomize()
            value, move = Minimax._minimax(rootstate, True, -Minimax.INF, Minimax.INF, 1)
            move_counter[move] += 1

        # from pprint import pprint
        # pprint(move_counter)

        result_move = max(moves, key=lambda item: move_counter[item])
        victim, guess = None, None

        if result_move.name == "Guard":
            victim, guess = get_guess_card(state.user_ctl.users, state.playerToMove, state.seen_cards)

        return result_move, victim, guess
コード例 #3
0
 def select(self, state, node, **kwargs):
     """
     Selection step
     :param state: current state of the game
     :return:
     """
     assert len(state.playerHands[state.playerToMove]) == 2
     while not state.round_over and not node.get_untried_moves(
             state.get_moves()):
         victim, guess = None, None
         # node is fully expanded and non-terminal
         available_moves = state.get_moves()
         node = node.ucb_select_child(available_moves)
         if node.move.name == "Guard" and kwargs.get('extra', False):
             victim, guess = get_guess_card(state.user_ctl.users,
                                            state.playerToMove,
                                            state.seen_cards)
         state.do_move(node.move,
                       victim=victim,
                       guess=guess,
                       verbose=kwargs.get('verbose', False))
     return node
コード例 #4
0
    def _minimax(state, is_maximizing_player, alpha, beta, depth):
        if state.round_over:
            try:
                assert len([1 for user in state.user_ctl.users if user.lost]) == 1 or not state.deck
            except AssertionError:
                import pdb
                pdb.set_trace()
            if not state.deck:
                def played_card_sum(player):
                    result = 0
                    for moved_player, card in state.currentTrick:
                        if moved_player == player:
                            result += card.value
                    return result

                cards = [(player, state.playerHands[player], played_card_sum(player))
                         for player in state.user_ctl.users
                         if not player.lost]

                cards.sort(key=lambda item: (item[1], item[2]), reverse=True)

                winner = cards[0][0]

                if winner == state.playerToMove:
                    if is_maximizing_player:
                        return depth - 100, None
                    else:
                        return 100 - depth, None
                else:
                    if is_maximizing_player:
                        return 100 - depth, None
                    else:
                        return depth - 100, None

            if is_maximizing_player:
                return depth - 100, None
            else:
                return 100 - depth, None

        if is_maximizing_player:
            best_value = -Minimax.INF
        else:
            best_value = Minimax.INF
        previous_move = None
        best_move = None

        for move in state.get_moves():
            if move == previous_move:
                continue
            previous_move = move
            victim, guess = None, None

            if move.name == "Guard":
                victim, guess = get_guess_card(state.user_ctl.users, state.playerToMove, state.seen_cards)

            state_copy = deepcopy(state)

            state_copy.do_move(move, victim=victim, guess=guess)

            value, _ = Minimax._minimax(state_copy, not is_maximizing_player, alpha, beta,depth + 1)

            if is_maximizing_player:
                if best_value < value:
                    best_value = value
                    best_move = move
                alpha = max(alpha, best_value)
            else:
                if best_value > value:
                    best_value = value
                    best_move = move
                beta = min(beta, best_value)

            if beta <= alpha:
                break

        return best_value, best_move
コード例 #5
0
    def get_move(self, rootstate, itermax, verbose=True, **kwargs):
        """ Conduct an ISMCTS search for itermax iterations starting from rootstate.
            Return the best move from the rootstate.
        """
        print(rootstate.playerHands[rootstate.playerToMove])
        move, victim, guess = get_move(rootstate, ismcts=True)

        if move:
            return move, victim, guess

        moves = rootstate.get_moves()

        trees_number = kwargs.get('trees_number', 50)

        decision_counter = defaultdict(int)

        for j in range(trees_number):
            state_copy = rootstate.clone_and_randomize()
            rootnode = Node()
            counter = 0
            for i in range(itermax // trees_number):
                state = deepcopy(state_copy)
                node = rootnode
                # determinize
                node = self.select(state, node)
                if counter == 5:
                    print(rootnode.tree_to_string(indent=0))
                node = self.expand(state, node)
                if counter == 5:
                    print(rootnode.tree_to_string(indent=0))
                self.simulate(state)
                if counter == 5:
                    print(rootnode.tree_to_string(indent=0))
                self.backpropagate(state, node)
                if counter == 5:
                    print(rootnode.tree_to_string(indent=0))
                    import pdb
                    pdb.set_trace()
                counter += 1
            decision_counter[self.select_final_move(rootnode,
                                                    rootstate)[0]] += 1

        # Output some information about the tree - can be omitted
        print("{} -> {}".format(moves[0], decision_counter[moves[0]]))
        print("{} -> {}".format(moves[1], decision_counter[moves[1]]))

        if decision_counter[moves[0]] >= decision_counter[moves[1]]:
            if moves[0].name == "Guard":
                # if final move is Guard, then guess card
                victim, guess = get_guess_card(rootstate.user_ctl.users,
                                               rootstate.playerToMove,
                                               rootstate.seen_cards)
                if guess:
                    return moves[0], victim, guess
            return moves[0], None, None
        else:
            if moves[1].name == "Guard":
                # if final move is Guard, then guess card
                victim, guess = get_guess_card(rootstate.user_ctl.users,
                                               rootstate.playerToMove,
                                               rootstate.seen_cards)
                if guess:
                    return moves[1], victim, guess
            return moves[1], None, None
コード例 #6
0
def get_move(state, ismcts=False):
    # TODO: fix multiple opponents case (selecting opponents)
    cards = state.playerHands[state.playerToMove]
    victim, guess = None, None
    maid = Maid()
    guard = Guard()
    princess = Princess()
    priest = Priest()
    baron = Baron()
    prince = Prince()
    king = King()
    countess = Countess()
    opponent = [
        player for player in state.user_ctl.users
        if player != state.playerToMove
    ][0]
    twin_cards = [priest, baron, maid, priest]

    victim, guess = get_guess_card(state.user_ctl.users, state.playerToMove,
                                   state.seen_cards)

    card_count = {
        Princess(): 1,
        Countess(): 1,
        King(): 1,
        Prince(): 2,
        Maid(): 2,
        Baron(): 2,
        Priest(): 2,
        Guard(): 5,
    }
    # substract used cards
    for card, counter in state.used_cards.items():
        card_count[card] -= counter
        assert card_count[card] >= 0

    # substract cards in hand
    for card in state.playerHands[state.playerToMove]:
        card_count[card] -= 1
        assert card_count[card] >= 0

    def play_guard():
        """
        Selects probable guess when playing with Guard
        :return: probable guess card
        """
        available_cards = sorted(
            [(counter, card)
             for card, counter in card_count.items() if card != guard],
            reverse=True)
        most_probable_cards = [
            card for counter, card in available_cards
            if counter == available_cards[0][0]
        ]
        return random.choice(most_probable_cards)

    def get_probability(player_card):
        c = 0
        if card_count[player_card] > 0:
            for card in twin_cards:
                if card_count[card] == 2 or (card_count[card] == 1
                                             and card in cards):
                    c += 1
            return 1 / c

        for card, counter in card_count.items():
            if counter > 0 or card in cards:
                c += 1

        return 1 / c

    def lose_with_baron(card):
        """
        Will the current player lose the game if he makes move with Baron
        :param card:
        :return:
        """
        if card != baron:
            return False
        if cards[0] == baron:
            if guess and cards[1] <= guess:
                return True
            if cards[1] <= baron:
                return True

        if cards[1] == baron:
            if guess and cards[0] <= guess:
                return True
            if cards[0] <= baron:
                return True

        return False

    # follow the rules about Countess
    if countess in cards:
        if king in cards:
            return king, None, None
        if prince in cards:
            return prince, None, None

    # if player has guard and knows an opponent's card
    if guard in cards and victim:
        return guard, victim, guess

    # if player knows an opponent's card and has a greater card
    if baron in cards and victim:
        if cards[0] == baron and cards[1] > guess:
            return baron, victim, None
        if cards[1] == baron and cards[0] > guess:
            return baron, victim, None

    # play with prince if player holds the princess
    if guess == princess and prince in cards:
        return prince, victim, None

    # make last move with minimal card
    if sum(card_count.values()) <= 2:
        card = min(cards)
        if card == guard:
            guess = play_guard()
        return min(cards), victim, guess

    # do not play with princess
    if cards[0] == princess:
        if cards[1] == guard:
            guess = play_guard()
        return cards[1], victim, guess

    # do not play with princess
    try:
        if cards[1] == princess:
            if cards[0] == guard:
                guess = play_guard()
            return cards[0], victim, guess
    except:
        import pdb
        pdb.set_trace()

    # if both cards are same, play any of them
    for card in card_dict.values():
        if cards.count(card) == 2:
            if card == guard:
                guess = play_guard()
            assert guess != guard
            return card, victim, guess

    # return seen card by an opponent if any
    for card in cards:
        # TODO: когда мы не видели карту, но нашего барона видели, а вторая карта слишком маленькая
        if not ismcts and card != guard and card in state.seen_cards[opponent][
                state.playerToMove] and card_count[
                    guard] > 0 and not lose_with_baron(card):
            return card, victim, guess

    # Guard and Priest
    if not ismcts and guard in cards and priest in cards:
        return priest, victim, guess

    # check if twin card has high prob to be guessed
    for card in twin_cards:
        # TODO: когда мы не видели карту, но нашего барона видели, а вторая карта слишком маленькая
        if not ismcts and card in cards and get_probability(
                card) >= 0.5 and card_count[guard] > 0 and not lose_with_baron(
                    card):
            return card, victim, guess

    # return nothing for ismcts algorithm
    if ismcts:
        return [None] * 3

    card = min(cards)
    if card == guard:
        guess = play_guard()
    if lose_with_baron(card):
        card = max(cards)
    return card, victim, guess