#include<bits/stdc++.h>
using namespace std;
#define INF 1e9 // 定义无穷大,用于初始化最短时间
const int N=2e3+10; // 定义地图的最大尺寸
// 全局变量定义
int n,m,sx,sy; // n:地图行数 m:地图列数 sx:起点x坐标 sy:起点y坐标
char g[N][N]; // 存储地图信息的二维数组
int dis1[N][N]; // 存储所有传送门能到达的点的最短距离
int dis2[N][N]; // 存储起点出发能到达的点的最短距离
vector<pair<int,int>> transdoor; // 存储所有传送门(@)的坐标
int dx[4]={1,0,-1,0}; // 上下左右四个方向的x轴偏移量
int dy[4]={0,1,0,-1}; // 上下左右四个方向的y轴偏移量
// BFS1:计算所有传送门到地图上各点的最短距离
void bfs1(){
// 初始化队列,将所有传送门的坐标加入队列(多源BFS)
queue<pair<int,int>> qpr;
for(int i=0;i<transdoor.size();i++){
qpr.push({transdoor[i].first,transdoor[i].second});
dis1[transdoor[i].first][transdoor[i].second]=0; // 传送门到自身的距离为0
}
// 多源BFS核心逻辑
while(!qpr.empty()){
pair<int,int> front=qpr.front();qpr.pop(); // 取出队首元素
int x=front.first,y=front.second; // 当前点的坐标
int dis=dis1[x][y]; // 当前点的最短距离
// 遍历四个方向
for(int i=0;i<4;i++){
int tx=x+dx[i]; // 新点x坐标
int ty=y+dy[i]; // 新点y坐标
// 边界检查 + 障碍物检查 + 未访问过检查
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&g[tx][ty]!='#'&&dis1[tx][ty]==-1){
dis1[tx][ty]=dis+1; // 更新最短距离
qpr.push({tx,ty}); // 加入队列继续搜索
}
}
}
}
// BFS2:计算起点出发,主角和镜像同步移动能到达的点的最短距离
void bfs2(){
queue<pair<int,int>> qpr;
qpr.push({sx,sy}); // 起点入队
dis2[sx][sy]=0; // 起点到自身的距离为0
while(!qpr.empty()){
pair<int,int> front=qpr.front();qpr.pop(); // 取出队首元素
int x=front.first,y=front.second; // 当前主角位置
int jx=2*sx-x; // 镜像的x坐标(以起点为中心对称)
int jy=2*sy-y; // 镜像的y坐标(以起点为中心对称)
// 遍历四个移动方向
for(int i=0;i<4;i++){
// 主角移动后的新坐标
int tx=x+dx[i];
int ty=y+dy[i];
// 镜像同步移动后的新坐标(与主角移动方向相反)
int tjx=jx-dx[i];
int tjy=jy-dy[i];
// 边界检查:主角和镜像都不能越界,且都不能走到障碍物(#)上
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&tjx>=1&&tjx<=n&&tjy>=1&&tjy<=m&&g[tx][ty]!='#'&&g[tjx][tjy]!='#'){
// 如果主角新位置未访问过,更新距离并加入队列
if(dis2[tx][ty]==-1){
qpr.push({tx,ty});
dis2[tx][ty]=dis2[x][y]+1;
}
// 如果镜像新位置未访问过,更新镜像位置的距离
if(dis2[tjx][tjy]==-1){
dis2[tjx][tjy]=dis2[jx][jy]+1;
}
}
}
}
}
// 主逻辑处理函数:计算最小时间
void solve(){
// 初始化距离数组为-1(-1表示不可达)
memset(dis1,-1,sizeof(dis1));
memset(dis2,-1,sizeof(dis2));
// 执行两次BFS,分别计算传送门和起点的最短距离
bfs1();
bfs2();
int res_time=INF; // 初始化最小时间为无穷大
// 遍历地图上所有点,寻找最优解
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
// 只处理起点能到达的点
if(dis2[i][j]!=-1){
int t1=dis2[i][j]; // 起点到(i,j)的时间
int jx=2*sx-i; // (i,j)对应的镜像位置x
int jy=2*sy-j; // (i,j)对应的镜像位置y
// 情况1:当前位置是传送门,且镜像位置能被其他传送门到达
if(g[i][j]=='@'&&dis1[jx][jy]!=-1){
res_time=min(res_time,t1+dis1[jx][jy]);
}
// 情况2:镜像位置是传送门,且当前位置能被其他传送门到达
if(g[jx][jy]=='@'&&dis1[i][j]!=-1){
res_time=min(res_time,t1+dis1[i][j]);
}
}
}
}
// 输出结果:如果最小时间还是无穷大则输出-1,否则输出最小时间
if(res_time==INF){
cout<<-1<<endl;
}else{
cout<<res_time<<endl;
}
return;
}
int main(){
// 输入地图尺寸和起点坐标
cin>>n>>m>>sx>>sy;
// 输入地图信息,并收集所有传送门的坐标
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>g[i][j];
if(g[i][j]=='@'){ // 识别传送门并存储坐标
transdoor.push_back({i,j});
}
}
}
// 执行核心逻辑
solve();
return 0;
}