bool SimpleBot::maybeGiveHelpfulHint()

in csrc/SimpleBot.cc [189:269]


bool SimpleBot::maybeGiveHelpfulHint(Server &server)
{
    if (server.hintStonesRemaining() == 0) return false;

    const int numPlayers = handKnowledge_.size();
    int best_so_far = 0;
    int player_to_hint = -1;
    int color_to_hint = -1;
    int value_to_hint = -1;
    for (int i = 1; i < numPlayers; ++i) {
        const int partner = (me_ + i) % numPlayers;
        assert(partner != me_);
        const std::vector<Card> partners_hand = server.handOfPlayer(partner);
        bool is_really_playable[5];
        for (int c=0; c < partners_hand.size(); ++c) {
            is_really_playable[c] =
                server.pileOf(partners_hand[c].color).nextValueIs(partners_hand[c].value);
        }
        /* Can we construct a color hint that gives our partner information
         * about unknown-playable cards, without also including any
         * unplayable cards? */
        for (Color color = RED; color <= BLUE; ++color) {
            int information_content = 0;
            bool misinformative = false;
            for (int c=0; c < partners_hand.size(); ++c) {
                if (partners_hand[c].color != color) continue;
                if (is_really_playable[c] &&
                    !handKnowledge_[partner][c].isPlayable)
                {
                    information_content += 1;
                } else if (!is_really_playable[c]) {
                    misinformative = true;
                    break;
                }
            }
            if (misinformative) continue;
            if (information_content > best_so_far) {
                best_so_far = information_content;
                color_to_hint = color;
                value_to_hint = -1;
                player_to_hint = partner;
            }
        }

        for (int value = 1; value <= 5; ++value) {
            int information_content = 0;
            bool misinformative = false;
            for (int c=0; c < partners_hand.size(); ++c) {
                if (partners_hand[c].value != value) continue;
                if (is_really_playable[c] &&
                    !handKnowledge_[partner][c].isPlayable)
                {
                    information_content += 1;
                } else if (!is_really_playable[c]) {
                    misinformative = true;
                    break;
                }
            }
            if (misinformative) continue;
            if (information_content > best_so_far) {
                best_so_far = information_content;
                color_to_hint = -1;
                value_to_hint = value;
                player_to_hint = partner;
            }
        }
    }

    if (best_so_far == 0) return false;

    /* Give the hint. */
    if (color_to_hint != -1) {
        server.pleaseGiveColorHint(player_to_hint, Color(color_to_hint));
    } else if (value_to_hint != -1) {
        server.pleaseGiveValueHint(player_to_hint, Value(value_to_hint));
    } else {
        assert(false);
    }

    return true;
}