//accepted by rose 2160,rose 1213
//cut pos is depend on whether input polygon is clockwise or cunterclock wise
//ortho?gical line de cut
#include<iostream>
#include<complex>
#include<vector>
#include<map>
#include<queue>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
const double eps = 1e-10;

#define RIGHT 1
#define LEFT -1

typedef complex<double> P;
typedef vector<P> Polygon;
typedef pair<P,P> Line;


class Edge{
public:
  int to;
  double cost;
  Edge(){};
  Edge(int tto,double ccost):to(tto),cost(ccost){}
};

class Point{
public:
  P data;
  Point(){};
  Point(P a):data(a){}
  bool operator<(const Point & a)const{
    if ( abs(data.real()-a.data.real())>eps)return data.real()<a.data.real();
    if ( abs(data.imag()-a.data.imag())>eps)return data.imag()<a.data.imag();
    return false;
  }
};

double cross(P a,P b){
  return a.real()*b.imag()-a.imag()*b.real();
}

P intersection_ll(P a1,P a2,P b1,P b2){
  P a=a2-a1,b=b2-b1;
  return a1+a*cross(b,b1-a1)/cross(b,a);
}


int ccw(P a,P b){
  if ( cross(a,b)<0)return RIGHT;
  else if ( cross(a,b)>0)return LEFT;
  return 2;
}

vector<P> Convex_Cut(Polygon in,int n,P a1,P a2,int cutpos){
  vector<P> ret;
  rep(i,n){
    P now = in[i],next=in[(i+1)%n];
    if( ccw(a1-a2,now-a2)==cutpos)ret.push_back(now);
    if ( ccw(a1-a2,now-a1)*ccw(a1-a2,next-a2)<0)
      ret.push_back(intersection_ll(a1,a2,now,next));
  }
  return ret;
}

//cutpos ha mondai izon. which side will remain
Line make_line(P ori,P b,int cutpos){
  P tmp=(ori+b);
  tmp.real()/=2;tmp.imag()/=2;
  P ret=b-tmp;
  swap(ret.real(),ret.imag());
  ret.real()*=-1;
  if ( ccw(ret,ori-tmp)!= cutpos)return make_pair(tmp,ret+tmp);
  return make_pair(ret+tmp,tmp);
}


void solve(int m,Polygon in,vector<P> CutLine,map<Point,int> &M,vector<Edge> *E,vector<P> &startcandidate){
  vector<Line> ver;
  rep(i,CutLine.size())
    if ( i == m)continue;
    else ver.push_back(make_line(CutLine[m],CutLine[i],LEFT));

  rep(i,ver.size())
    in=Convex_Cut(in,in.size(),ver[i].first,ver[i].second,LEFT);
  
  rep(i,in.size()){
    Point f(in[i]),t(in[(i+1)%in.size()]);
    int from,to;
    if ( M.find(f) ==M.end()){
      int tmp=M.size();M[f]=tmp,startcandidate.push_back(in[i]);
    }
    from=M[f];
    if ( M.find(t) ==M.end()){
      int tmp=M.size();M[t]=tmp,startcandidate.push_back(in[(i+1)%in.size()]);
    }
    to=M[t];
    
    if (abs(in[i].imag())<eps && abs(in[(i+1)%in.size()].imag()) <eps)continue;
    if (abs(in[i].imag()-4)<eps && abs(in[(i+1)%in.size()].imag()-4)<eps)continue;
    E[from].push_back(Edge(to,abs(in[i]-in[(i+1)%in.size()])));
    E[to].push_back(Edge(from,abs(in[i]-in[(i+1)%in.size()])));
  }
}



const double INF = 100000000;
void solve2(int n,vector<int> start,vector<int>goal,vector<Edge> *E){
  double ans=INF;
  double cost[n][n];
  rep(i,n){
    rep(j,n)cost[i][j]=INF;
  }
  rep(i,n){
    rep(j,E[i].size()){
      cost[i][E[i][j].to]=E[i][j].cost;
    }
  }

  rep(k,n){
    rep(i,n){
      rep(j,n)cost[i][j]=min(cost[i][j],cost[i][k]+cost[k][j]);
    }
  }

  rep(i,start.size()){
    rep(j,goal.size()){
      ans = min(ans,cost[start[i]][goal[j]]);
    }
  }
  if ( ans >= INF-eps)puts("impossible");
  else printf("%.5lf\n",ans);
}

main(){
  int n;
  Polygon a;
  a.push_back(complex<double>(0,0));
  a.push_back(complex<double>(4,0));
  a.push_back(complex<double>(4,4));
  a.push_back(complex<double>(0,4));
  while(cin>>n && n){
    vector<P> Mons;
    map<Point,int> M;
    vector<Edge>    E[500];
    vector<P> node;
    rep(i,n){
      P tmp;
      cin>>tmp.real()>>tmp.imag();
      Mons.push_back(tmp);
    }
    
    rep(i,n){
      solve(i,a,Mons,M,E,node);
    }

    vector<int> start,goal;
    n=node.size();
    rep(i,n){
      if ( node[i].real()<eps)start.push_back(i);
      else if ( abs(node[i].real()-4)<eps)goal.push_back(i);
    }
    if ( n >200)return true;
    solve2(n,start,goal,E);
    
  }
}

Measured memory_bytes: 0