in hanabi-learning-environment/hanabi_lib/canonical_encoders.cc [450:519]
int EncodeCardKnowledge(const HanabiGame& game,
const HanabiObservation& obs,
int start_offset,
const std::vector<int>& order,
bool shuffle_color,
const std::vector<int>& color_permute,
std::vector<float>* encoding) {
int bits_per_card = BitsPerCard(game);
int num_colors = game.NumColors();
int num_ranks = game.NumRanks();
int num_players = game.NumPlayers();
int hand_size = game.HandSize();
int offset = start_offset;
const std::vector<HanabiHand>& hands = obs.Hands();
assert(hands.size() == num_players);
for (int player = 0; player < num_players; ++player) {
const std::vector<HanabiHand::CardKnowledge>& knowledge =
hands[player].Knowledge();
int num_cards = 0;
for (int i = 0; i < knowledge.size(); ++i) {
// for (const HanabiHand::CardKnowledge& card_knowledge : knowledge) {
int card_idx = i;
if (player != 0 && order.size() > 0) {
card_idx = order[i];
}
const auto& card_knowledge = knowledge[card_idx];
// Add bits for plausible card.
for (int color = 0; color < num_colors; ++color) {
if (card_knowledge.ColorPlausible(color)) {
for (int rank = 0; rank < num_ranks; ++rank) {
if (card_knowledge.RankPlausible(rank)) {
int card_idx = CardIndex(color, rank, num_ranks, shuffle_color, color_permute);
(*encoding)[offset + card_idx] = 1;
}
}
}
}
offset += bits_per_card;
// Add bits for explicitly revealed colors and ranks.
if (card_knowledge.ColorHinted()) {
int color = card_knowledge.Color();
if (shuffle_color) {
color = color_permute[color];
}
(*encoding)[offset + color] = 1;
}
offset += num_colors;
if (card_knowledge.RankHinted()) {
(*encoding)[offset + card_knowledge.Rank()] = 1;
}
offset += num_ranks;
++num_cards;
}
// A player's hand can have fewer cards than the initial hand size.
// Leave the bits for the absent cards empty (adjust the offset to skip
// bits for the missing cards).
if (num_cards < hand_size) {
offset +=
(hand_size - num_cards) * (bits_per_card + num_colors + num_ranks);
}
}
assert(offset - start_offset == CardKnowledgeSectionLength(game));
return offset - start_offset;
}