Problem: icpc2025_asia_seoul_regional_a
Difficulty: hard
Categories: graph, data structures
Time limit: 3000 ms, memory limit: 256 MB

Dabi, the galaxy-famous adventurer, has entered a long-forgotten underground city said to hide an ancient treasure. Within its pitch-black tunnels, she must find a key and reach the treasure chest before the city collapses.

The entire city can be represented as an $h \times w$ grid $( 3 \leq h , w \leq 1 6 )$ ). Each cell of this grid is one of the following types:

⚫ Empty cell, which is a traversable passage.   
⚫ Wall cell, which is a solid block that cannot be entered. Teleport cell, which is an ancient device that instantly connects two distant places.

The following facts are known about this underground city:

⚫ Every cell on the grid’s boundary (i.e., topmost/bottommost row, or leftmost/rightmost column) is a wall. All wall cells are connected through four directions: north (up), south (down), east (right), and west (left)—that is, they form a single 4-directional connected component. All empty cells are connected, forming a single 4-directional connected component surrounded by walls. For every teleport cell, all eight neighboring cells are empty cells.   
$\bullet$ Every teleport cell belongs to exactly one teleport pair. If Dabi steps into a teleport cell from any direction, she is immediately transported to its paired cell and then moves one additional step in the same direction she entered the teleport cell. This process never triggers another teleportation. Each teleport pair is labeled with one of the uppercase letters A, B, C, D, E, and F. Therefore, there are at most $6 \times 2 = 1 2$ teleport cells in total. There is exactly one key and one treasure chest, each placed on distinct empty cells, but neither is at Dabi’s initial position.

![](images/0871d9bb5916e1201c3a6c8a57c6f3138768bb57e20ec737ea6bb8317cc4d6a6.jpg)  
Figure 1. An example configuration of the underground city $h = 7$ ; $w = 9$ ) with two teleport pairs A and B.

Dabi can perform the following two actions:

Move to one of the four adjacent cells that is not a wall. Teleportation and the subsequent extra step are considered part of ‘entering a teleport cell’ and do not count as separate actions. Pick up the key if she is on the cell with the key.

Dabi always stands on an empty cell before and after each action.

Figure 1 illustrates an example of the underground city where $h = 7$ and $w = 9$ . Teleport pair A connects the two cells marked with the letter A, and teleport pair B connects the two cells marked with the letter B. Note that Figure 1 corresponds to the city described in the attached sample.in file.

As shown in Figure 2, the teleportation process works as follows. In Figure 2(a), Dabi is standing on the cell immediately east of teleport A. When she moves west, she steps into the teleport cell marked A, is instantly transported to its paired cell, and then moves one additional step to the west, resulting in the configuration shown in Figure 2(b).

![](images/2de463e26eafb241c11f429842597fe1a6b9c89eaa9c0b7199d256620911e8fc.jpg)  
Figure 2. Illustration of the teleportation process. (a) Dabi stands on the cell immediately east of teleport A. (b) After moving west, she steps into teleport cell A, is transported to its paired cell, and then moves one additional step to the west.

When Dabi picks up the key, the city begins to collapse. From that moment, she must reach the treasure cell in the minimum possible number of actions. Any longer route causes the attempt to fail.

Dabi carries a reliable compass and can always tell north, south, east, and west. By feeling the walls around her, she can sense for each of the four directions whether the adjacent cell is a wall or not. However, she does not initially know her coordinates or the overall layout of the city. At any moment, she can also sense whether her current cell contains the key or the treasure. She may stand on the key cell without immediately picking it up.

Your task is to guide Dabi through the city to obtain the key and then reach the treasure chest, obeying all movement rules. Write a program to accomplish this by interacting with the interactor through a sequence of commands.

# Interaction

This is an interactive problem. Your submitted program will interact with an interactor inside the grading server, which reads input from and writes output to your program. Your program must control Dabi by printing commands and reading the interactor’s replies. After every line of output, you must immediately flush the output.

# Initial Input

At the beginning of the interaction, the interactor provides information about Dabi’s current cell. The information is given as a single line containing six characters without spaces:

Each of the six characters is either $\bullet _ { 0 } ,$ or ‘1’. For the first four characters, $\cdot _ { 1 } ,$ means that the adjacent cell in that direction is a wall, and $\bullet _ { 0 } ,$ means that the adjacent cell in that direction is not a wall. The order of directions is north, south, east, and west. The fifth character is $\cdot _ { 1 } ,$ if the key is present on Dabi’s current cell and has not yet been picked up; otherwise, it is $\bullet _ { 0 } ,$ .   
$\bullet$ The sixth character is $\bullet _ { 1 } ,$ if the treasure chest is on Dabi’s current cell; otherwise, it is $\bullet _ { 0 } ,$ .   
$\bullet$ Since the key and the treasure chest are on different cells, the fifth and sixth characters are never both $\bullet _ { 1 } ,$ .

For example, $^ { \bullet \bullet } \mathrm { 1 0 0 0 1 0 ^ { \bullet } }$ means that there is a wall to the north, the other three directions are open, the unpicked key is on the current cell, and there is no treasure.

# Commands

Your program may repeatedly output exactly one of the following commands until the interactor outputs “correct” or terminates the interaction.

1. “N”, “S”, “E”, or “W”

$\bullet$ Move one step in the chosen direction—“N” (north), “S” (south), “E” (east), or “W” (west). The target cell must not be a wall. If it is a teleport cell, Dabi will be teleported according to the rules described above. Attempting to move into a wall causes the interactor to output “wrong”. 2. “K” Pick up the key on the current cell. After this action, the treasure chest opens, and from that moment Dabi must reach the treasure cell in the minimum possible number of actions. If there is no unpicked key on the current cell, the interactor outputs “wrong”.

Each command must be printed on its own line and immediately flushed. The total number of commands issued must not exceed 230,611.

# Interactor Responses

After each action, the interactor responds as follows:

. The interactor outputs “correct” if Dabi has already picked up the key and has just reached the treasure cell using the minimum possible number of actions. The interactor immediately terminates the interaction if any rule is violated—for example, a malformed command, an invalid move, attempting to pick up a nonexistent or already collected key, exceeding 230,611 actions in total, or reaching the treasure through a route that does not use the minimum possible number of actions after the key has been collected.   
. Otherwise, the interactor outputs a six-character string describing Dabi’s new current cell, in the same format as the initial input.

Receiving “correct” means that your program has successfully completed the mission and should terminate gracefully. Do not forget to flush the output after printing each command.

The city layout is fixed throughout the interaction; the interactor is not adaptive.

The time and memory used by the interactor are also included in the calculation of your program’s execution time and memory usage. You can assume that the maximum time used by the interactor is 1 second and the maximum amount of memory is 64 MiB.

The following shows a sample interaction when the city layout and Dabi’s initial position are the same as in Figure 1.

# Read (Interactor’s Response)

# Sample Interaction 1

<table><tr><td rowspan=1 colspan=2>101000</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>W</td></tr><tr><td rowspan=1 colspan=2>000000</td><td rowspan=1 colspan=1></td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>W</td></tr><tr><td rowspan=1 colspan=2>000000</td><td rowspan=1 colspan=1></td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>S</td></tr><tr><td rowspan=1 colspan=2>010000</td><td rowspan=1 colspan=1></td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>W</td></tr><tr><td rowspan=1 colspan=2>010110</td><td rowspan=1 colspan=1></td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>K</td></tr><tr><td rowspan=1 colspan=2>010100</td><td rowspan=1 colspan=1></td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>N</td></tr><tr><td rowspan=1 colspan=2>000000</td><td rowspan=1 colspan=1></td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>W</td></tr><tr><td rowspan=1 colspan=2>010100</td><td rowspan=1 colspan=1></td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>N</td></tr><tr><td rowspan=1 colspan=2>000100</td><td rowspan=1 colspan=1></td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=2>E</td></tr><tr><td rowspan=1 colspan=2>correct</td><td rowspan=1 colspan=1></td></tr></table>

To flush, you need to do the following right after writing a command and a newline:

fflush(stdout) in C;   
std::cout << std::flush in $\mathrm { C } { + } { + }$ ;   
System.out.flush() in Java or Kotlin;   
sys.stdout.flush() in Python.

A testing tool is provided to help you develop your solution, so it is not mandatory to use it. If you want to use it, you can download the attachment testing_tool.py from the DOMjudge Problemset page. You can run the testing tool to see how your program interacts for a specific city layout. This testing tool can be used regardless of the language of your program as follows. The same explanation is also included in the comments of testing_tool.py.

Usage: python3 testing_tool.py -f <inputfile> <program>

Use the -f parameter to specify the input file, e.g. input.in.

Format of the input file: The first line contains two integers $h$ and $w$ . The next $h$ lines each contain a string of length ??, describing the map of the city. Each character represents a cell type as follows:

‘#’: A wall cell.   
‘.’: An empty cell.   
‘k’: The empty cell containing the key.   
‘t’: The empty cell containing the treasure chest.   
‘v’: The empty cell where Dabi initially stands.   
‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’: Teleport cells, where each letter represents one teleport pair.

Example: The city shown in Figure 1 is represented as follows.

<table><tr><td>79</td><td></td></tr><tr><td>#########</td><td></td></tr><tr><td>###...###</td><td></td></tr><tr><td>#...A.v##</td><td></td></tr><tr><td>#.B.....#</td><td></td></tr><tr><td>#...A.Bt#</td><td></td></tr><tr><td>##k.....#</td><td></td></tr><tr><td>#########</td><td></td></tr></table>

The tool is provided as-is, and you should feel free to make whatever alterations or augmentations you like to it. Note that it is not guaranteed that a program that passes the testing tool will be accepted. For example, the testing tool does not verify whether Dabi reaches the treasure chest using the minimum possible number of actions after picking up the key; instead, it only reports how many actions were taken.

If you have a $\mathrm { C } { + } { + }$ solution stored in a file called “sol.cpp”, you must first compile using $^ { 6 6 } \mathrm { { g } + + }$ sol.cpp -o sol” and then invoke the testing tool with:

If you have a Python solution that you would run using “pypy3 solution.py”, you can invoke the testing tool with:

python3 testing_tool.py -f input.in pypy3 solution.py

If you have a Java solution that you would run using “java MyClass”, you can invoke the testing tool with:

python3 testing_tool.py -f input.in java MyClass

If you have a Kotlin solution that you would run using “kotlin SolutionKt”, you can invoke the testing tool with:

python3 testing_tool.py -f input.in kotlin SolutionKt

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;

struct Pos {
    int r = 0;
    int c = 0;
};

static int queries = 0;
static constexpr int QUERY_LIMIT = 230611;

static void log_queries() {
    tout << "queries=" << queries << '\n';
    tout << "query_limit=" << QUERY_LIMIT << '\n';
}

[[noreturn]] static void quit_with(TResult verdict, const string& msg) {
    log_queries();
    quitf(verdict, "%s", msg.c_str());
}

static bool in_bounds(int r, int c, int h, int w) {
    return 0 <= r && r < h && 0 <= c && c < w;
}

static char wall_char(const vector<string>& g, int r, int c) {
    if (!in_bounds(r, c, (int)g.size(), (int)g[0].size())) {
        return '#';
    }
    return g[r][c];
}

static string observation(
    const vector<string>& g,
    Pos p,
    Pos key_pos,
    Pos treasure_pos,
    bool key_picked
) {
    static const int DR[4] = {-1, 1, 0, 0};
    static const int DC[4] = {0, 0, 1, -1};

    string s;
    s.reserve(6);
    for (int d = 0; d < 4; d++) {
        const char ch = wall_char(g, p.r + DR[d], p.c + DC[d]);
        s.push_back(ch == '#' ? '1' : '0');
    }
    const bool key_here = (!key_picked && p.r == key_pos.r && p.c == key_pos.c);
    const bool treasure_here = (p.r == treasure_pos.r && p.c == treasure_pos.c);
    s.push_back(key_here ? '1' : '0');
    s.push_back(treasure_here ? '1' : '0');
    return s;
}

static bool is_teleport(char ch) {
    return 'A' <= ch && ch <= 'F';
}

static Pos step_once(
    const vector<string>& g,
    const unordered_map<char, array<Pos, 2>>& tele,
    Pos cur,
    int dr,
    int dc
) {
    const int h = (int)g.size();
    const int w = (int)g[0].size();

    const int nr = cur.r + dr;
    const int nc = cur.c + dc;
    if (!in_bounds(nr, nc, h, w)) {
        quit_with(_wa, "Move out of bounds");
    }
    const char to = g[nr][nc];
    if (to == '#') {
        quit_with(_wa, "Move into wall");
    }
    if (!is_teleport(to)) {
        return Pos{nr, nc};
    }

    auto it = tele.find(to);
    if (it == tele.end()) {
        quit_with(_wa, "Teleport missing pair");
    }
    const array<Pos, 2>& pair = it->second;
    const Pos a = pair[0];
    const Pos b = pair[1];

    Pos other = a;
    if (a.r == nr && a.c == nc) {
        other = b;
    } else if (b.r == nr && b.c == nc) {
        other = a;
    } else {
        quit_with(_wa, "Teleport pair mismatch");
    }

    const int fr = other.r + dr;
    const int fc = other.c + dc;
    if (!in_bounds(fr, fc, h, w)) {
        quit_with(_wa, "Teleport extra step out of bounds");
    }
    const char after = g[fr][fc];
    if (after == '#') {
        quit_with(_wa, "Teleport extra step into wall");
    }

    
    return Pos{fr, fc};
}

static int shortest_after_key(
    const vector<string>& g,
    const unordered_map<char, array<Pos, 2>>& tele,
    Pos key_pos,
    Pos treasure_pos
) {
    const int h = (int)g.size();
    const int w = (int)g[0].size();
    const int total = h * w;
    auto id = [&](Pos p) { return p.r * w + p.c; };

    vector<int> dist(total, -1);
    queue<Pos> q;
    dist[id(key_pos)] = 0;
    q.push(key_pos);

    static const int DR[4] = {-1, 1, 0, 0};
    static const int DC[4] = {0, 0, 1, -1};

    while (!q.empty()) {
        Pos cur = q.front();
        q.pop();
        const int d0 = dist[id(cur)];
        if (cur.r == treasure_pos.r && cur.c == treasure_pos.c) {
            return d0;
        }
        for (int dir = 0; dir < 4; dir++) {
            const int nr = cur.r + DR[dir];
            const int nc = cur.c + DC[dir];
            if (!in_bounds(nr, nc, h, w)) {
                continue;
            }
            if (g[nr][nc] == '#') {
                continue;
            }
            Pos nxt = step_once(g, tele, cur, DR[dir], DC[dir]);
            const int nid = id(nxt);
            if (dist[nid] != -1) {
                continue;
            }
            dist[nid] = d0 + 1;
            q.push(nxt);
        }
    }

    return -1;
}

int main(int argc, char* argv[]) {
    registerInteraction(argc, argv);
    atexit(log_queries);

    const int h = inf.readInt(3, 16, "h");
    inf.readSpace();
    const int w = inf.readInt(3, 16, "w");
    inf.readEoln();

    vector<string> g(h);
    for (int i = 0; i < h; i++) {
        
        g[i] = inf.readLine();
        if ((int)g[i].size() != w) {
            quit_with(_fail, "Bad case: row length mismatch");
        }
    }

    Pos start{-1, -1};
    Pos key_pos{-1, -1};
    Pos treasure_pos{-1, -1};
    unordered_map<char, vector<Pos>> tele_raw;
    for (int r = 0; r < h; r++) {
        for (int c = 0; c < w; c++) {
            const char ch = g[r][c];
            if (ch == 'v') {
                start = Pos{r, c};
                g[r][c] = '.';
            } else if (ch == 'k') {
                key_pos = Pos{r, c};
                g[r][c] = '.';
            } else if (ch == 't') {
                treasure_pos = Pos{r, c};
                g[r][c] = '.';
            } else if (is_teleport(ch)) {
                tele_raw[ch].push_back(Pos{r, c});
            } else if (ch == '#' || ch == '.') {
                
            } else {
                quit_with(_fail, "Bad case: unknown cell type");
            }
        }
    }

    if (start.r < 0 || key_pos.r < 0 || treasure_pos.r < 0) {
        quit_with(_fail, "Bad case: missing v/k/t");
    }

    unordered_map<char, array<Pos, 2>> tele;
    for (auto& [ch, v] : tele_raw) {
        if (v.size() != 2) {
            quit_with(_fail, "Bad case: teleport not paired");
        }
        tele[ch] = {v[0], v[1]};
    }

    Pos cur = start;
    bool key_picked = false;
    int moves_after_key = 0;
    int best_after_key = -1;

    cout << observation(g, cur, key_pos, treasure_pos, key_picked) << endl;

    while (true) {
        string cmd;
        if (!(cin >> cmd)) {
            quit_with(_pe, "Unexpected EOF");
        }

        queries++;
        if (queries > QUERY_LIMIT) {
            quit_with(_wa, "Too many commands");
        }

        if (cmd == "K") {
            if (key_picked) {
                cout << "wrong" << endl;
                quit_with(_wa, "Key already picked");
            }
            if (!(cur.r == key_pos.r && cur.c == key_pos.c)) {
                cout << "wrong" << endl;
                quit_with(_wa, "Pick key on wrong cell");
            }
            key_picked = true;
            moves_after_key = 0;
            best_after_key = shortest_after_key(g, tele, key_pos, treasure_pos);
            if (best_after_key < 0) {
                quit_with(_fail, "Bad case: treasure unreachable after key");
            }
            cout << observation(g, cur, key_pos, treasure_pos, key_picked) << endl;
            continue;
        }

        int dr = 0;
        int dc = 0;
        if (cmd == "N") {
            dr = -1;
        } else if (cmd == "S") {
            dr = 1;
        } else if (cmd == "E") {
            dc = 1;
        } else if (cmd == "W") {
            dc = -1;
        } else {
            quit_with(_pe, "Invalid command");
        }

        cur = step_once(g, tele, cur, dr, dc);
        if (key_picked) {
            moves_after_key++;
        }

        if (key_picked && cur.r == treasure_pos.r && cur.c == treasure_pos.c) {
            if (moves_after_key == best_after_key) {
                cout << "correct" << endl;
                quit_with(_ok, "Correct");
            }
            cout << "wrong" << endl;
            quit_with(_wa, "Not optimal path after key");
        }

        cout << observation(g, cur, key_pos, treasure_pos, key_picked) << endl;
    }
}


Adaptive interactor (C++):

Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;


const int MIN_SIDE = 3;
const int MAX_SIDE = 16;

struct Grid {
    int h, w;
    vector<string> grid;

    Grid(int _h, int _w) : h(_h), w(_w) {
        grid.resize(h, string(w, '#'));
    }

    bool is_valid(int r, int c) const {
        return r >= 0 && r < h && c >= 0 && c < w;
    }

    
    bool is_wall(int r, int c) const {
        if (!is_valid(r, c)) return true;
        return grid[r][c] == '#';
    }

    
    
    
    bool is_empty_type(int r, int c) const {
        if (!is_valid(r, c)) return false;
        char C = grid[r][c];
        return C == '.' || C == 'k' || C == 't' || C == 'v';
    }

    
    bool check() {
        
        for (int r = 0; r < h; r++) {
            if (grid[r][0] != '#' || grid[r][w-1] != '#') return false;
        }
        for (int c = 0; c < w; c++) {
            if (grid[0][c] != '#' || grid[h-1][c] != '#') return false;
        }

        
        
        
        map<char, int> counts;
        vector<pair<int,int>> tels;
        for(int r = 0; r < h; ++r){
            for(int c = 0; c < w; ++c){
                char C = grid[r][c];
                if(C >= 'A' && C <= 'F'){
                    tels.push_back({r,c});
                    counts[C]++;
                    
                    for(int dr = -1; dr <= 1; ++dr){
                        for(int dc = -1; dc <= 1; ++dc){
                            if(dr == 0 && dc == 0) continue;
                            if(!is_empty_type(r + dr, c + dc)) return false;
                        }
                    }
                }
            }
        }
        for(auto kv : counts) if(kv.second != 2) return false;

        
        int wall_cnt = 0;
        int wr = -1, wc = -1;
        for(int r = 0; r < h; ++r){
            for(int c = 0; c < w; ++c){
                if(grid[r][c] == '#'){
                    wall_cnt++;
                    wr = r; wc = c;
                }
            }
        }
        if(wall_cnt > 0) {
            int visited_walls = 0;
            vector<vector<bool>> vis(h, vector<bool>(w, false));
            queue<pair<int,int>> q;
            q.push({wr, wc});
            vis[wr][wc] = true;
            visited_walls++;
            int dr[] = {0,0,1,-1};
            int dc[] = {1,-1,0,0};
            while(!q.empty()){
                auto [r, c] = q.front(); q.pop();
                for(int i=0; i<4; ++i){
                    int nr = r + dr[i], nc = c + dc[i];
                    if(is_valid(nr, nc) && grid[nr][nc] == '#' && !vis[nr][nc]){
                        vis[nr][nc] = true;
                        visited_walls++;
                        q.push({nr, nc});
                    }
                }
            }
            if(visited_walls != wall_cnt) return false;
        }

        
        int empty_cnt = 0;
        int er = -1, ec = -1;
        for(int r = 0; r < h; ++r){
            for(int c = 0; c < w; ++c){
                if(is_empty_type(r, c)){
                    empty_cnt++;
                    er = r; ec = c;
                }
            }
        }
        if(empty_cnt == 0) return false;

        int visited_empty = 0;
        vector<vector<bool>> vis(h, vector<bool>(w, false));
        queue<pair<int,int>> q;
        q.push({er, ec});
        vis[er][ec] = true;
        visited_empty++;
        int dr[] = {0,0,1,-1};
        int dc[] = {1,-1,0,0};
        while(!q.empty()){
            auto [r, c] = q.front(); q.pop();
            for(int i=0; i<4; ++i){
                int nr = r + dr[i], nc = c + dc[i];
                if(is_valid(nr, nc) && is_empty_type(nr, nc) && !vis[nr][nc]){
                    vis[nr][nc] = true;
                    visited_empty++;
                    q.push({nr, nc});
                }
            }
        }
        if(visited_empty != empty_cnt) return false;

        
        bool has_k = false, has_t = false, has_v = false;
        for(int r=0; r<h; ++r) for(int c=0; c<w; ++c) {
            if(grid[r][c] == 'k') has_k = true;
            if(grid[r][c] == 't') has_t = true;
            if(grid[r][c] == 'v') has_v = true;
        }
        return has_k && has_t && has_v;
    }
};

Grid generate_random(int h, int w) {
    int max_attempts = 1000;
    for (int attempt = 0; attempt < max_attempts; ++attempt) {
        Grid g(h, w);
        
        
        
        int max_pairs = (h < 5 || w < 5) ? 0 : 6;
        int num_pairs = rnd.next(0, max_pairs);
        if (num_pairs > 0 && rnd.next(3) == 0) num_pairs = rnd.next(0, num_pairs);

        vector<pair<int,int>> tels;
        int fails = 0;
        for(int i = 0; i < num_pairs * 2; ++i) {
            int r = rnd.next(2, h - 3);
            int c = rnd.next(2, w - 3);
            
            
            bool ok = true;
            for(auto p : tels) {
                if(max(abs(p.first - r), abs(p.second - c)) < 2) {
                    ok = false; break;
                }
            }
            if(ok) tels.push_back({r, c});
            else { i--; fails++; if(fails > 100) break; }
        }
        if(tels.size() % 2 != 0) tels.pop_back();

        
        vector<vector<bool>> forced_empty(h, vector<bool>(w, false));
        for(size_t i = 0; i < tels.size(); ++i) {
            char label = 'A' + (i / 2);
            g.grid[tels[i].first][tels[i].second] = label;
            for(int dr = -1; dr <= 1; ++dr) {
                for(int dc = -1; dc <= 1; ++dc) {
                    if(dr == 0 && dc == 0) continue;
                    forced_empty[tels[i].first + dr][tels[i].second + dc] = true;
                }
            }
        }

        
        for(int r = 0; r < h; ++r) for(int c = 0; c < w; ++c) 
            if(forced_empty[r][c]) g.grid[r][c] = '.';

        
        for(int r = 1; r < h - 1; ++r) {
            for(int c = 1; c < w - 1; ++c) {
                if(g.grid[r][c] == '#') {
                    if(rnd.next(100) < 60) g.grid[r][c] = '.';
                }
            }
        }

        
        int attempts = 0;
        while(attempts++ < 5) {
            vector<pair<int,int>> empties;
            for(int r=0; r<h; ++r) for(int c=0; c<w; ++c) if(g.is_empty_type(r,c)) empties.push_back({r,c});
            
            if(empties.empty()) { g.grid[h/2][w/2] = '.'; continue; }

            
            vector<vector<int>> vis(h, vector<int>(w, 0));
            int comp = 0;
            int dr[] = {0,0,1,-1};
            int dc[] = {1,-1,0,0};
            for(auto p : empties) {
                if(!vis[p.first][p.second]) {
                    comp++;
                    queue<pair<int,int>> q;
                    q.push(p);
                    vis[p.first][p.second] = comp;
                    while(!q.empty()){
                        auto [r, c] = q.front(); q.pop();
                        for(int i=0; i<4; ++i){
                            int nr = r + dr[i], nc = c + dc[i];
                            if(g.is_valid(nr, nc) && g.is_empty_type(nr, nc) && !vis[nr][nc]){
                                vis[nr][nc] = comp;
                                q.push({nr, nc});
                            }
                        }
                    }
                }
            }

            if(comp <= 1) break;

            
            vector<vector<int>> dist(h, vector<int>(w, -1));
            vector<vector<pair<int,int>>> parent(h, vector<pair<int,int>>(w, {-1,-1}));
            queue<pair<int,int>> q;
            
            for(int r=0; r<h; ++r) for(int c=0; c<w; ++c) if(vis[r][c] == 1) {
                dist[r][c] = 0;
                q.push({r,c});
            }

            int found_r = -1, found_c = -1;
            while(!q.empty()){
                auto [r,c] = q.front(); q.pop();
                if(vis[r][c] != 0 && vis[r][c] != 1) {
                    found_r = r; found_c = c;
                    break; 
                }
                
                vector<int> dirs = {0,1,2,3};
                shuffle(dirs.begin(), dirs.end());
                for(int i : dirs){
                    int nr = r + dr[i], nc = c + dc[i];
                    if(g.is_valid(nr, nc) && nr > 0 && nr < h-1 && nc > 0 && nc < w-1) {
                        if(g.grid[nr][nc] >= 'A' && g.grid[nr][nc] <= 'F') continue;
                        if(dist[nr][nc] == -1){
                            dist[nr][nc] = dist[r][c] + 1;
                            parent[nr][nc] = {r,c};
                            q.push({nr, nc});
                        }
                    }
                }
            }

            if(found_r != -1) {
                int curr = found_r, curc = found_c;
                while(vis[curr][curc] != 1) {
                    if(g.grid[curr][curc] == '#') g.grid[curr][curc] = '.';
                    pair<int,int> p = parent[curr][curc];
                    curr = p.first; curc = p.second;
                }
            } else {
                break; 
            }
        }

        
        vector<pair<int,int>> empties;
        for(int r=0; r<h; ++r) for(int c=0; c<w; ++c) if(g.is_empty_type(r,c)) empties.push_back({r,c});
        
        if(empties.size() < 3) continue;
        shuffle(empties.begin(), empties.end());
        
        g.grid[empties[0].first][empties[0].second] = 'v';
        g.grid[empties[1].first][empties[1].second] = 'k';
        g.grid[empties[2].first][empties[2].second] = 't';

        if(g.check()) return g;
    }

    
    Grid g(h, w);
    for(int r = 1; r < h - 1; ++r)
        for(int c = 1; c < w - 1; ++c)
            g.grid[r][c] = '.';
    g.grid[1][1] = 'v';
    g.grid[1][2] = 'k';
    g.grid[1][3] = 't';
    return g;
}

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);
    
    string mode = opt<string>("mode", "non");
    int seed_val = atoi(argv[1]);

    int h, w;
    while(true) {
        if (seed_val == 1) { h = 3; w = 5; }
        else if (seed_val == 2) { h = 16; w = 16; }
        else if (seed_val == 3) { h = 5; w = 5; }
        else {
            h = rnd.next(MIN_SIDE, MAX_SIDE);
            w = rnd.next(MIN_SIDE, MAX_SIDE);
            if (rnd.next(2)) {
                h = rnd.next(10, MAX_SIDE);
                w = rnd.next(10, MAX_SIDE);
            }
        }
        
        if ((h - 2) * (w - 2) >= 3) break;
        if (seed_val <= 3) {
            
             h = 6; w = 6; break; 
        }
    }

    if (mode == "adp") {
        cout << h << " " << w << endl;
    } else {
        Grid g = generate_random(h, w);
        cout << g.h << " " << g.w << endl;
        for(const auto& row : g.grid) {
            cout << row << endl;
        }
    }

    return 0;
}