diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 51ec9c14a..5cacc0b88 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -192,8 +192,8 @@ maskPointChin = MaskPoint; maskPosition point:MaskPoint x_shift:double y_shift:double scale:double = MaskPosition; -//@description Describes one answer option of a poll @text Option text, 1-100 characters @voter_count Number of voters for this option @is_chosen True, if the option was chosen by the user -pollOption text:string voter_count:int32 is_chosen:Bool = PollOption; +//@description Describes one answer option of a poll @text Option text, 1-100 characters @voter_count Number of voters for this option @vote_percentage The percentage of votes for this option, 0-100 @is_chosen True, if the option was chosen by the user +pollOption text:string voter_count:int32 vote_percentage:int32 is_chosen:Bool = PollOption; //@description Describes an animation file. The animation must be encoded in GIF or MPEG4 format @duration Duration of the animation, in seconds; as defined by the sender @width Width of the animation @height Height of the animation diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index f6bb9fe02..470b3af4f 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/PollManager.cpp b/td/telegram/PollManager.cpp index 3ac6c0060..76ccf0a2d 100644 --- a/td/telegram/PollManager.cpp +++ b/td/telegram/PollManager.cpp @@ -308,7 +308,98 @@ PollManager::Poll *PollManager::get_poll_force(PollId poll_id) { } td_api::object_ptr PollManager::get_poll_option_object(const PollOption &poll_option) { - return td_api::make_object(poll_option.text, poll_option.voter_count, poll_option.is_chosen); + return td_api::make_object(poll_option.text, poll_option.voter_count, 0, poll_option.is_chosen); +} + +vector PollManager::get_vote_percentage(const vector &voter_counts, int32 total_voter_count) { + vector result(voter_counts.size(), 0); + if (total_voter_count == 0 || voter_counts.empty()) { + return result; + } + + int32 sum = 0; + for (auto voter_count : voter_counts) { + CHECK(0 <= voter_count); + CHECK(voter_count <= std::numeric_limits::max() - sum); + sum += voter_count; + } + CHECK(total_voter_count <= sum); + if (total_voter_count != sum) { + // just round to the nearest + for (size_t i = 0; i < result.size(); i++) { + result[i] = + static_cast((static_cast(voter_counts[i]) * 200 + total_voter_count) / total_voter_count / 2); + } + return result; + } + + // make sure that options with equal votes have equal percent and total sum is less than 100% + int32 percent_sum = 0; + vector gap(voter_counts.size(), 0); + for (size_t i = 0; i < result.size(); i++) { + auto multiplied_voter_count = static_cast(voter_counts[i]) * 100; + result[i] = static_cast(multiplied_voter_count / total_voter_count); + CHECK(0 <= result[i] && result[i] <= 100); + gap[i] = static_cast(static_cast(result[i] + 1) * total_voter_count - multiplied_voter_count); + CHECK(0 <= gap[i] && gap[i] <= total_voter_count); + percent_sum += result[i]; + } + CHECK(0 <= percent_sum && percent_sum <= 100); + if (percent_sum == 100) { + return result; + } + + // now we need to choose up to (100 - percent_sum) options with minimum total gap, such so + // any two options with the same voter_count are chosen or not chosen simultaneously + struct Option { + int32 pos = -1; + int32 count = 0; + }; + std::unordered_map options; + for (size_t i = 0; i < result.size(); i++) { + auto &option = options[voter_counts[i]]; + option.pos = i; + option.count++; + } + vector