gepardo's blog

By gepardo, history, 9 months ago, In English,

Hello, Codeforces!

If you tried to prepare some competitive programming problems, you might parse parameters like this:

#include "testlib.h"
#include <cstdlib>

using namespace std;

int main(int argc, char **argv) {
  registerGen(argc, argv, 1);
  int n = atoi(argv[1]);
  int m = atoi(argv[2]);
  int k = atoi(argv[3]);
  ...

Of course, such way has many disadvantages:

  • You need to pass the exact amount of parameters, you cannot define default values for them.
  • If you have many parameters, it's easy to forget the order.
  • If you pass too few of the them, it will be undefined behavior.

So I developed a library called ParmPars to pass parameters to generators in a more convenient way. You can find it on GitHub. I hope it will help you to generate tests better.

Using ParmPars, you could rewrite the code above in the following way:

#include "testlib.h"
#include "parmpars.hpp"

using namespace std;

int main(int argc, char **argv) {
  initGenerator(argc, argv, 1);
  DECLARE(int, n);
  DECLARE(int, m);
  DECLARE(int, k);
  ...

In ParmPars, all the parameters are named, so to run the generator you can write something like

gen n=1 m=2 k=3

Let's write a simple generator for A+B problem using ParmPars: initGenerator is a function that initializes both Testlib ad ParmPars. DECLARE macros are used to declare a variable and init it from the parameters.

Of course, default parameters can be used:

#include "testlib.h"
#include "parmpars.hpp"

using namespace std;

int main(int argc, char **argv) {
  initGenerator(argc, argv, 1);
  DECLARE_D(int, n, 1);
  DECLARE_D(int, m, 2);
  DECLARE_D(int, k, 3);
  ...

Now if you run gen without parameters, it will assume n=1, m=2 and k=3.

Using ParmPars in Polygon

Just upload it to Files > Resource Files.

More powerful example: generator ranges

Let's write a simple generator for A+B problem using ParmPars:

#include "testlib.h"
#include "parmpars.hpp"

using namespace std;

int main(int argc, char **argv) {
  initGenerator(argc, argv, 1);
  DECLARE_GEN(GenRange<int>, a);
  DECLARE_GEN(GenRange<int>, b);
  cout << a << " " << b << endl;
  return 0;
}

Now we want to generate a test with two random numbers from 1 to 1000. Then, we can just use gen a=[1,1000] b=[1,1000]. It works, because DECLARE_GEN first reads [1,1000], and then converts it to int by calling rnd.next(1, 1000). You can also append the generator seed as a last parameter: gen a=[1,1000] b=[1,1000] randomseed.

More examples

You can find more examples in the project's README.

Questions

You can report the issues, ask questions about ParmPars and suggest enhancements in the comments. Obviously, you can also use GitHub's issue and pull request functionality.

 
 
 
 
  • Vote: I like it
  • +102
  • Vote: I do not like it