// me.cpp -- C++14
// Compile: g++ -std=c++14 me.cpp -O2 -o me.exe
#include <bits/stdc++.h>
using namespace std;
struct Pos { int r, c; };
const int MAXN = 32;
int N;
int dr[4] = {-1,1,0,0};
int dc[4] = {0,0,-1,1};
char mvChar[4] = {'U','D','L','R'};
bool inb(int r,int c){ return r>=0 && r<N && c>=0 && c<N; }
string state_key(const vector<pair<int,int>>& boxes, const Pos &player){
// boxes must be sorted externally
string s;
for(size_t i=0;i<boxes.size();++i){
s += to_string(boxes[i].first) + "," + to_string(boxes[i].second) + ";";
}
s += "|" + to_string(player.r) + "," + to_string(player.c);
return s;
}
vector<vector<int>> bfs_from_goals(const vector<string>& grid, const vector<Pos>& goals){
vector<vector<int>> dist(N, vector<int>(N, -1));
queue<Pos> q;
for(auto &g: goals){
dist[g.r][g.c] = 0;
q.push(g);
}
while(!q.empty()){
Pos u = q.front(); q.pop();
for(int d=0; d<4; ++d){
int nr = u.r + dr[d], nc = u.c + dc[d];
if(!inb(nr,nc)) continue;
if(grid[nr][nc] == '#') continue;
if(dist[nr][nc] != -1) continue;
dist[nr][nc] = dist[u.r][u.c] + 1;
q.push({nr,nc});
}
}
return dist;
}
vector<vector<int>> player_reachable(const vector<string>& grid, const vector<pair<int,int>>& boxes, const Pos &start){
vector<vector<int>> vis(N, vector<int>(N,0));
vector<vector<int>> blocked(N, vector<int>(N,0));
for(auto &b: boxes) blocked[b.first][b.second]=1;
queue<Pos> q;
if(!blocked[start.r][start.c]){
vis[start.r][start.c]=1;
q.push(start);
}
while(!q.empty()){
Pos u = q.front(); q.pop();
for(int d=0; d<4; ++d){
int nr=u.r+dr[d], nc=u.c+dc[d];
if(!inb(nr,nc)) continue;
if(vis[nr][nc]) continue;
if(grid[nr][nc]=='#') continue;
if(blocked[nr][nc]) continue;
vis[nr][nc]=1;
q.push({nr,nc});
}
}
// return visited as ints (0/1)
return vis;
}
// BFS path (no box move) to target cell; returns next step from start (dr,dc) index or -1 if unreachable
int next_step_towards(const vector<string>& grid, const vector<pair<int,int>>& boxes, const Pos &start, const Pos &target){
vector<vector<int>> blocked(N, vector<int>(N,0));
for(auto &b: boxes) blocked[b.first][b.second]=1;
vector<vector<int>> dist(N, vector<int>(N,-1));
vector<vector<pair<int,int>>> pre(N, vector<pair<int,int>>(N, {-1,-1}));
queue<Pos> q;
if(blocked[start.r][start.c]) return -1;
dist[start.r][start.c]=0;
q.push(start);
while(!q.empty()){
Pos u = q.front(); q.pop();
if(u.r==target.r && u.c==target.c) break;
for(int d=0; d<4; ++d){
int nr=u.r+dr[d], nc=u.c+dc[d];
if(!inb(nr,nc)) continue;
if(blocked[nr][nc]) continue;
if(grid[nr][nc]=='#') continue;
if(dist[nr][nc]!=-1) continue;
dist[nr][nc] = dist[u.r][u.c] + 1;
pre[nr][nc] = make_pair(u.r,u.c);
q.push({nr,nc});
}
}
if(dist[target.r][target.c]==-1) return -1;
// backtrack to find first step
int tr = target.r, tc = target.c;
while(!(pre[tr][tc].first == start.r && pre[tr][tc].second == start.c)){
auto p = pre[tr][tc];
tr = p.first; tc = p.second;
}
for(int d=0; d<4; ++d){
if(start.r + dr[d] == tr && start.c + dc[d] == tc) return d;
}
return -1;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Read input from server
if(!(cin >> N)) { cout << "S\n"; return 0; }
vector<string> grid(N);
for(int i=0;i<N;++i) cin >> grid[i];
Pos me, opp;
cin >> me.r >> me.c;
cin >> opp.r >> opp.c;
// collect boxes and goals
vector<pair<int,int>> boxes;
vector<Pos> myGoals;
for(int r=0;r<N;++r) for(int c=0;c<N;++c){
if(grid[r][c]=='X') boxes.emplace_back(r,c);
if(grid[r][c]=='A') myGoals.push_back({r,c});
}
// If already any box on goal -> do nothing
for(auto &b: boxes){
for(auto &g: myGoals) if(b.first==g.r && b.second==g.c){
cout << "S\n";
return 0;
}
}
if(myGoals.empty()){
// no goal for me -> stand
cout << "S\n";
return 0;
}
// Precompute dist-to-goal (ignoring boxes)
vector<vector<int>> distToGoal = bfs_from_goals(grid, myGoals);
// If no box can reach goal (dist INF) -> fallback BFS towards nearest box
bool anyBoxReachable=false;
for(auto &b: boxes){
if(distToGoal[b.first][b.second] != -1) { anyBoxReachable=true; break; }
}
// A* on pushes: state = (sorted boxes positions, player pos)
// heuristic: min distToGoal over boxes (admissible)
struct ANode {
vector<pair<int,int>> boxes;
Pos player;
int g;
int h;
bool operator>(ANode const& o) const { return g + h > o.g + o.h; }
};
auto heuristic = [&](const vector<pair<int,int>>& bs)->int{
int mn = INT_MAX;
for(auto &b: bs){
int d = distToGoal[b.first][b.second];
if(d==-1) continue;
mn = min(mn, d);
}
if(mn==INT_MAX) return 1000000;
return mn;
};
// Sort initial boxes for canonical state representation
sort(boxes.begin(), boxes.end());
string start_key = state_key(boxes, me);
// Priority queue
priority_queue<ANode, vector<ANode>, greater<ANode>> pq;
unordered_map<string, pair<string, string> > parent; // child_key -> (parent_key, action)
// action format: "push:idx:dir" where idx is index in boxes vector before push, dir 0..3
unordered_map<string, int> gscore;
string init_key = start_key;
int init_h = heuristic(boxes);
pq.push(ANode{boxes, me, 0, init_h});
gscore[init_key] = 0;
parent[init_key] = make_pair(string(""), string("")); // root marker
string goal_state_key = "";
bool found = false;
int expansions = 0;
const int MAX_EXPAND = 200000; // safety limit
while(!pq.empty() && expansions < MAX_EXPAND){
ANode cur = pq.top(); pq.pop();
string cur_key = state_key(cur.boxes, cur.player);
int cur_g = cur.g;
// skip stale
if(gscore.find(cur_key) != gscore.end() && cur_g != gscore[cur_key]) continue;
expansions++;
// check goal: any box on a goal cell
bool ok=false;
for(auto &b: cur.boxes){
if(distToGoal[b.first][b.second]==0){ ok=true; break; }
// more generally box directly on any myGoal
for(auto &mg: myGoals) if(b.first==mg.r && b.second==mg.c) { ok=true; break; }
if(ok) break;
}
if(ok){
goal_state_key = cur_key;
found = true;
break;
}
// compute player's reachable area without moving boxes
vector<vector<int>> reachable = player_reachable(grid, cur.boxes, cur.player);
// For each box and each direction, attempt push
for(size_t bi=0; bi<cur.boxes.size(); ++bi){
int br = cur.boxes[bi].first;
int bc = cur.boxes[bi].second;
for(int d=0; d<4; ++d){
int from_r = br - dr[d];
int from_c = bc - dc[d];
int to_r = br + dr[d];
int to_c = bc + dc[d];
if(!inb(from_r,from_c) || !inb(to_r,to_c)) continue;
// target cell for box must be free (not wall, not another box)
if(grid[to_r][to_c] == '#') continue;
bool occupied = false;
for(size_t j=0;j<cur.boxes.size();++j){
if(j==bi) continue;
if(cur.boxes[j].first==to_r && cur.boxes[j].second==to_c){ occupied=true; break; }
}
if(occupied) continue;
// player must be able to reach from_r,from_c without moving boxes
if(!reachable[from_r][from_c]) continue;
// we can push: create new boxes vector and new player pos = br,bc (where box was)
vector<pair<int,int>> new_boxes = cur.boxes;
new_boxes[bi] = make_pair(to_r,to_c);
sort(new_boxes.begin(), new_boxes.end());
Pos new_player = { br, bc };
int new_g = cur_g + 1; // cost per push = 1 (we optimize pushes)
int new_h = heuristic(new_boxes);
string new_key = state_key(new_boxes, new_player);
if(gscore.find(new_key) == gscore.end() || new_g < gscore[new_key]){
gscore[new_key] = new_g;
parent[new_key] = make_pair(cur_key, string("push:") + to_string(br) + "," + to_string(bc) + ":" + to_string(d));
pq.push(ANode{new_boxes, new_player, new_g, new_h});
}
}
}
} // end A*
// reconstruct sequence of pushes (if found)
vector<string> actions; // actions from start -> goal
vector<pair<vector<pair<int,int>>, Pos>> states_seq; // optional
if(found){
string k = goal_state_key;
while(parent[k].first != ""){
actions.push_back(parent[k].second);
k = parent[k].first;
}
reverse(actions.begin(), actions.end());
// Now we have a sequence of pushes; need to convert into atomic moves:
// For each push action "push:br,bc:d", the player must first walk from current pos to (from = br - dr[d], bc - dc[d])
// then perform push (one atomic move in direction d). We'll compute the first atomic move to output.
vector<pair<int,int>> cur_boxes = boxes;
Pos cur_player = me;
for(size_t ai=0; ai<actions.size(); ++ai){
string s = actions[ai]; // format "push:br,bc:d"
// parse
// push:br,bc:d
int p1 = s.find(":");
int p2 = s.find(":", p1+1);
string mid = s.substr(p1+1, p2 - (p1+1));
int dd = stoi(s.substr(p2+1));
int comma = mid.find(",");
int br = stoi(mid.substr(0,comma));
int bc = stoi(mid.substr(comma+1));
int from_r = br - dr[dd];
int from_c = bc - dc[dd];
// if currently adjacent and in correct position -> push now
if(cur_player.r == from_r && cur_player.c == from_c){
// push is atomic move - return push direction
cout << mvChar[dd] << "\n";
return 0;
}
// else find path step from cur_player to from_{r,c} avoiding boxes (current cur_boxes)
int step = next_step_towards(grid, cur_boxes, cur_player, {from_r, from_c});
if(step != -1){
cout << mvChar[step] << "\n";
return 0;
} else {
// unreachable to the required pushing square (shouldn't happen if A* used reachability)
// try a fallback: go towards nearest box step
break;
}
}
// If code reaches here, somehow we couldn't output a step from plan -> fallback below
}
// Fallback strategies
// 1) If A* didn't find plan or we couldn't follow plan, step towards nearest box (BFS).
// Find nearest box cell we can walk to (adjacent to box) and output one step toward it.
// Build blocked map
vector<vector<int>> blocked(N, vector<int>(N,0));
for(auto &b: boxes) blocked[b.first][b.second]=1;
// target positions are any cell adjacent to a box and walkable
vector<vector<int>> dist(N, vector<int>(N,-1));
vector<vector<pair<int,int>>> pre(N, vector<pair<int,int>>(N, {-1,-1}));
queue<Pos> q;
if(!blocked[me.r][me.c] && grid[me.r][me.c] != '#'){
dist[me.r][me.c]=0;
q.push(me);
}
Pos chosenTarget = {-1,-1};
while(!q.empty()){
Pos u = q.front(); q.pop();
// check adjacency to any box
bool adjBox = false;
for(int d=0; d<4; ++d){
int nr=u.r+dr[d], nc=u.c+dc[d];
if(!inb(nr,nc)) continue;
if(blocked[nr][nc]) { adjBox = true; break; }
}
if(adjBox){
chosenTarget = u;
break;
}
for(int d=0; d<4; ++d){
int nr=u.r+dr[d], nc=u.c+dc[d];
if(!inb(nr,nc)) continue;
if(blocked[nr][nc]) continue;
if(grid[nr][nc]=='#') continue;
if(dist[nr][nc] != -1) continue;
dist[nr][nc] = dist[u.r][u.c] + 1;
pre[nr][nc] = make_pair(u.r,u.c);
q.push({nr,nc});
}
}
if(chosenTarget.r == -1){
// cannot reach any adjacent-to-box cell: stand
cout << "S\n";
return 0;
} else {
// backtrack next step
int tr = chosenTarget.r, tc = chosenTarget.c;
while(!(pre[tr][tc].first == me.r && pre[tr][tc].second == me.c) && !(tr==me.r && tc==me.c)){
auto p = pre[tr][tc];
tr = p.first; tc = p.second;
}
if(tr==me.r && tc==me.c){
// we are already at chosenTarget, but it's adjacent to box. just stay or push if possible
// choose push if adjacent box and push destination empty
for(int d=0; d<4; ++d){
int br = me.r + dr[d], bc = me.c + dc[d];
if(!inb(br,bc)) continue;
if(!blocked[br][bc]) continue;
int trr = br + dr[d], tcc = bc + dc[d];
if(!inb(trr,tcc)) continue;
if(grid[trr][tcc]=='#') continue;
bool occ=false;
for(auto &b: boxes) if(b.first==trr && b.second==tcc) { occ=true; break; }
if(occ) continue;
// push
cout << mvChar[d] << "\n";
return 0;
}
// otherwise stand
cout << "S\n";
return 0;
} else {
// find direction from me -> (tr,tc)
for(int d=0; d<4; ++d){
if(me.r + dr[d] == tr && me.c + dc[d] == tc){
cout << mvChar[d] << "\n";
return 0;
}
}
}
}
// ultimate fallback
cout << "S\n";
return 0;
}