• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

APN-Pucky / tyrant_optimize / 20460090975

23 Dec 2025 11:54AM UTC coverage: 70.463% (+0.06%) from 70.399%
20460090975

push

github

dsuchka
Fix Enhance for Hunt and Mark

Looks like it is a game bug, but Hunt and Mark both
can be enhanced on inactive units. Implement it.

1 of 1 new or added line in 1 file covered. (100.0%)

3 existing lines in 2 files now uncovered.

4783 of 6788 relevant lines covered (70.46%)

8587459.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.14
/algorithms_util.cpp
1
#include "algorithms_util.h"
2
void copy_deck(Deck* src,Deck* dst)
2,830✔
3
{
4
        dst->commander = src->commander;
2,830✔
5
        dst->alpha_dominion = src->alpha_dominion;
2,830✔
6
        dst->cards = src->cards;
2,830✔
7
}
2,830✔
8
std::string card_id_name(const Card* card)
×
9
{
10
        std::stringstream ios;
×
11
        if (card)
×
12
        {
13
                ios << "[" << card->m_id << "] " << card->m_name;
×
14
        }
15
        else
16
        {
17
                ios << "-void-";
×
18
        }
19
        return ios.str();
×
20
}
×
21
std::string card_slot_id_names(const std::vector<std::pair<signed, const Card *>> card_list)
50✔
22
{
23
        if (card_list.empty())
50✔
24
        {
UNCOV
25
                return "-void-";
×
26
        }
27
        std::stringstream ios;
50✔
28
        std::string separator = "";
50✔
29
        for (const auto & card_it : card_list)
100✔
30
        {
31
                ios << separator;
50✔
32
                separator = ", ";
50✔
33
                if (card_it.first >= 0)
50✔
34
                { ios << card_it.first << " "; }
×
35
                ios << "[" << card_it.second->m_id << "] " << card_it.second->m_name;
50✔
36
        }
37
        return ios.str();
50✔
38
}
50✔
39
// remove val from oppo if found, otherwise append val to self
40
        template <typename C>
41
void append_unless_remove(C & self, C & oppo, typename C::const_reference val)
×
42
{
43
        for (auto it = oppo.begin(); it != oppo.end(); ++ it)
×
44
        {
45
                if (*it == val)
×
46
                {
47
                        oppo.erase(it);
×
48
                        return;
×
49
                }
50
        }
51
        self.push_back(val);
×
52
}
53

54
// insert card at to_slot into deck limited by fund; store deck_cost
55
// return true if affordable
56
bool adjust_deck(Deck * deck, const signed from_slot, const signed to_slot, const Card * card, unsigned fund, std::mt19937 & re, unsigned & deck_cost,
2,221✔
57
                std::vector<std::pair<signed, const Card *>> & cards_out, std::vector<std::pair<signed, const Card *>> & cards_in)
58
{
59
        bool is_random = (deck->strategy == DeckStrategy::random) || (deck->strategy == DeckStrategy::flexible);
2,221✔
60
        cards_out.clear();
2,221✔
61
        cards_in.clear();
2,221✔
62
        if (from_slot < 0)
2,221✔
63
        {
64
                if (card->m_category == CardCategory::dominion_alpha)
841✔
65
                { // change alpha dominion
66
                        cards_out.emplace_back(-1, deck->alpha_dominion);
186✔
67
                        deck->alpha_dominion = card;
186✔
68
                        cards_in.emplace_back(-1, deck->alpha_dominion);
186✔
69
                        deck_cost = get_deck_cost(deck);
186✔
70
                        return true;
186✔
71
                }
72

73
                // change commander
74
                cards_out.emplace_back(-1, deck->commander);
655✔
75
                deck->commander = card;
655✔
76
                cards_in.emplace_back(-1, deck->commander);
655✔
77
                deck_cost = get_deck_cost(deck);
655✔
78
                return (deck_cost <= fund);
655✔
79
        }
80
        if (from_slot < (signed)deck->cards.size())
1,380✔
81
        { // remove card from the deck
82
                cards_out.emplace_back(is_random ? -1 : from_slot, deck->cards[from_slot]);
1,368✔
83
                deck->cards.erase(deck->cards.begin() + from_slot);
1,368✔
84
        }
85
        if (card == nullptr)
1,380✔
86
        { // remove card (no new replacement for removed card)
87
                deck_cost = get_deck_cost(deck);
51✔
88
                return (deck_cost <= fund);
51✔
89
        }
90

91
        // backup deck cards
92
        const Card * old_commander = deck->commander;
1,329✔
93
        std::vector<const Card *> cards = deck->cards;
1,329✔
94

95
        // try to add new card into the deck, downgrade it if necessary
96
        {
1,329✔
97
                const Card * candidate_card = card;
1,329✔
98
                deck->commander = nullptr;
1,329✔
99
                deck->cards.clear();
1,329✔
100
                deck->cards.emplace_back(card);
1,329✔
101
                deck_cost = get_deck_cost(deck);
1,329✔
102
                if (!use_top_level_card && (deck_cost > fund))
1,329✔
103
                {
104
                        while ((deck_cost > fund) && !candidate_card->is_low_level_card())
×
105
                        {
106
                                candidate_card = candidate_card->downgraded();
×
107
                                deck->cards[0] = candidate_card;
×
108
                                deck_cost = get_deck_cost(deck);
×
109
                        }
110
                }
111
                if (deck_cost > fund)
1,329✔
112
                { return false; }
113
                cards_in.emplace_back(is_random ? -1 : to_slot, deck->cards[0]);
1,329✔
114
        }
115

116
        // try to add commander into the deck, downgrade it if necessary
117
        {
1,329✔
118
                const Card * candidate_card = old_commander;
1,329✔
119
                deck->commander = candidate_card;
1,329✔
120
                deck_cost = get_deck_cost(deck);
1,329✔
121
                if (!use_top_level_commander && (deck_cost > fund))
1,329✔
122
                {
123
                        while ((deck_cost > fund) && !candidate_card->is_low_level_card())
×
124
                        {
125
                                candidate_card = candidate_card->downgraded();
×
126
                                deck->commander = candidate_card;
×
127
                                deck_cost = get_deck_cost(deck);
×
128
                        }
129
                }
130
                if (deck_cost > fund)
1,329✔
131
                { return false; }
132
                if (deck->commander != old_commander)
1,329✔
133
                {
134
                        append_unless_remove(cards_out, cards_in, {-1, old_commander});
×
135
                        append_unless_remove(cards_in, cards_out, {-1, deck->commander});
×
136
                }
137
        }
138

139
        // added backuped deck cards back (place cards strictly before/after card inserted above according to slot index)
140
        for (signed i = 0; i < (signed)cards.size(); ++ i)
10,105✔
141
        {
142
                // try to add cards[i] into the deck, downgrade it if necessary
143
                const Card * candidate_card = cards[i];
9,290✔
144
                auto in_it = deck->cards.end() - (i < to_slot); // (before/after according to slot index)
9,290✔
145
                in_it = deck->cards.insert(in_it, candidate_card);
9,290✔
146
                deck_cost = get_deck_cost(deck);
9,290✔
147
                if (!use_top_level_card && (deck_cost > fund))
9,290✔
148
                {
149
                        while ((deck_cost > fund) && !candidate_card->is_low_level_card())
×
150
                        {
151
                                candidate_card = candidate_card->downgraded();
×
152
                                *in_it = candidate_card;
×
153
                                deck_cost = get_deck_cost(deck);
×
154
                        }
155
                }
156
                if (deck_cost > fund)
9,290✔
157
                { return false; }
514✔
158
                if (*in_it != cards[i])
8,776✔
159
                {
160
                        append_unless_remove(cards_out, cards_in, {is_random ? -1 : i + (i >= from_slot), cards[i]});
×
161
                        append_unless_remove(cards_in, cards_out, {is_random ? -1 : i + (i >= to_slot), *in_it});
×
162
                }
163
        }
164
        return !cards_in.empty() || !cards_out.empty();
815✔
165
}
1,329✔
166

167
unsigned check_requirement(const Deck* deck, const Requirement & requirement
1,891✔
168
#ifndef NQUEST
169
                , const Quest & quest
170
#endif
171
                )
172
{
173
        unsigned gap = safe_minus(min_deck_len, deck->cards.size());
1,891✔
174
        if (!requirement.num_cards.empty())
1,891✔
175
        {
176
                std::unordered_map<const Card*, unsigned> num_cards;
×
177
                num_cards[deck->commander] = 1;
×
178
                for (auto card: deck->cards)
×
179
                {
180
                        ++ num_cards[card];
×
181
                }
182
                for (auto it: requirement.num_cards)
×
183
                {
184
                        gap += safe_minus(it.second, num_cards[it.first]);
×
185
                }
186
        }
×
187
#ifndef NQUEST
188
        if (quest.quest_type != QuestType::none)
189
        {
190
                unsigned potential_value = 0;
191
                switch (quest.quest_type)
192
                {
193
                        case QuestType::skill_use:
194
                        case QuestType::skill_damage:
195
                                for (const auto & ss: deck->commander->m_skills)
196
                                {
197
                                        if (quest.quest_key == ss.id)
198
                                        {
199
                                                potential_value = quest.quest_value;
200
                                                break;
201
                                        }
202
                                }
203
                                break;
204
                        case QuestType::faction_assault_card_kill:
205
                        case QuestType::type_card_kill:
206
                                potential_value = quest.quest_value;
207
                                break;
208
                        default:
209
                                break;
210
                }
211
                for (auto card: deck->cards)
212
                {
213
                        switch (quest.quest_type)
214
                        {
215
                                case QuestType::skill_use:
216
                                case QuestType::skill_damage:
217
                                        for (const auto & ss: card->m_skills)
218
                                        {
219
                                                if (quest.quest_key == ss.id)
220
                                                {
221
                                                        potential_value = quest.quest_value;
222
                                                        break;
223
                                                }
224
                                        }
225
                                        break;
226
                                case QuestType::faction_assault_card_use:
227
                                        potential_value += (quest.quest_key == card->m_faction);
228
                                        break;
229
                                case QuestType::type_card_use:
230
                                        potential_value += (quest.quest_key == card->m_type);
231
                                        break;
232
                                default:
233
                                        break;
234
                        }
235
                        if (potential_value >= (quest.must_fulfill ? quest.quest_value : 1))
236
                        {
237
                                break;
238
                        }
239
                }
240
                gap += safe_minus(quest.must_fulfill ? quest.quest_value : 1, potential_value);
241
        }
242
#endif
243
        return gap;
1,891✔
244
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc