#include<bits/stdc++.h>
using namespace std;
using ll = long long;

template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }

#define FOR(i,a,b) for(ll i=(a);i<(b);++i)
#define ALL(v) (v).begin(), (v).end()
#define p(s) cout<<(s)<<endl
#define p2(s, t) cout << (s) << " " << (t) << endl
#define br() p("")
#define pn(s) cout << (#s) << " " << (s) << endl

int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

const int W = 4;

// ofstream of;

struct Point{
    ll x;
    ll y;
    Point(ll x, ll y): x(x), y(y) {}
    Point(){}

    bool operator==(const Point &b)const{
        if(x==b.x && y==b.y){
            return true;
        }else{
            return false;
        }
    }
};

struct Puzzle{
    ll A[W][W];
    vector<ll> path;

    Point get_space(){
        Point p;
        FOR(y, 0, W){
            FOR(x, 0, W){
                if(A[y][x]==0){
                    p.x = x;
                    p.y = y;
                    return p;
                }
            }
        }
        return p;
    }

    bool operator<(const Puzzle &b)const
    {
        FOR(y, 0, W){
            FOR(x, 0, W){
                if(A[y][x] != b.A[y][x]){
                    return A[y][x] < b.A[y][x];
                }
            }
        }
        return false;
    }

    bool is_solved(){
        if(manhattan_distance()==0){
            return true;
        }else{
            return false;
        }
    }

    // 各マスの目的位置までのマンハッタン距離の和
    ll manhattan_distance(){
        ll sum = 0;
        FOR(y, 0, W){
            FOR(x, 0, W){
                ll v = A[y][x];
                ll tx, ty; // 最終的にいるべき場所
                // 0はMDに含めない
                if(v!=0){
                    v--;
                    tx = v%W;
                    ty = v/W;
                    ll dist = abs(x - tx) + abs(y - ty);
                    sum += dist;
                }
            }
        }
        return sum;        
    }

    void print(){
        FOR(y, 0, W){
            FOR(x, 0, W){
                //  << setw(2) << A[y][x] << ' ';
            }
            // of << endl;
        }
    }
};

// depth : 現在深度
bool dfs(ll depth, ll limit, Puzzle pz, Point prev){
    // of << endl << "depth " << depth << endl;
    // pz.print();

    // pn(depth);
    ll MD = pz.manhattan_distance();
    if(MD==0){
        return true;
    }

    // pruning
    if(depth+MD > limit) return false;

    auto sp = pz.get_space();
    
    // 解けてないなら4方向へ移動
    FOR(i, 0, 4){
        ll sx = sp.x;
        ll sy = sp.y;
        
        // target position
        ll tx = sx + dx[i];
        ll ty = sy + dy[i];

        auto cp = pz;

        // in range
        if(0<=tx && tx<W && 0<=ty && ty<W){
            swap(cp.A[sy][sx], cp.A[ty][tx]);

            bool is_new_destination = true;
            if(cp.get_space()==prev){
                is_new_destination = false;
            }

            if(is_new_destination && dfs(depth+1, limit, cp, sp)){
                return true;
            }
        }
    }
    return false;
}


ll iterative_deepening(Puzzle pz){
    ll MD = pz.manhattan_distance();
    FOR(limit, MD, 100){
        // pn(limit);
        Point prev;
        prev.x = -1;
        prev.y = -1;
        
        bool f = dfs(0, limit, pz, prev);
        if(f){
            return limit;
        }
    }
    return -1;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    // of.open("log.txt");

    // 初期状態
    auto p = Puzzle();
    FOR(y, 0, W){
        FOR(x, 0, W){
            cin >> p.A[y][x];
        }
    }

    // p.print();

    ll ans = iterative_deepening(p);
    p(ans);
    
    return 0;
}


Measured memory_bytes: 3212