in csrc/HolmesBot.cc [500:571]
Hint HolmesBot::bestHintForPlayer(const Server &server, int partner) const
{
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);
}
Hint best_so_far;
best_so_far.to = partner;
/* 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) {
const CardKnowledge &knol = handKnowledge_[partner][c];
if (partners_hand[c].color != color) continue;
if (is_really_playable[c] && !knol.isPlayable) {
information_content += 1;
} else if (!is_really_playable[c] && (knol.value() == -1 && !knol.isWorthless)) {
misinformative = true;
break;
}
}
if (misinformative) continue;
if (information_content > best_so_far.information_content) {
best_so_far.information_content = information_content;
best_so_far.color = color;
best_so_far.value = -1;
}
}
/* Avoid giving hints that could be misinterpreted as warnings. */
const int discardIndex = nextDiscardIndex(server, partner);
int valueToAvoid = -1;
if (discardIndex != -1) {
const CardKnowledge &knol = handKnowledge_[partner][discardIndex];
valueToAvoid = partners_hand[discardIndex].value;
if (!couldBeValuable(server, knol, valueToAvoid)) valueToAvoid = -1;
}
for (int value = 1; value <= 5; ++value) {
if (value == valueToAvoid) continue;
int information_content = 0;
bool misinformative = false;
for (int c=0; c < partners_hand.size(); ++c) {
const CardKnowledge &knol = handKnowledge_[partner][c];
if (partners_hand[c].value != value) continue;
if (is_really_playable[c] && !knol.isPlayable)
{
information_content += 1;
} else if (!is_really_playable[c] && (knol.color() == -1 && !knol.isWorthless)) {
misinformative = true;
break;
}
}
if (misinformative) continue;
if (information_content > best_so_far.information_content) {
best_so_far.information_content = information_content;
best_so_far.color = -1;
best_so_far.value = value;
}
}
return best_so_far;
}