int EncodeCardKnowledge()

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;
}