/* clang-format off */
#include "testlib.h"
#include "gen_lib.h"
#include "limits.h"
/* clang-format on */

using namespace std;

struct Test {
    int n, m;
    string path;
    vector<string> a;

    void match_random_empty_cells(int cnt) {
        vector<pair<int, int>> cells;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (a[i][j] == '.') {
                    cells.emplace_back(i, j);
                }
            }
        }
        for (auto i : random::distinctIntegers(0, (int)cells.size(), cnt, rnd)) {
            auto [x, y] = cells[i];
            a[x][y] = '#';
        }
    }

    void fill_up() {
        vector<int> ord;
        for (int i = 0; i < (int)path.size(); i++) {
            if (path[i] == 'D' || path[i] == 'U') {
                ord.push_back(i);
            }
        }
        if (ord.empty()) {
            return;
        }

        int pos = random::choice(ord, rnd);
        string to_add;
        char prev = path[pos];
        while ((int)(path.size() + to_add.size()) < 2 * n * m) {
            prev ^= 'D' ^ 'U';
            to_add.push_back(prev);
        }

        path = path.substr(0, pos + 1) + to_add + path.substr(pos + 1);
    }

    void print() {
        println(n, m);
        println(path);
        for (auto s : a) {
            println(s);
        }
    }
};

ArgumentParser parser;
Test t;
Limits limits;

namespace grid_generators {
    void random_grid() {
        t.match_random_empty_cells(parser.getInt("occ"));
    }

    void parity_grid() {
        for (int i = 0; i < t.n; i++) {
            for (int j = 0; j < t.m; j++) {
                if (j % 2 == 0 || (i + j / 2) % 2 == 0) {
                    continue;
                }
                t.a[i][j] = '#';
            }
        }
        t.match_random_empty_cells(parser.getInt("extra"));
    }

    void excluded() {
        for (int i = 0; i < t.n; i++) {
            fill(t.a[i].begin(), t.a[i].end(), '#');
        }

        int to_exclude = parser.getInt("exclude");
        for (auto i : random::distinctIntegers(0, t.n * t.m, to_exclude, rnd)) {
            int x = i / t.m;
            int y = i % t.m;

            t.a[x][y] = '.';
            for (auto c : t.path) {
                if (c == 'R') {
                    y++;
                } else {
                    x += (c == 'D' ? 1 : -1);
                }
                if (x < 0 || x >= t.n || y >= t.m) {
                    break;
                }
                t.a[x][y] = '.';
            }
        }
    }
} // namespace grid_generators

namespace path_generators {
    void append_vertical_part(int &x, int min_x, int max_x, int next_x) {
        if (random::random(0, 2, rnd)) {
            t.path += string(x - min_x, 'U');
            t.path += string(max_x - min_x, 'D');
            t.path += string(max_x - next_x, 'U');
        } else {
            t.path += string(max_x - x, 'D');
            t.path += string(max_x - min_x, 'U');
            t.path += string(next_x - min_x, 'D');
        }
        x = next_x;
    }

    void stupid_random() {
        int len = parser.getInt("len");
        for (int i = 0; i < len; i++) {
            t.path.push_back(random::choice(vector{'D', 'U', 'R'}, rnd));
        }
    }

    void random_path() {
        int right = parser.getInt("right");
        int offset = parser.getInt("offset");

        do {
            t.path.clear();

            int x = offset;
            for (int i = 0; i <= right; i++) {
                if (i > 0) {
                    t.path.push_back('R');
                }
                int min_x = random::random(0, x + 1, rnd);
                int max_x = random::random(x, 2 * offset + 1, rnd);
                int next_x = random::random(min_x, max_x + 1, rnd);
                append_vertical_part(x, min_x, max_x, next_x);
            }
        } while (t.path.empty());
    }

    void parity_path() {
        int len = parser.getInt("len");
        int maxshift = parser.getInt("maxshift");
        int x = maxshift;
        for (int i = 0; i < len; i++) {
            if (i > 0) {
                t.path.push_back('R');
            }
            if (i % 2 == 1) {
                continue;
            }
            while (true) {
                int min_x = random::random(0, x + 1, rnd);
                int max_x = random::random(x, 2 * maxshift + 1, rnd);
                int next_x = random::random(min_x, max_x + 1, rnd);
                if ((next_x - maxshift - i / 2) % 2) {
                    continue;
                }
                append_vertical_part(x, min_x, max_x, next_x);
                break;
            }
        }
    }

    void max_length() {
        int right = parser.getInt("right");
        int down = parser.getInt("down");
        for (int i = 0; i < right; i++) {
            if (i > 0) {
                t.path.push_back('R');
            }
            t.path += string(down, 'D');
            t.path += string(down, 'U');
        }
    }

    void only_right() {
        t.path = string(parser.getInt("len"), 'R');
    }

    void only_up() {
        t.path = string(parser.getInt("len"), 'U');
    }

    void right_or_down() {
        int right = parser.getInt("right");
        int down = parser.getInt("down");
        t.path = string(right + down, 'R');
        for (auto i : random::distinctIntegers(0, right + down, down, rnd)) {
            t.path[i] = 'D';
        }
    }

    void up_or_down() {
        int len = parser.getInt("len");
        int x = random::random(0, len + 1, rnd);
        append_vertical_part(x, 0, len, random::random(0, len + 1, rnd));

        int final_length = parser.getInt("flen", -1);
        if (final_length == -1) {
            return;
        }
        while ((int)t.path.size() < final_length) {
            if (x == 0) {
                x++;
                t.path.push_back('D');
            } else if (x == len) {
                x--;
                t.path.push_back('U');
            } else if (random::random(0, 2, rnd)) {
                x++;
                t.path.push_back('D');
            } else {
                x--;
                t.path.push_back('U');
            }
        }
    }
} // namespace path_generators

int main(int argc, char *argv[]) {
    registerGen(argc, argv, 1);
    parser = ArgumentParser(argc, argv);
    limits = LIMITS[parser.getInt("group")];

    t.n = parser.getInt("n", limits.max_n);
    t.m = parser.getInt("m", limits.max_m);
    t.a = vector<string>(t.n, string(t.m, '.'));

    const auto pmode = parser.getString("pmode");
    if (pmode == "stupid_random") {
        path_generators::stupid_random();
    } else if (pmode == "random") {
        path_generators::random_path();
    } else if (pmode == "parity") {
        path_generators::parity_path();
    } else if (pmode == "max_length") {
        path_generators::max_length();
    } else if (pmode == "only_right") {
        path_generators::only_right();
    } else if (pmode == "up_or_down") {
        path_generators::up_or_down();
    } else if (pmode == "only_up") {
        path_generators::only_up();
    } else if (pmode == "right_or_down") {
        path_generators::right_or_down();
    } else {
        global::logAndThrowException("invalid pmode: " + pmode);
    }

    const auto gmode = parser.getString("gmode");
    if (gmode == "random") {
        grid_generators::random_grid();
    } else if (gmode == "parity") {
        grid_generators::parity_grid();
    } else if (gmode == "excluded") {
        grid_generators::excluded();
    } else {
        global::logAndThrowException("invalid gmode: " + gmode);
    }

    if (!parser.hasFlag("ignore") && limits.allow_up && limits.allow_down) {
        t.fill_up();
    }

    t.print();
}
