int EncodeHands()

in hanabi-learning-environment/hanabi_lib/canonical_encoders.cc [70:142]


int EncodeHands(const HanabiGame& game,
                const HanabiObservation& obs,
                int start_offset,
                bool show_own_cards,
                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_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<HanabiCard>& cards = hands[player].Cards();
    int num_cards = 0;

    // for (const HanabiCard& card : cards) {
    for (int i = 0; i < cards.size(); ++i) {
      int card_i = i;
      if (player != 0 && order.size() > 0) {
        card_i = order[i];
      }
      const auto& card = cards[card_i];
      // Only a player's own cards can be invalid/unobserved.
      // assert(card.IsValid());
      assert(card.Color() < game.NumColors());
      assert(card.Rank() < num_ranks);
      if (player == 0) {
        if (show_own_cards) {
          assert(card.IsValid());
          // std::cout << offset << CardIndex(card.Color(), card.Rank(), num_ranks) << std::endl;
          // std::cout << card.Color() << ", " << card.Rank() << ", " << num_ranks << std::endl;
          auto card_idx = CardIndex(
              card.Color(), card.Rank(), num_ranks, shuffle_color, color_permute);
          (*encoding).at(offset + card_idx) = 1;
        } else {
          assert(!card.IsValid());
          // (*encoding).at(offset + CardIndex(card.Color(), card.Rank(), num_ranks)) = 0;
        }
      } else {
        assert(card.IsValid());
        auto card_idx = CardIndex(
            card.Color(), card.Rank(), num_ranks, shuffle_color, color_permute);
        (*encoding).at(offset + card_idx) = 1;
      }

      ++num_cards;
      offset += bits_per_card;
    }

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

  // For each player, set a bit if their hand is missing a card.
  for (int player = 0; player < num_players; ++player) {
    if (hands[player].Cards().size() < game.HandSize()) {
      (*encoding)[offset + player] = 1;
    }
  }
  offset += num_players;

  assert(offset - start_offset == HandsSectionLength(game));
  return offset - start_offset;
}