Problem: cf1201_e2
Difficulty: hard
Categories: graph, game, greedy
Time limit: 3000 ms, memory limit: 256 MB

This is an interactive problem.

Alice and Bob are playing a game on the chessboard of size $n \times m$ where $n$ and $m$ are even. The rows are numbered from $1$ to $n$ and the columns are numbered from $1$ to $m$. There are two knights on the chessboard. A white one initially is on the position $(x_1, y_1)$, while the black one is on the position $(x_2, y_2)$. Alice will choose one of the knights to play with, and Bob will use the other one.

The Alice and Bob will play in turns and whoever controls the white knight starts the game. During a turn, the player must move their knight adhering the chess rules. That is, if the knight is currently on the position $(x, y)$, it can be moved to any of those positions (as long as they are inside the chessboard):

 $(x+1, y+2)$, $(x+1, y-2)$, $(x-1, y+2)$, $(x-1, y-2)$,

$(x+2, y+1)$, $(x+2, y-1)$, $(x-2, y+1)$, $(x-2, y-1)$.

We all know that knights are strongest in the middle of the board. Both knight have a single position they want to reach:

* the owner of the white knight wins if it captures the black knight or if the white knight is at $(n/2, m/2)$ and this position is not under attack of the black knight at this moment;
* The owner of the black knight wins if it captures the white knight or if the black knight is at $(n/2+1, m/2)$ and this position is not under attack of the white knight at this moment.

Formally, the player who captures the other knight wins. The player who is at its target square ($(n/2, m/2)$ for white, $(n/2+1, m/2)$ for black) and this position is not under opponent's attack, also wins.

A position is under attack of a knight if it can move into this position. Capturing a knight means that a player moves their knight to the cell where the opponent's knight is.

If Alice made $350$ moves and nobody won, the game is a draw.

Alice is unsure in her chess skills, so she asks you for a help. Choose a knight and win the game for her. It can be shown, that Alice always has a winning strategy.

Interaction

The interaction starts with two integers $n$ and $m$ ($6 \le n,m \le 1000$, $n$ and $m$ are even) — the dimensions of the chessboard.

The second line contains four integers $x_1, y_1, x_2, y_2$ ($1 \le x_1, x_2 \le n$, $1 \le y_1, y_2 \le m$) — the positions of the white and the black knight. It is guaranteed that the two knights have different starting positions. It is also guaranteed that none of the knights are in their own target square in the beginning of the game (however, they can be on the opponent's target position).

Your program should reply with either "WHITE" or "BLACK", depending on the knight you want to play with. In case you select the white knight, you start the game.

During every your turn, you need to print two integers: $x$ and $y$, the position to move the knight. If you won the game by this turn, you must terminate your program immediately.

After every turn of the opponent, you will receive two integers: $x$ and $y$, the position where Bob moved his knight.

If your last move was illegal or you lost the game after jury's turn, or you made $350$ moves, and haven't won, you will receive "-1 -1". In such cases, you should terminate your program and then you will get a Wrong Answer verdict.

After printing anything, do not forget to output the end of line and flush the output. Otherwise, you might get Idleness limit exceeded. To do this, use:

* fflush(stdout) or cout.flush() in C++;
* System.out.flush() in Java;
* flush(output) in Pascal;
* stdout.flush() in Python;
* see documentation for other languages.

Jury's program is adaptive: the moves of jury may depend on the moves made by your program.

Examples

Input

```
8 8
2 3 1 8
```

Output

```
WHITE
4 4
```

Input

```
6 6
4 4 2 2
6 3
```

Output

```
BLACK
4 3
```

Note

In the first example, the white knight can reach it's target square in one move.

In the second example black knight wins, no matter what white knight moves.

Non-adaptive interactor (C++):















#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;


static int contestant_moves = 0;
static const int MOVE_LIMIT = 350;

struct Point {
    int x, y;
    bool operator==(const Point& other) const {
        return x == other.x && y == other.y;
    }
    bool operator!=(const Point& other) const {
        return !(*this == other);
    }
};

int n, m;
Point white_start, black_start;
Point white_target, black_target;


vector<vector<int>> dist_white_target;
vector<vector<int>> dist_black_target;

int dx[] = {-2, -2, -1, -1, 1, 1, 2, 2};
int dy[] = {-1, 1, -2, 2, -2, 2, -1, 1};

bool in_bounds(int r, int c) {
    return r >= 1 && r <= n && c >= 1 && c <= m;
}


vector<vector<int>> bfs(Point start) {
    vector<vector<int>> d(n + 1, vector<int>(m + 1, -1));
    queue<Point> q;
    d[start.x][start.y] = 0;
    q.push(start);
    while (!q.empty()) {
        Point u = q.front();
        q.pop();
        for (int i = 0; i < 8; i++) {
            int nx = u.x + dx[i];
            int ny = u.y + dy[i];
            if (in_bounds(nx, ny) && d[nx][ny] == -1) {
                d[nx][ny] = d[u.x][u.y] + 1;
                q.push({nx, ny});
            }
        }
    }
    return d;
}

void log_metrics() {
    try {
        tout << "queries=" << contestant_moves << endl;
        tout << "query_limit=" << MOVE_LIMIT << endl;
    } catch (...) {}
}

void finish(TResult verdict, string msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}


bool is_attacked(Point p, Point attacker_pos) {
    for (int i = 0; i < 8; i++) {
        if (p.x == attacker_pos.x + dx[i] && p.y == attacker_pos.y + dy[i]) return true;
    }
    return false;
}


Point get_jury_move(Point my_pos, Point opp_pos, bool i_am_white, 
                    const vector<vector<int>>& my_target_dist, 
                    const vector<vector<int>>& opp_target_dist, 
                    Point my_target, Point opp_target) {
    
    vector<Point> candidates;
    for (int i = 0; i < 8; i++) {
        int nx = my_pos.x + dx[i];
        int ny = my_pos.y + dy[i];
        if (in_bounds(nx, ny)) candidates.push_back({nx, ny});
    }
    
    
    for (const auto& mv : candidates) {
        if (mv == opp_pos) return mv; 
        if (mv == my_target && !is_attacked(mv, opp_pos)) return mv; 
    }
    
    
    vector<Point> safe_moves;
    for (const auto& mv : candidates) {
        if (!is_attacked(mv, opp_pos)) safe_moves.push_back(mv);
    }
    
    const vector<Point>& search_space = (safe_moves.empty() ? candidates : safe_moves);
    
    
    int my_d = my_target_dist[my_pos.x][my_pos.y];
    int opp_d = opp_target_dist[opp_pos.x][opp_pos.y];
    
    bool race_mode = false;
    if (i_am_white) {
        if (my_d <= opp_d) race_mode = true;
    } else {
        if (my_d < opp_d) race_mode = true;
    }
    
    Point best_move = search_space[0];
    long long best_score = 1e18;
    
    for (const auto& mv : search_space) {
        long long score;
        if (race_mode) score = my_target_dist[mv.x][mv.y];
        else score = opp_target_dist[mv.x][mv.y]; 
        
        if (score < best_score) {
            best_score = score;
            best_move = mv;
        } else if (score == best_score) {
            
            if (mv.x < best_move.x || (mv.x == best_move.x && mv.y < best_move.y)) {
                best_move = mv;
            }
        }
    }
    
    return best_move;
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);
    
    
    n = inf.readInt();
    m = inf.readInt();
    white_start.x = inf.readInt();
    white_start.y = inf.readInt();
    black_start.x = inf.readInt();
    black_start.y = inf.readInt();
    
    white_target = {n / 2, m / 2};
    black_target = {n / 2 + 1, m / 2};
    
    
    dist_white_target = bfs(white_target);
    dist_black_target = bfs(black_target);
    
    
    cout << n << " " << m << endl;
    cout << white_start.x << " " << white_start.y << " " << black_start.x << " " << black_start.y << endl;
    
    
    string color_token;
    if (!(cin >> color_token)) finish(_pe, "No color token");
    
    string color_upper = "";
    for(char c : color_token) color_upper += toupper(c);
    
    bool contestant_white = (color_upper == "WHITE");
    if (!contestant_white && color_upper != "BLACK") finish(_pe, "Invalid color: " + color_token);
    
    Point my_pos = (contestant_white ? black_start : white_start);
    Point contest_pos = (contestant_white ? white_start : black_start);
    Point my_target = (contestant_white ? black_target : white_target);
    Point contest_target = (contestant_white ? white_target : black_target);
    
    const vector<vector<int>>& my_bfs = (contestant_white ? dist_black_target : dist_white_target);
    const vector<vector<int>>& contest_bfs = (contestant_white ? dist_white_target : dist_black_target);
    
    bool my_turn = !contestant_white; 
    
    while (true) {
        
        
        
        if (contest_pos == contest_target && !is_attacked(contest_pos, my_pos)) {
            finish(_ok, "Contestant reached target safe");
        }
        if (my_pos == my_target && !is_attacked(my_pos, contest_pos)) {
            cout << "-1 -1" << endl;
            finish(_wa, "Jury reached target safe");
        }
        
        if (my_turn) {
            Point move = get_jury_move(my_pos, contest_pos, !contestant_white, my_bfs, contest_bfs, my_target, contest_target);
            
            
            if (move == contest_pos) {
                cout << "-1 -1" << endl;
                finish(_wa, "Jury captured contestant");
            }
            if (move == my_target && !is_attacked(move, contest_pos)) {
                cout << "-1 -1" << endl;
                finish(_wa, "Jury reached target safe");
            }
            
            
            cout << move.x << " " << move.y << endl;
            my_pos = move;
            my_turn = false;
        } else {
            string token;
            if (!(cin >> token)) finish(_pe, "Unexpected end of stream");
            
            
            if (token == "!") finish(_pe, "Unexpected '!' token");
            if (token == "?") {
                if (!(cin >> token)) finish(_pe, "Broken query");
            }
            
            int cx, cy;
            try { cx = stoi(token); } catch(...) { finish(_pe, "Token not number: " + token); }
            if (!(cin >> cy)) finish(_pe, "Missing y");
            
            if (!in_bounds(cx, cy)) {
                cout << "-1 -1" << endl;
                finish(_wa, "Move out of bounds");
            }
            
            bool valid = false;
            for(int i=0; i<8; i++) {
                if(contest_pos.x + dx[i] == cx && contest_pos.y + dy[i] == cy) { valid = true; break; }
            }
            if (!valid) {
                cout << "-1 -1" << endl;
                finish(_wa, "Invalid knight move");
            }
            
            contest_pos = {cx, cy};
            contestant_moves++;
            log_metrics(); 
            
            if (contest_pos == my_pos) finish(_ok, "Contestant captured jury");
            
            if (contestant_moves > MOVE_LIMIT) {
                cout << "-1 -1" << endl;
                finish(_wa, "Move limit exceeded");
            }
            
            my_turn = true;
        }
    }
}


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

using namespace std;


int queries = 0;
const int query_limit = 350;


int N, M;
int TW_x, TW_y; 
int TB_x, TB_y; 


vector<vector<int>> dist_TW; 
vector<vector<int>> dist_TB; 


const int dx[] = {1, 1, -1, -1, 2, 2, -2, -2};
const int dy[] = {2, -2, 2, -2, 1, -1, 1, -1};


void log_metrics() {
    tout << "queries=" << queries << endl;
    tout << "query_limit=" << query_limit << endl;
}


void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}


void on_exit() {
    log_metrics();
}


bool valid(int x, int y) {
    return x >= 1 && x <= N && y >= 1 && y <= M;
}


bool attacks(int ax, int ay, int tx, int ty) {
    for (int i = 0; i < 8; i++) {
        if (ax + dx[i] == tx && ay + dy[i] == ty) return true;
    }
    return false;
}


vector<vector<int>> bfs(int tx, int ty) {
    vector<vector<int>> d(N + 1, vector<int>(M + 1, -1));
    queue<pair<int, int>> q;
    
    if (valid(tx, ty)) {
        d[tx][ty] = 0;
        q.push({tx, ty});
    }
    
    while (!q.empty()) {
        auto [cx, cy] = q.front();
        q.pop();
        
        for (int i = 0; i < 8; i++) {
            int nx = cx + dx[i];
            int ny = cy + dy[i];
            if (valid(nx, ny) && d[nx][ny] == -1) {
                d[nx][ny] = d[cx][cy] + 1;
                q.push({nx, ny});
            }
        }
    }
    return d;
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(on_exit);
    
    
    N = inf.readInt();
    M = inf.readInt();
    int x1 = inf.readInt();
    int y1 = inf.readInt();
    int x2 = inf.readInt();
    int y2 = inf.readInt();
    
    TW_x = N / 2;
    TW_y = M / 2;
    TB_x = N / 2 + 1;
    TB_y = M / 2;
    
    
    cout << N << " " << M << endl;
    cout << x1 << " " << y1 << " " << x2 << " " << y2 << endl;
    
    
    log_metrics();

    
    dist_TW = bfs(TW_x, TW_y);
    dist_TB = bfs(TB_x, TB_y);
    
    
    string s = ouf.readToken();
    bool user_is_white = (s == "WHITE");
    
    int wx = x1, wy = y1;
    int bx = x2, by = y2;
    
    int turn = 0; 
    int user_moves_count = 0;
    
    while (true) {
        bool is_user_turn = (user_is_white ? (turn == 0) : (turn == 1));
        
        if (is_user_turn) {
            
            if (user_moves_count >= 350) {
                cout << "-1 -1" << endl;
                finish(_wa, "Limit of 350 moves exceeded");
            }
            
            
            int ux = ouf.readInt();
            int uy = ouf.readInt();
            user_moves_count++;
            queries = user_moves_count; 
            log_metrics(); 
            
            
            if (ux == -1 && uy == -1) {
                finish(_wa, "User output -1 -1 (resigned)");
            }
            
            int my_x = (turn == 0) ? wx : bx;
            int my_y = (turn == 0) ? wy : by;
            
            
            if (!valid(ux, uy)) {
                cout << "-1 -1" << endl;
                finish(_wa, "Move out of bounds");
            }
            if (!attacks(my_x, my_y, ux, uy)) {
                cout << "-1 -1" << endl;
                finish(_wa, "Invalid knight move");
            }
            
            
            if (turn == 0) { wx = ux; wy = uy; }
            else { bx = ux; by = uy; }
            
            
            int op_x = (turn == 0) ? bx : wx;
            int op_y = (turn == 0) ? by : wy;
            int my_tx = (turn == 0) ? TW_x : TB_x;
            int my_ty = (turn == 0) ? TW_y : TB_y;
            
            
            if (wx == bx && wy == by) finish(_ok, "User captured opponent");
            
            
            if ((turn == 0 ? wx : bx) == my_tx && (turn == 0 ? wy : by) == my_ty) {
                
                if (!attacks(op_x, op_y, (turn == 0 ? wx : bx), (turn == 0 ? wy : by))) {
                    finish(_ok, "User reached target safely");
                }
            }
            
        } else {
            
            int my_x = (turn == 0) ? wx : bx;
            int my_y = (turn == 0) ? wy : by;
            int op_x = (turn == 0) ? bx : wx;
            int op_y = (turn == 0) ? by : wy;
            
            int my_tx = (turn == 0) ? TW_x : TB_x;
            int my_ty = (turn == 0) ? TW_y : TB_y;
            
            const auto& my_d = (turn == 0) ? dist_TW : dist_TB;
            const auto& op_d = (turn == 0) ? dist_TB : dist_TW;
            
            
            vector<pair<int, int>> moves;
            for (int i = 0; i < 8; i++) {
                int nx = my_x + dx[i];
                int ny = my_y + dy[i];
                if (valid(nx, ny)) moves.push_back({nx, ny});
            }
            
            
            
            
            
            pair<int, int> best_move = {-1, -1};
            
            
            for (auto p : moves) {
                
                if (p.first == op_x && p.second == op_y) {
                    best_move = p;
                    break;
                }
                
                if (p.first == my_tx && p.second == my_ty) {
                    if (!attacks(op_x, op_y, p.first, p.second)) {
                        best_move = p;
                        break;
                    }
                }
            }
            
            if (best_move.first == -1) {
                
                vector<pair<int, int>> safe_moves;
                for (auto p : moves) {
                    
                    if (!attacks(op_x, op_y, p.first, p.second)) {
                        safe_moves.push_back(p);
                    }
                }
                
                
                vector<pair<int, int>>& candidates = safe_moves.empty() ? moves : safe_moves;
                
                
                int d_me = my_d[my_x][my_y];
                int d_opp = op_d[op_x][op_y];
                
                
                
                
                bool race = (turn == 0) ? (d_me <= d_opp) : (d_me < d_opp);
                
                best_move = candidates[0];
                tuple<int, int, int> best_score = {1e9, 1e9, 1e9};
                
                for (auto p : candidates) {
                    int v1 = my_d[p.first][p.second]; 
                    int v2 = op_d[p.first][p.second]; 
                    
                    tuple<int, int, int> score;
                    if (race) {
                        
                        score = {v1, v2, 0};
                    } else {
                        
                        score = {v2, v1, 0};
                    }
                    
                    if (score < best_score) {
                        best_score = score;
                        best_move = p;
                    }
                }
            }
            
            
            cout << best_move.first << " " << best_move.second << endl;
            
            
            if (turn == 0) { wx = best_move.first; wy = best_move.second; }
            else { bx = best_move.first; by = best_move.second; }
            
            
            if (wx == bx && wy == by) {
                cout << "-1 -1" << endl;
                finish(_wa, "Interactor captured user");
            }
            if ((turn == 0 ? wx : bx) == my_tx && (turn == 0 ? wy : by) == my_ty) {
                int op_nx = (turn == 0) ? bx : wx;
                int op_ny = (turn == 0) ? by : wy;
                if (!attacks(op_nx, op_ny, best_move.first, best_move.second)) {
                    cout << "-1 -1" << endl;
                    finish(_wa, "Interactor reached target safe");
                }
            }
        }
        
        turn = 1 - turn;
    }
    
    return 0;
}


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

using namespace std;

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);

    
    
    
    
    string mode = opt<string>("mode", "non");

    
    int seed = atoi(argv[1]);

    int n, m;
    int x1, y1, x2, y2;

    
    if (seed == 1) {
        
        n = 6; m = 6;
        x1 = 1; y1 = 1;
        x2 = 1; y2 = 2;
    } else if (seed == 2) {
        
        n = 6; m = 6;
        x1 = 1; y1 = 1;
        x2 = 6; y2 = 6;
    } else if (seed == 3) {
        
        
        n = 1000; m = 1000;
        x1 = 498; y1 = 500;
        x2 = 503; y2 = 500;
    } else if (seed == 4) {
        
        n = 1000; m = 1000;
        x1 = 1; y1 = 1;
        x2 = 1000; y2 = 1000;
    } else {
        
        
        if (rnd.next(2) == 0) {
            n = rnd.next(6, 1000);
            m = rnd.next(6, 1000);
        } else {
            n = rnd.next(950, 1000);
            m = rnd.next(950, 1000);
        }

        
        if (n % 2 != 0) n--;
        if (m % 2 != 0) m--;
        if (n < 6) n = 6;
        if (m < 6) m = 6;

        int tx_w = n / 2;
        int ty_w = m / 2;
        int tx_b = n / 2 + 1;
        int ty_b = m / 2;

        
        while (true) {
            x1 = rnd.next(1, n);
            y1 = rnd.next(1, m);
            x2 = rnd.next(1, n);
            y2 = rnd.next(1, m);

            
            if (x1 == x2 && y1 == y2) continue;
            
            
            if (x1 == tx_w && y1 == ty_w) continue;
            if (x2 == tx_b && y2 == ty_b) continue;

            break;
        }
    }

    
    
    int tx_w = n / 2;
    int ty_w = m / 2;
    int tx_b = n / 2 + 1;
    int ty_b = m / 2;

    if (x1 == tx_w && y1 == ty_w) x1 = (x1 > 1 ? x1 - 1 : x1 + 1);
    if (x2 == tx_b && y2 == ty_b) x2 = (x2 > 1 ? x2 - 1 : x2 + 1);
    if (x1 == x2 && y1 == y2) {
        
        y2 = (y2 % m) + 1;
    }
    
    if (x2 == tx_b && y2 == ty_b) x2 = (x2 > 1 ? x2 - 1 : x2 + 1);

    
    
    
    println(n, m);
    println(x1, y1, x2, y2);

    return 0;
}