#include <bits/stdc++.h>
using namespace std;
int Kralj=0;
int Lovac= 1;
int Top= 2;
int Konj= 3;
int Kraljica= 4;
int n,m;
int KingX[8]={1,1,1,-1,-1,-1,0,0};
int KingY[8]={0,1,-1,0,1,-1,1,-1};
int HorseX[8]={-1,-1,1,1,-2,-2,2,2};
int HorseY[8]={2,-2,2,-2,1,-1,1,-1};
int QueenX[8]={1,1,1,-1,-1,-1,0,0};
int QueenY[8]={0,1,-1,0,1,-1,1,-1};
int CannonX[4]={0,0,-1,1};
int CannonY[4]={1,-1,0,0};
int BishopX[4]={1,1,-1,-1};
int BishopY[4]={-1,1,-1,1};

vector <int > MovesX[5];
vector <int > MovesY[5];
void InitMoves(){
MovesX[Kralj]=vector <int>(begin(KingX),end(KingX));
MovesX[Kraljica]=vector <int>(begin(KingX),end(KingX));
MovesX[Top]=vector <int>(begin(CannonX),end(CannonX));
MovesX[Lovac]=vector <int>(begin(BishopX),end(BishopX));
MovesX[Konj]=vector <int>(begin(HorseX),end(HorseX));

MovesY[Kralj]=vector <int>(begin(KingY),end(KingY));
MovesY[Kraljica]=vector <int>(begin(KingY),end(KingY));
MovesY[Top]=vector <int>(begin(CannonY),end(CannonY));
MovesY[Lovac]=vector <int>(begin(BishopY),end(BishopY));
MovesY[Konj]=vector <int>(begin(HorseY),end(HorseY));
}

void Check(vector <string> &a,int x=0,int y=0){
    if(x<0||y<0||x>=a.size()||y>a[0].size())return;
    if(a[x][y]!='.')return;
    a[x][y]='Z';
    for(int i=0;i<8;i++){
        Check(a,x+KingX[i],y+KingY[i]);
        Check(a,x+HorseX[i],y+HorseY[i]);
    }

}
void Die(int code){
    cout <<code<<endl;
    exit(0);
}
struct Cost{

    int Kraljica[8];
    int Top[4];
    int Lovac[4];
};
struct Move{
int SourceX,SourceY;
int NodeX,NodeY;
int Cena;
int Figure;
};
struct CompareMoves{
    bool operator()(Move const& A,Move  const&B){
        return A.Cena>B.Cena;
    }
};
vector <vector<int> > DP[5];
vector <vector<bool> > Bio[5];
vector <vector <Cost> > Cene;
 Cost Default(){
    Cost cena;
    for(int i=0;i<4;i++){
       cena.Top[i]=1;
       cena.Lovac[i]=1;
    }
    for(int i=0;i<8;i++)
        cena.Kraljica[i]=1;

    return cena;
}
int IndexOfMove(int x1,int y1,int x2,int y2,int figura){
    int deltaX=x2-x1;
    int deltaY=y2-y1;
    for(int i=0;i<MovesX[figura].size();i++){
        if(MovesX[figura][i]==deltaX&&MovesY[figura][i]==deltaY)return i;
    }
    ///cout <<"FOUND ERRORRRRRRRRR"<<endl;
    return -1;
}


Move MakeMove(int x1,int y1,int x2,int y2,int Figure,int Cena){
Move mov;
mov.SourceX=x1;
mov.SourceY=y1;
mov.NodeX=x2;
mov.NodeY=y2;
mov.Figure=Figure;
mov.Cena=Cena;
return mov;
}
void SrediCene(const Move &A,const Move &B){///Sredjuje se A(gleda se samo A.Node, jer je src nebitan)
///SREDI SEBE
if(A.NodeX==A.SourceX&&A.SourceY==A.NodeY){
     if(A.Figure==Kraljica)
        for(int i=0;i<8;i++)
            Cene[A.NodeX][A.NodeY].Kraljica[i]=0;
     if(A.Figure==Top)
        for(int i=0;i<4;i++)
            Cene[A.NodeX][A.NodeY].Top[i]=0;
     if(A.Figure==Lovac)
          for(int i=0;i<4;i++)
            Cene[A.NodeX][A.NodeY].Lovac[i]=0;
    return;
}

     if(A.Figure==Kraljica)
        Cene[A.NodeX][A.NodeY].Kraljica[IndexOfMove(A.SourceX,A.SourceY,A.NodeX,A.NodeY,Kraljica)]=0;
     if(A.Figure==Top)
        Cene[A.NodeX][A.NodeY].Top[IndexOfMove(A.SourceX,A.SourceY,A.NodeX,A.NodeY,Top)]=0;
     if(A.Figure==Lovac)
        Cene[A.NodeX][A.NodeY].Lovac[IndexOfMove(A.SourceX,A.SourceY,A.NodeX,A.NodeY,Lovac)]=0;


    if(!(A.Figure==B.Figure))return;
    if(B.SourceX==B.NodeX&&B.SourceY==B.NodeY)return;
  if(B.NodeX<0||B.NodeY<0||B.NodeX>=n||B.NodeY>=m)return;

    int dx=B.NodeX-B.SourceX;
    int dy=B.NodeY-B.SourceY;
    int vx=A.NodeX-B.SourceX;
    int vy=A.NodeY-B.SourceY;
    if((dx==vx||(dx*vx>0&&vx%dx==0))&&(dy==vy||(dy*vy>0&&vy%dy==0))){
        if(!(vx*dy==dx*vy))return;
        if(A.Figure==Kraljica)
        Cene[A.NodeX][A.NodeY].Kraljica[IndexOfMove(0,0,dx,dy,Kraljica)]=0;
        if(A.Figure==Top)
        Cene[A.NodeX][A.NodeY].Top[IndexOfMove(0,0,dx,dy,Top)]=0;
           if(A.Figure==Lovac)
        Cene[A.NodeX][A.NodeY].Lovac[IndexOfMove(0,0,dx,dy,Lovac)]=0;
    }
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cerr.tie(0);
    InitMoves();

    //cin >>n>>m;
    n=50;
    m=50;

    Cene.resize(n,vector<Cost>(m));
    int solved=0;
    for(int i=0;i<5;i++)DP[i].resize(n,vector <int> (m,1000));
    for(int i=0;i<5;i++)Bio[i].resize(n,vector <bool> (m));

    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            Cene[i][j]=Default();
        }
    }
    vector <string> a(n);
    string s="";
    for(int j=0;j<m;j++)s+='.';
    for(int i=0;i<n;i++){

    a[i]=s;
    }


    vector <string> cpy(n);
    cpy=a;
    Check(cpy);
    if(cpy[n-1][m-1]!='Z')Die(-1);

    priority_queue<Move,vector<Move>, CompareMoves > pq;
    vector<Move> q;

    for(int k=0;k<5;k++){
    pq.push(MakeMove(0,0,0,0,k,k+2-2*(k==Kralj)-(k==Konj)));
    }
   /* for(int k=0;k<5;k++){
            for(int i=0;i<MovesX[k].size();i++)
                pq.push(MakeMove(0,0,MovesX[k][i],MovesY[k][i],k,k+2-(k==Kralj)-(k==Konj)));
            DP[k][0][0]=k+1-(k==Kralj);
    }
*/


     while(q.size()||pq.size()||solved>=n*m*5-1){///HERE GOES CRAZY DP WITH DIJIKSTRA AND MOVE OPTIMISATIONS
        Move Current;
        solved++;
        if(q.size()){
            Current=q.back();
            q.pop_back();
        }
        else {
            Current=pq.top();
            pq.pop();
        }
       // cout <<"Njet broken yet"<<endl;
       ///cout <<Current.Figure<<" "<<Current.NodeX<<" "<<Current.NodeY<<endl;

       if(Current.NodeX<0||Current.NodeY<0||Current.NodeX>=n||Current.NodeY>=m)continue;

        if(a[Current.NodeX][Current.NodeY]=='#')continue;

        if(Bio[Current.Figure][Current.NodeX][Current.NodeY])continue;

        Bio[Current.Figure][Current.NodeX][Current.NodeY]=1;

        for(int i=0;i<q.size();i++){
            SrediCene(Current,q[i]);
        }

        if(Current.Figure!=Kralj&&Current.Figure!=Konj){
            while(pq.size()&&pq.top().Cena==Current.Cena){
                Move Qd=pq.top();
                pq.pop();

                SrediCene(Current,Qd);

                    q.push_back(Qd);

            }
        }


    DP[Current.Figure][Current.NodeX][Current.NodeY]=Current.Cena;
    for(int i=0;i<5;i++){
        if(i==Current.Figure)continue;
        pq.push(MakeMove(Current.NodeX,Current.NodeY,Current.NodeX,Current.NodeY,i,Current.Cena+i+2-(i==Kralj||i==Konj)));

    }
    for(int i=0;i<MovesX[Current.Figure].size();i++){
            int DeltaCena=1;
        if(Current.Figure==Kralj||Current.Figure==Konj)DeltaCena=1;

        if(Current.Figure==Kraljica){
        DeltaCena=Cene[Current.NodeX][Current.NodeY].Kraljica[IndexOfMove(Current.NodeX,Current.NodeY,Current.NodeX+MovesX[Kraljica][i],Current.NodeY+MovesY[Kraljica][i],Kraljica)];
        }
        if(Current.Figure==Top){
        DeltaCena=Cene[Current.NodeX][Current.NodeY].Top[IndexOfMove(Current.NodeX,Current.NodeY,Current.NodeX+MovesX[Top][i],Current.NodeY+MovesY[Top][i],Top)];
        }
        if(Current.Figure==Lovac){

        DeltaCena=Cene[Current.NodeX][Current.NodeY].Lovac[IndexOfMove(Current.NodeX,Current.NodeY,Current.NodeX+MovesX[Lovac][i],Current.NodeY+MovesY[Lovac][i],Lovac)];
        }
     pq.push(MakeMove(Current.NodeX,Current.NodeY,Current.NodeX+MovesX[Current.Figure][i],Current.NodeY+MovesY[Current.Figure][i],Current.Figure,Current.Cena+DeltaCena));


    }

 }
 for(int k=0;k<5;k++){
        ///cout <<endl<<k<<endl;
 ///cout <<"_____________________________________________________________"<<endl;
     for(int i=0;i<n;i++){
          ///  cout <<endl;
        for(int j=0;j<m;j++){
          ///  cout <<DP[k][i][j] <<" ";
        }
     }
 }
//cout <<endl;
    int rez=DP[0][n-1][m-1];
    int fig=0;
    for(int i=0;i<5;i++){
        if(rez>DP[i][n-1][m-1])fig=i;
    rez=min(rez,DP[i][n-1][m-1]);
    }
   /// cout <<"FIG: "<<fig<<endl;
    cout <<rez<<endl;



}