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

APN-Pucky / tyrant_optimize / 26396287599

25 May 2026 10:39AM UTC coverage: 70.501% (+0.1%) from 70.364%
26396287599

Pull #112

github

web-flow
Merge 330a16f82 into adf7c9377
Pull Request #112: Correct skipped-simulation accounting by counting DB-hit results as skipped

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

2 existing lines in 1 file now uncovered.

4799 of 6807 relevant lines covered (70.5%)

8983151.52 hits per line

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

91.51
/sim_test.cpp
1
// exec: ./tuo-test , verbose: ./tuo-test --log_level=all
2
// set-iterations ./tuo-test 100  , default = 10 // more than 100 cause errors
3
#ifdef TEST
4
#ifdef NQUEST // only without quests
5
#define BOOST_TEST_DYN_LINK
6
#define BOOST_TEST_MODULE sim
7

8
#include <chrono>
9
#include <boost/test/included/unit_test.hpp>
10
#include <boost/test/data/test_case.hpp>
11
#include <boost/test/data/monomorphic.hpp>
12
#include <iostream>
13
#include <fstream>
14
#include <iostream>
15
#include <exception>
16
#include <sstream>
17
#include <regex>
18
#include "tyrant.h"
19
#include "tyrant_optimize.h"
20
#include "sim.h"
21
#include "read.h"
22

23
using namespace std;
24
namespace bdata = boost::unit_test::data;
25
typedef std::tuple<FinalResults<long double>, std::string, double, std::string> Result; // score, output, time, result_deck
26
int iter = 1000;
27
unsigned seed = 0;
28
// limit for float diffing
29
// disable
30
double eps = 1.;
31
// enable
32
// double eps = 0.0000001;
33

34
// pipe output: https://stackoverflow.com/questions/5405016/can-i-check-my-programs-output-with-boost-test
35
struct ios_redirect
36
{
37
    ios_redirect(std::streambuf *new_buffer, std::ostream &ios)
168 ✔
38
        : old(ios.rdbuf(new_buffer)), iios(ios)
168 ✔
39
    {
40
    }
41

42
    ~ios_redirect()
168 ✔
43
    {
44
        iios.rdbuf(old);
84 ✔
45
    }
46

47
private:
48
    std::streambuf *old;
49
    std::ostream &iios;
50
};
51

52
struct TestInfo
77 ✔
53
{
54
    std::string your_deck, enemy_deck, bge;
55
};
56
std::ostream &operator<<(std::ostream &os, const TestInfo &ti)
61 ✔
57
{
58
    return os << "Your Deck: " << ti.your_deck << "; Enemy Deck: " << ti.enemy_deck << "; BGE: " << ti.bge;
61 ✔
59
}
60

61
inline Result run_sim(int argc, const char **argv, bool pipe_output = true)
84 ✔
62
{
63
    init();
84 ✔
64
    Result res;
84 ✔
65
    std::string rdeck = "";
84 ✔
66
    FinalResults<long double> fr;
84 ✔
67
    //
68

69
    auto start_time = std::chrono::system_clock::now();
84 ✔
70
    // pipe output
71
    std::stringstream output;
84 ✔
72
    std::stringstream eoutput;
84 ✔
73
    {
84 ✔
74
        ios_redirect guard2(eoutput.rdbuf(), std::cerr); // block warnings
84 ✔
75
        if (pipe_output)
84 ✔
76
        {
77
            ios_redirect guard1(output.rdbuf(), std::cout);
84 ✔
78

79
            //////////////////////
80
            // only single thread for string stream build
81
            //////////////////////
82
            const char **param = new const char *[argc + 2];
84 ✔
83
            for (int i = 0; i < argc; i++)
991 ✔
84
                param[i] = const_cast<char *>(argv[i]);
907 ✔
85
            param[argc] = const_cast<char *>("-t");
84 ✔
86
            param[argc + 1] = const_cast<char *>("1");
84 ✔
87
            auto rett = run(argc + 2, param);
84 ✔
88
            delete[] param;
84 ✔
89
            fr = rett.second;
84 ✔
90
            // result to string
91
            auto drc = rett;
84 ✔
92
            std::stringstream oss;
84 ✔
93
            if (drc.first->commander)
84 ✔
94
                oss << drc.first->commander->m_name << ", ";
84 ✔
95
            if (drc.first->alpha_dominion)
84 ✔
96
                oss << drc.first->alpha_dominion->m_name << ", ";
71 ✔
97
            print_cards_inline(drc.first->cards, oss, drc.first);
84 ✔
98
            rdeck = oss.str();
84 ✔
99
        }
84 ✔
100
        else
101
        {
102
            // no guard here
103
            //////////////////////
104
            // only single thread, else crashes
105
            //////////////////////
106
            const char **param = new const char *[argc + 2];
×
107
            for (int i = 0; i < argc; i++)
×
108
                param[i] = const_cast<char *>(argv[i]);
×
109
            param[argc] = const_cast<char *>("-t");
×
110
            param[argc + 1] = const_cast<char *>("1");
×
111
            auto rett = run(argc + 2, param);
×
112
            delete[] param;
×
113
            fr = rett.second;
×
114
            // result to string
115
            auto drc = rett;
×
116
            std::stringstream oss;
×
117
            if (drc.first->commander)
×
118
                oss << drc.first->commander->m_name << ", ";
×
119
            if (drc.first->alpha_dominion)
×
120
                oss << drc.first->alpha_dominion->m_name << ", ";
×
121
            print_cards_inline(drc.first->cards, oss, drc.first);
×
122
            rdeck = oss.str();
×
123
        }
×
124
    }
×
125

126
    auto end_time = std::chrono::system_clock::now();
84 ✔
127
    std::chrono::duration<double> delta_t = (end_time - start_time);
84 ✔
128
    res = std::make_tuple(fr, "\n" + debug_str + output.str(), delta_t.count(), rdeck);
252 ✔
129
    return res;
168 ✔
130
}
84 ✔
131

132
inline void check_win(Result result)
63 ✔
133
{
134
    BOOST_CHECK_MESSAGE(
63 ✔
135
        1 - eps <= std::get<0>(result).wins &&
136
            eps >= std::get<0>(result).losses &&
137
            eps >= std::get<0>(result).draws,
138
        std::get<1>(result));
139
    // BOOST_CHECK(100==result.points);
140
}
63 ✔
141
// inline void check_win_sim(const char* your_deck, const char* enemy_deck, const char* bge="") {
142
inline void check_win_sim(TestInfo ti)
61 ✔
143
{
144
    /////////////
145
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
146
    ////////////
147
    string s = std::to_string(iter);
61 ✔
148
    char *ii = new char[s.length()+1];
61 ✔
149
    strcpy(ii, s.c_str());
61 ✔
150
    s = std::to_string(seed);
61 ✔
151
    char *iii = new char[s.length()+1];
61 ✔
152
    strcpy(iii, s.c_str());
61 ✔
153
    const char *argv[] = {"tuo", ti.your_deck.c_str(), ti.enemy_deck.c_str(), "-e", ti.bge.c_str(), "sim", ii, "seed", iii, "prefix", "tests/sim/"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
61 ✔
154
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
155
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
61 ✔
156
    delete[] ii;
61 ✔
157
    delete[] iii;
61 ✔
158
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
159
    check_win(result);
122 ✔
160
}
61 ✔
161
inline double time_db_sim(std::string gnt1, std::string gnt2)
1 ✔
162
{
163
    /////////////
164
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
165
    ////////////
166
    string s = std::to_string(iter);
1 ✔
167
    char *ii = new char[s.length()+1];
1 ✔
168
    strcpy(ii, s.c_str());
1 ✔
169
    s = std::to_string(seed);
1 ✔
170
    char *iii = new char[s.length()+1];
1 ✔
171
    strcpy(iii, s.c_str());
1 ✔
172
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/db/", "db", "no-db-load"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
1 ✔
173
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
174
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
1 ✔
175
    delete[] ii;
1 ✔
176
    delete[] iii;
1 ✔
177
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
178
    // check_win(result);
179
    return std::get<2>(result);
1 ✔
180
}
1 ✔
181
inline double time_db(std::string gnt1, std::string gnt2)
1 ✔
182
{
183
    /////////////
184
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
185
    ////////////
186
    string s = std::to_string(iter);
1 ✔
187
    char *ii = new char[s.length()+1];
1 ✔
188
    strcpy(ii, s.c_str());
1 ✔
189
    s = std::to_string(seed);
1 ✔
190
    char *iii = new char[s.length()+1];
1 ✔
191
    strcpy(iii, s.c_str());
1 ✔
192
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/db/", "db"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
1 ✔
193
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
194
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
1 ✔
195
    delete[] ii;
1 ✔
196
    delete[] iii;
1 ✔
197
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
198
    // check_win(result);
199
    return std::get<2>(result);
1 ✔
200
}
1 ✔
201
inline double time_ml_sim(std::string gnt1, std::string gnt2)
1 ✔
202
{
203
    /////////////
204
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
205
    ////////////
206
    string s = std::to_string(iter);
1 ✔
207
    char *ii = new char[s.length()+1];
1 ✔
208
    strcpy(ii, s.c_str());
1 ✔
209
    s = std::to_string(seed);
1 ✔
210
    char *iii = new char[s.length()+1];
1 ✔
211
    strcpy(iii, s.c_str());
1 ✔
212
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/ml/", "no-db-load"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
1 ✔
213
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
214
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
1 ✔
215
    delete[] ii;
1 ✔
216
    delete[] iii;
1 ✔
217
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
218
    // check_win(result);
219
    return std::get<2>(result);
1 ✔
220
}
1 ✔
221
inline double time_ml(std::string gnt1, std::string gnt2)
1 ✔
222
{
223
    /////////////
224
    // Max. Iter == 100, else check_win fails with integer vs double equal in check_win
225
    ////////////
226
    string s = std::to_string(iter);
1 ✔
227
    char *ii = new char[s.length()+1];
1 ✔
228
    strcpy(ii, s.c_str());
1 ✔
229
    s = std::to_string(seed);
1 ✔
230
    char *iii = new char[s.length()+1];
1 ✔
231
    strcpy(iii, s.c_str());
1 ✔
232
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/ml/", "no-db", "ml"}; // much output on error?! // better 100 iterations for test, 10 for checking errors
1 ✔
233
    // const char* argv[] = {"tuo",ti.your_deck.c_str(),ti.enemy_deck.c_str(),"-e",ti.bge.c_str(),"sim", ii,"seed", iii}; //much output on error?! // better 100 iterations for test, 10 for checking errors
234
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv));
1 ✔
235
    delete[] ii;
1 ✔
236
    delete[] iii;
1 ✔
237
    // result.second += "\nTest: " + ti.your_deck + "; " + ti.enemy_deck + "; " + ti.bge;
238
    // check_win(result);
239
    return std::get<2>(result);
1 ✔
240
}
1 ✔
241

242
inline bool try_get_skipped_simulations(std::string const& output, unsigned long& skipped_simulations)
2 ✔
243
{
244
    std::smatch matches;
2 ✔
245
    if (std::regex_search(output, matches, std::regex("Evaluated [0-9]+ decks \\([0-9]+ \\+ ([0-9]+) simulations\\)\\.")))
4 ✔
246
    {
247
        skipped_simulations = std::stoul(matches[1].str());
6 ✔
248
        return true;
2 ✔
249
    }
250
    return false;
251
}
2 ✔
252

253
inline void genetic(std::string gnt1, std::string gnt2)
254
{
255
    string s = std::to_string(iter);
256
    char *ii = new char[s.length()+1];
257
    strcpy(ii, s.c_str());
258
    const char *argv[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "brawl", "genetic", ii};
259
    Result result(run_sim(sizeof(argv) / sizeof(*argv), argv, false));
260
    std::ofstream mf;
261
    mf.open("out.csv", std::ios_base::app);
262
    mf << gnt1 << ";" << gnt2 << ";" << std::get<0>(result).points << ";" << std::get<2>(result) << std::endl;
263
    mf.close();
264
}
265

266
inline void check_algo(std::string gnt1, std::string gnt2, std::string algo)
3 ✔
267
{
268
    string s = std::to_string(iter);
3 ✔
269
    char *ii = new char[s.length()+1];
3 ✔
270
    strcpy(ii, s.c_str());
3 ✔
271
    s = std::to_string(seed);
3 ✔
272
    char *iii = new char[s.length()+1];
3 ✔
273
    strcpy(iii, s.c_str());
3 ✔
274
    const char *argv1[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
3 ✔
275
    Result result_sim(run_sim(sizeof(argv1) / sizeof(*argv1), argv1));
3 ✔
276
    // Do the algo
277
    const char *argv2[] = {"tuo", gnt1.c_str(), gnt2.c_str(), algo.c_str(), ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
3 ✔
278
    Result result(run_sim(sizeof(argv2) / sizeof(*argv2), argv2));
3 ✔
279
    // Rerun sim with optimized deck to check if algo produced wrong sim result
280
    const char *argv3[] = {"tuo", std::get<3>(result).c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
3 ✔
281
    Result result_opt(run_sim(sizeof(argv3) / sizeof(*argv3), argv3));
3 ✔
282
    delete[] ii;
3 ✔
283
    delete[] iii;
3 ✔
284
    BOOST_CHECK_MESSAGE(std::get<0>(result_sim).wins <= std::get<0>(result_opt).wins,
18 ✔
285
                        std::get<1>(result_sim) + "\n" + std::get<1>(result_opt) + "\nWrongly from " + algo + ": " +
286
                            std::to_string(std::get<0>(result_sim).wins) + ">" + std::to_string(std::get<0>(result_opt).wins));
287
}
9 ✔
288
inline void check_anneal(std::string gnt1, std::string gnt2)
1 ✔
289
{
290
    std::string algo = "anneal";
1 ✔
291
    double anneal_temp = 100;
1 ✔
292
    double anneal_temp_down = 0.01;
1 ✔
293
    string s = std::to_string(iter);
1 ✔
294
    char *ii = new char[s.length()+1];
1 ✔
295
    strcpy(ii, s.c_str());
1 ✔
296
    s = std::to_string(seed);
1 ✔
297
    char *iii = new char[s.length()+1];
1 ✔
298
    strcpy(iii, s.c_str());
1 ✔
299
    s = std::to_string(anneal_temp);
1 ✔
300
    char *iv = new char[s.length()+1];
1 ✔
301
    strcpy(iv, s.c_str());
1 ✔
302
    s = std::to_string(anneal_temp_down);
1 ✔
303
    char *v = new char[s.length()+1];
1 ✔
304
    strcpy(v, s.c_str());
1 ✔
305
    const char *argv1[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1 ✔
306
    Result result_sim(run_sim(sizeof(argv1) / sizeof(*argv1), argv1));
1 ✔
307
    const char *argv2[] = {"tuo", gnt1.c_str(), gnt2.c_str(), algo.c_str(), ii, iv, v, "seed", iii, "prefix", "tests/algo/", "no-db"};
1 ✔
308
    Result result(run_sim(sizeof(argv2) / sizeof(*argv2), argv2));
1 ✔
309
    // Rerun sim with optimized deck to check if algo produced wrong sim result
310
    const char *argv3[] = {"tuo", std::get<3>(result).c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1 ✔
311
    Result result_opt(run_sim(sizeof(argv3) / sizeof(*argv3), argv3));
1 ✔
312
    delete[] ii;
1 ✔
313
    delete[] iii;
1 ✔
314
    delete[] iv;
1 ✔
315
    delete[] v;
1 ✔
316
    BOOST_CHECK_MESSAGE(std::get<0>(result_sim).wins <= std::get<0>(result_opt).wins,
6 ✔
317
                        std::get<1>(result_sim) + "\n" + std::get<1>(result_opt) + "\nWrongly from " + algo + ": " +
318
                            std::to_string(std::get<0>(result_sim).wins) + ">" + std::to_string(std::get<0>(result_opt).wins));
319
}
3 ✔
320
inline void check_climbex(std::string gnt1, std::string gnt2)
1 ✔
321
{
322
    std::string algo = "climbex";
1 ✔
323
    int init = 10;
1 ✔
324
    string s = std::to_string(iter);
1 ✔
325
    char *ii = new char[s.length()+1];
1 ✔
326
    strcpy(ii, s.c_str());
1 ✔
327
    s = std::to_string(seed);
1 ✔
328
    char *iii = new char[s.length()+1];
1 ✔
329
    strcpy(iii, s.c_str());
1 ✔
330
    s = std::to_string(init);
1 ✔
331
    char *iv = new char[s.length()+1];
1 ✔
332
    strcpy(iv, s.c_str());
1 ✔
333
    const char *argv1[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1 ✔
334
    Result result_sim(run_sim(sizeof(argv1) / sizeof(*argv1), argv1));
1 ✔
335
    const char *argv2[] = {"tuo", gnt1.c_str(), gnt2.c_str(), algo.c_str(), iv, ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1 ✔
336
    Result result(run_sim(sizeof(argv2) / sizeof(*argv2), argv2));
1 ✔
337
    // Rerun sim with optimized deck to check if algo produced wrong sim result
338
    const char *argv3[] = {"tuo", std::get<3>(result).c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "prefix", "tests/algo/", "no-db"};
1 ✔
339
    Result result_opt(run_sim(sizeof(argv3) / sizeof(*argv3), argv3));
1 ✔
340
    delete[] ii;
1 ✔
341
    delete[] iii;
1 ✔
342
    delete[] iv;
1 ✔
343
    BOOST_CHECK_MESSAGE(std::get<0>(result_sim).wins <= std::get<0>(result_opt).wins,
6 ✔
344
                        std::get<1>(result_sim) + "\n" + std::get<1>(result_opt) + "\nWrongly from " + algo + ": " +
345
                            std::to_string(std::get<0>(result_sim).wins) + ">" + std::to_string(std::get<0>(result_opt).wins));
346
}
3 ✔
347

348
inline void check_climb_forts(std::string gnt1, std::string gnt2, std::string yf, std::string ef)
349
{
350
    std::string algo = "climb_forts";
351
    int init = 10;
352
    string s = std::to_string(iter);
353
    char *ii = new char[s.length()+1];
354
    strcpy(ii, s.c_str());
355
    s = std::to_string(seed);
356
    char *iii = new char[s.length()+1];
357
    strcpy(iii, s.c_str());
358
    s = std::to_string(init);
359
    char *iv = new char[s.length()+1];
360
    strcpy(iv, s.c_str());
361
    const char *argv1[] = {"tuo", gnt1.c_str(), gnt2.c_str(), "sim", ii, "seed", iii, "yf", yf.c_str(), "yfpool", "2", "ef", ef.c_str(), "efpool", "2", "prefix", "tests/algo/", "no-db"};
362
    Result result_sim(run_sim(sizeof(argv1) / sizeof(*argv1), argv1));
363
    const char *argv2[] = {"tuo", gnt1.c_str(), gnt2.c_str(), algo.c_str(), iv, ii, "seed", iii, "yf", yf.c_str(), "yfpool", "2", "ef", ef.c_str(), "efpool", "2", "prefix", "tests/algo/", "no-db"};
364
    Result result_opt(run_sim(sizeof(argv2) / sizeof(*argv2), argv2));
365
    // Rerun sim with optimized deck to check if algo produced wrong sim result
366
    // const char* argv3[] = {"tuo",gnt1.c_str(),gnt2.c_str(),"sim",ii, "seed", iii,  "yf",std::get<3>(result).c_str(), "yfpool","2", "ef", ef.c_str(), "efpool", "2","prefix" , "tests/algo/", "no-db"};
367
    // Result result_opt(run_sim(sizeof(argv3)/sizeof(*argv3),argv3));
368
    delete[] ii;
369
    delete[] iii;
370
    delete[] iv;
371
    BOOST_CHECK_MESSAGE(std::get<0>(result_sim).wins <= std::get<0>(result_opt).wins,
372
                        std::get<1>(result_sim) + "\n" + std::get<1>(result_opt) + "\nWrongly from " + algo + ": " +
373
                            std::to_string(std::get<0>(result_sim).wins) + ">" + std::to_string(std::get<0>(result_opt).wins));
374
}
375

376
std::vector<TestInfo> read_test_file(const std::string filename)
5 ✔
377
{
378
    std::vector<TestInfo> ret;
5 ✔
379
    std::ifstream test_file(filename);
5 ✔
380
    if (test_file.good())
5 ✔
381
    {
382
        try
383
        {
384
            while (test_file && !test_file.eof())
82 ✔
385
            {
386
                TestInfo ti;
77 ✔
387
                std::string line, yd, ed, bg;
77 ✔
388
                std::getline(test_file, line);
77 ✔
389
                if (is_line_empty_or_commented(line))
77 ✔
390
                {
391
                    continue;
16 ✔
392
                }
393
                std::istringstream iss(line);
61 ✔
394
                std::getline(iss, ti.your_deck, ';');
61 ✔
395
                std::getline(iss, ti.enemy_deck, ';');
61 ✔
396
                std::getline(iss, ti.bge, ';');
61 ✔
397
                ret.push_back(ti);
61 ✔
398
            }
77 ✔
399
        }
400
        catch (std::exception &e)
×
401
        {
402
        }
×
403
    }
404
    return ret;
5 ✔
405
}
5 ✔
406

407
BOOST_AUTO_TEST_SUITE(test)
408
BOOST_AUTO_TEST_CASE(test_init)
7 ✔
409
{
410
    init();
1 ✔
411

412
    seed = std::chrono::system_clock::now().time_since_epoch().count() * 2654435761;
1 ✔
413
    if (boost::unit_test::framework::master_test_suite().argc >= 2)
1 ✔
414
    {
415
        iter = atoi(boost::unit_test::framework::master_test_suite().argv[1]);
×
416
    }
417
    if (boost::unit_test::framework::master_test_suite().argc >= 3)
1 ✔
418
    {
419
        seed = atoi(boost::unit_test::framework::master_test_suite().argv[2]);
×
420
    }
421
    //BOOST_TEST_MESSAGE("ITER: " << iter);
422
    BOOST_TEST_MESSAGE("SEED: " << seed);
2 ✔
423
    BOOST_CHECK(1 == 1); //..
1 ✔
424
}
1 ✔
425

426
BOOST_AUTO_TEST_SUITE(test_algo)
427
BOOST_AUTO_TEST_CASE(test_algo_init)
6 ✔
428
{
429
    iter = 1000;
1 ✔
430
}
×
431
BOOST_AUTO_TEST_SUITE(test_algo_climb)
432
BOOST_AUTO_TEST_CASE(test_algo_climb)
7 ✔
433
{
434
    check_algo("Mission#134", "Mission#135", "climb");
2 ✔
435
}
1 ✔
436
BOOST_AUTO_TEST_SUITE_END()
437

438
BOOST_AUTO_TEST_SUITE(test_algo_anneal)
439
BOOST_AUTO_TEST_CASE(test_algo_anneal)
7 ✔
440
{
441
    check_anneal("Mission#134", "Mission#135");
2 ✔
442
}
1 ✔
443
BOOST_AUTO_TEST_SUITE_END()
444

445
BOOST_AUTO_TEST_SUITE(test_algo_climbex)
446
BOOST_AUTO_TEST_CASE(test_algo_climbex)
7 ✔
447
{
448
    check_climbex("Mission#134", "Mission#135");
2 ✔
449
}
1 ✔
450
BOOST_AUTO_TEST_SUITE_END()
451

452
BOOST_AUTO_TEST_SUITE(test_algo_genetic)
453
BOOST_AUTO_TEST_CASE(test_algo_genetic)
7 ✔
454
{
455
    check_algo("Mission#134", "Mission#135", "genetic");
2 ✔
456
}
1 ✔
457
BOOST_AUTO_TEST_SUITE_END()
458

459
BOOST_AUTO_TEST_SUITE(test_algo_beam)
460
BOOST_AUTO_TEST_CASE(test_algo_beam)
7 ✔
461
{
462
    check_algo("Mission#134", "Mission#135", "beam");
2 ✔
463
}
1 ✔
464
BOOST_AUTO_TEST_SUITE_END()
465

466
// TODO Fix this test
467
// BOOST_AUTO_TEST_SUITE(test_algo_climb_forts)
468
// BOOST_AUTO_TEST_CASE(test_algo_climb_forts)
469
//{
470
//        check_climb_forts("Mission#135","Mission#135","LC#2, TC#2, IB#2, DF#2","LC#2, TC#2, IB#2, DF#2");
471
//}
472
// BOOST_AUTO_TEST_SUITE_END()
473

474
BOOST_AUTO_TEST_SUITE_END()
475

476
BOOST_AUTO_TEST_SUITE(test_sim)
477
BOOST_AUTO_TEST_CASE(test_sim_init)
6 ✔
478
{
479
    iter = 100;
1 ✔
480
    debug_print++;
1 ✔
481
    debug_cached++;
1 ✔
482
    debug_line = true;
1 ✔
483
}
×
484
/////////////////////////////////////
485
// Test Cases !should! be very close fights for maximum sensitivity of errors
486
/////////////////////////////////////
487
BOOST_AUTO_TEST_SUITE(test_single_units)
488
BOOST_DATA_TEST_CASE(test_single_units, bdata::make(read_test_file("tests/test_sinlge_units.csv")), ti)
42 ✔
489
{
490
    check_win_sim(ti);
6 ✔
491
}
6 ✔
492
BOOST_AUTO_TEST_SUITE_END()
493

494
BOOST_AUTO_TEST_SUITE(test_multi_units)
495
BOOST_DATA_TEST_CASE(test_multi_units, bdata::make(read_test_file("tests/test_multi_units.csv")), ti)
91 ✔
496
{
497
    check_win_sim(ti);
13 ✔
498
}
13 ✔
499
BOOST_AUTO_TEST_SUITE_END()
500

501
BOOST_AUTO_TEST_SUITE(test_bges)
502
BOOST_DATA_TEST_CASE(test_bges, bdata::make(read_test_file("tests/test_bges.csv")), ti)
28 ✔
503
{
504
    check_win_sim(ti);
4 ✔
505
}
4 ✔
506
BOOST_AUTO_TEST_SUITE_END()
507

508
BOOST_AUTO_TEST_SUITE(test_whole_decks)
509
BOOST_DATA_TEST_CASE(test_whole_decks, bdata::make(read_test_file("tests/test_whole_decks.csv")), ti)
7 ✔
510
{
511
    check_win_sim(ti);
1 ✔
512
}
1 ✔
513
BOOST_AUTO_TEST_SUITE_END()
514

515
BOOST_AUTO_TEST_SUITE(test_crashes)
516
BOOST_DATA_TEST_CASE(test_crashes, bdata::make(read_test_file("tests/test_crash.csv")), ti)
259 ✔
517
{
518
    eps = 1.; // only check for crashes now
37 ✔
519
    check_win_sim(ti);
37 ✔
520
}
37 ✔
521
BOOST_AUTO_TEST_SUITE_END()
522
BOOST_AUTO_TEST_SUITE_END()
523

524
BOOST_AUTO_TEST_SUITE(test_db)
525
BOOST_AUTO_TEST_CASE(test_db_init)
6 ✔
526
{
527
    iter = 100000;
1 ✔
528
    debug_print = 0;
1 ✔
529
    debug_cached = 0;
1 ✔
530
    debug_line = false;
1 ✔
531
}
×
532
BOOST_AUTO_TEST_SUITE(test_db_scaling)
533
BOOST_AUTO_TEST_CASE(test_db_scaling)
7 ✔
534
{
535
    BOOST_TEST_MESSAGE("DB time improvement test");
2 ✔
536
    auto t1 = time_db_sim("Sir Alaric the Swift-1, Broodmother's Nexus-1, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6, ", "Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6,");
1 ✔
537
    auto t2 =     time_db("Sir Alaric the Swift-1, Broodmother's Nexus-1, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6, ", "Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6,");
1 ✔
538
    BOOST_CHECK_MESSAGE(t1 > t2, "DB time improvement failed: " + std::to_string(t1) + " > " + std::to_string(t2));
3 ✔
539
}
1 ✔
540
BOOST_AUTO_TEST_SUITE_END()
541

542
BOOST_AUTO_TEST_SUITE(test_db_skipped_counter)
543
BOOST_AUTO_TEST_CASE(test_db_skipped_counter_on_hit)
7 ✔
544
{
545
    iter = 1;
1 ✔
546
    const char *warmup_argv[] = {"tuo", "Mission#134", "Mission#135", "beam", "1", "seed", "1", "prefix", "tests/db/", "db", "no-db-load"};
1 ✔
547
    Result warmup(run_sim(sizeof(warmup_argv) / sizeof(*warmup_argv), warmup_argv));
1 ✔
548
    unsigned long warmup_skipped{0};
1 ✔
549
    BOOST_REQUIRE_MESSAGE(try_get_skipped_simulations(std::get<1>(warmup), warmup_skipped), "Failed to parse skipped simulations from warmup output");
1 ✔
550

551
    const char *cached_argv[] = {"tuo", "Mission#134", "Mission#135", "beam", "1", "seed", "1", "prefix", "tests/db/", "db"};
1 ✔
552
    Result cached(run_sim(sizeof(cached_argv) / sizeof(*cached_argv), cached_argv));
1 ✔
553
    unsigned long cached_skipped{0};
1 ✔
554
    BOOST_REQUIRE_MESSAGE(try_get_skipped_simulations(std::get<1>(cached), cached_skipped), "Failed to parse skipped simulations from cached output");
1 ✔
555
    BOOST_CHECK_MESSAGE(cached_skipped > 0, "Expected skipped simulations to include DB-hit results, got " + std::to_string(cached_skipped) + ". Warmup skipped: " + std::to_string(warmup_skipped));
3 ✔
556
}
2 ✔
557
BOOST_AUTO_TEST_SUITE_END()
558
BOOST_AUTO_TEST_SUITE_END()
559

560
BOOST_AUTO_TEST_SUITE(test_ml)
561
BOOST_AUTO_TEST_CASE(test_ml_init)
6 ✔
562
{
563
    iter = 100000;
1 ✔
564
    debug_print = 0;
1 ✔
565
    debug_cached = 0;
1 ✔
566
    debug_line = false;
1 ✔
UNCOV
567
}
×
568
BOOST_AUTO_TEST_SUITE(test_ml_scaling)
569
BOOST_AUTO_TEST_CASE(test_ml_scaling)
7 ✔
570
{
571
    auto t1 = time_ml_sim("Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6, ", "Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6,");
1 ✔
572
    auto t2 = time_ml("Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6, ", "Sir Alaric the Swift-1, Broodmother's Nexus-6, Mystic Gatekeeper-6, Ruthless Pursuer-6, Maculakornos-6, Primal Yeren-6, Megalift Foundry-6, Kinaxa Soulspark-6, Mangler of Existence-6, Mangler of Existence-6, Eranore's Obstructor-6, Eranore's Obstructor-6,");
1 ✔
573
    BOOST_CHECK_MESSAGE(t1 > t2, "ML time improvement failed: " + std::to_string(t1) + " > " + std::to_string(t2));
3 ✔
574
}
1 ✔
575
BOOST_AUTO_TEST_SUITE_END()
576
BOOST_AUTO_TEST_SUITE_END()
577

578
// Define raw C-style arrays
579
static const char* test_case_1[] = {
580
    "tuo", "Bug86", "Bug86", "sim", "100", "seed", "100", "prefix", "tests/sim/",
581
    "update-reduce-delay-summoned-by-tower", nullptr
582
};
583

584
static const char* test_case_2[] = {
585
    "tuo", "Bug86", "Bug86", "sim", "100", "seed", "100", "prefix", "tests/sim/",
586
    "no-update-reduce-delay-summoned-by-tower", nullptr
587
};
588

589
static const std::array<const char**, 2> argv_dataset = {
590
    test_case_1,
591
    test_case_2
592
};
593
BOOST_AUTO_TEST_SUITE(test_fixes)
594
BOOST_AUTO_TEST_CASE(test_fixes_init)
6 ✔
595
{
596
    iter = 10000;
1 ✔
597
    debug_print = 0;
1 ✔
598
    debug_cached = 0;
1 ✔
599
    debug_line = false;
1 ✔
600
    eps = 1.; // only check for crashes now
1 ✔
UNCOV
601
}
×
602
BOOST_AUTO_TEST_SUITE(test_fixes_run)
603
BOOST_DATA_TEST_CASE(test_fixes_run, bdata::make(test::argv_dataset),argv)
14 ✔
604
{
605
    // Convert vector to argv-style array
606
    int argc = 0;
2 ✔
607
    while (argv[argc] != nullptr) ++argc;
22 ✔
608
    check_win(run_sim(argc, argv));
2 ✔
609
    //check_win(run_sim(sizeof(argv) / sizeof(*argv), argv));
610
}
2 ✔
611
BOOST_AUTO_TEST_SUITE_END()
612
BOOST_AUTO_TEST_SUITE_END()
613

614
BOOST_AUTO_TEST_SUITE_END()
615
#endif
616
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc