#include <bits/stdc++.h>
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME
#define pr(...) cerr<< GET_MACRO(__VA_ARGS__,pr8,pr7,pr6,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__) <<endl
#define pr1(a) (#a)<<"="<<(a)<<" "
#define pr2(a,b) pr1(a)<<pr1(b)
#define pr3(a,b,c) pr1(a)<<pr2(b,c)
#define pr4(a,b,c,d) pr1(a)<<pr3(b,c,d)
#define pr5(a,b,c,d,e) pr1(a)<<pr4(b,c,d,e)
#define pr6(a,b,c,d,e,f) pr1(a)<<pr5(b,c,d,e,f)
#define pr7(a,b,c,d,e,f,g) pr1(a)<<pr6(b,c,d,e,f,g)
#define pr8(a,b,c,d,e,f,g,h) pr1(a)<<pr7(b,c,d,e,f,g,h)
#define prArr(a) {cerr<<(#a)<<"={";int i=0;for(auto t:(a))cerr<<(i++?", ":"")<<t;cerr<<"}"<<endl;}
using namespace std;
using Int = long long;
using _int = int;
using ll = long long;
using Double = long double;
const Int INF = (1LL<<60)+1e9; // ~ 1.15 * 1e18
const Int mod = (1e9)+7;
const Double EPS = 1e-8;
const Double PI = 6.0 * asin((Double)0.5);
using P = pair<Int,Int>;
template<class T> T Max(T &a,T b){return a=max(a,b);}
template<class T> T Min(T &a,T b){return a=min(a,b);}
template<class T1, class T2> ostream& operator<<(ostream& o,pair<T1,T2> p){return o<<"("<<p.first<<","<<p.second<<")";}
template<class T1, class T2, class T3> ostream& operator<<(ostream& o,tuple<T1,T2,T3> t){
  return o<<"("<<get<0>(t)<<","<<get<1>(t)<<","<<get<2>(t)<<")";}
template<class T1, class T2> istream& operator>>(istream& i,pair<T1,T2> &p){return i>>p.first>>p.second;}
template<class T> ostream& operator<<(ostream& o,vector<T> a){Int i=0;for(T t:a)o<<(i++?" ":"")<<t;return o;}
template<class T> istream& operator>>(istream& i,vector<T> &a){for(T &t:a)i>>t;return i;}
//INSERT ABOVE HERE
using ull = unsigned int;
const int N = 4;
using mat = vector<vector<char> >;

int calcCost(mat &pos, mat &goal){
  static int idxX[N * N], idxY[N * N], init = 1;
  if(init){
    init = 0;
    for(int i=0;i<N;i++)
      for(int j=0;j<N;j++) idxX[goal[i][j]] = j, idxY[goal[i][j]] = i;
  }
  
  int res = 0;  
  for(int i=0;i<N;i++)
    for(int j=0;j<N;j++){
      if(pos[i][j] == 0) continue;
      res += abs(i - idxY[pos[i][j]]) + abs(j - idxX[pos[i][j]]);
    }
  return res;
}

int calcCostDiff(mat &pos, mat &goal, int i, int j, int ni, int nj){
  static int idxX[N * N], idxY[N * N], init = 1;
  if(init){
    init = 0;
    for(int i=0;i<N;i++)
      for(int j=0;j<N;j++) idxX[goal[i][j]] = j, idxY[goal[i][j]] = i;
  }
  
  int a = abs(ni - idxY[ pos[i][j] ]) + abs(nj - idxX[ pos[i][j] ]);
  int b = abs(i - idxY[ pos[i][j] ]) + abs(j - idxX[ pos[i][j] ]);
  return -a + b;
}

ull toHash(mat &mp){
  const ull B = 1777771;
  ull hash = 0;
  for(int i=0;i<N;i++)
    for(int j=0;j<N;j++) hash = hash * B + mp[i][j];
  return hash;
}

ull calcHashDiff(mat &mp, int i, int j,int ni, int nj){
  static int init = 1;
  static ull pow[20];
  const ull B = 1777771;
  if(init){
    init = 0;
    pow[0] = 1;
    for(int i=1;i<20;i++) pow[i] = pow[i-1] * B;
  }

  int idx1 = i * N + j;
  int idx2 = ni * N + nj;
  ull p1 = pow[N * N - 1 - idx1];
  ull p2 = pow[N * N - 1 - idx2];
  return -(mp[ni][nj] * p1 + mp[i][j] * p2) + (mp[i][j] * p1 + mp[ni][nj] * p2);
}

int dijkstra(mat start, mat goal){
  using T = tuple<char, ull>;
  using P = pair<char, mat>;
  unordered_map<ull, P> D;
  
  priority_queue<T, vector<T>, greater<T> > Q;
  Q.push(T(calcCost(start, goal), toHash(start)));
  D[toHash(start)] = P(0, start);
  ull ghash = toHash(goal);
  queue<ull> his;
  his.push(toHash(start));
  
  while(!Q.empty()){
    int cost;
    ull hash;
    tie(cost, hash) = Q.top(); Q.pop();
    mat &A = D[hash].second;

    if(hash == ghash) return cost;

    his.push(hash);
    if(his.size() > 10000){
      D.erase(his.front());
      his.pop();
    }
    
    int y, x;
    for(int i=0;i<N;i++)
      for(int j=0;j<N;j++)
	if(A[i][j] == 0) {y = i, x = j;break;}

    const int dx[] = {0, 0, 1, -1};
    const int dy[] = {1, -1, 0, 0};
    for(int i=0;i<4;i++){
      int nx = x + dx[i];
      int ny = y + dy[i];
      if(nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
      swap(A[y][x], A[ny][nx]);
      mat &nA = A;
      int ncost = calcCostDiff(nA, goal, y, x, ny, nx) + cost + 1;
      ull nhash = hash + calcHashDiff(nA, y, x, ny, nx);
      if(!D.count(nhash) && ncost <= 45){
	Q.push(T(ncost, nhash));
	D[nhash] = P(ncost, nA);
      }
      swap(A[y][x], A[ny][nx]);
    }
  }
  assert(0);
}

signed main(){
  srand((unsigned)time(NULL));
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);

  mat goal(N, vector<char>(N));
  for(int i=0;i<N;i++)
    for(int j=0;j<N;j++) goal[i][j] = i*N + j + 1;
  goal[N-1][N-1] = 0;

  mat start(N, vector<char>(N));
  for(int i=0;i<N;i++)
    for(int j=0;j<N;j++){
      int num;
      cin>>num;
      start[i][j] = num;
    }
  
  int ans = dijkstra(start, goal);
  cout<<ans<<endl;
  return 0;
}



Measured memory_bytes: 236084