import std.algorithm, std.conv, std.range, std.stdio, std.string;
import std.container, std.typecons;

const auto n = 4;
const auto bits = 4;

void main()
{
  auto b = 0UL;
  foreach (i; 0..n) {
    auto rd = readln.split.to!(int[]);
    foreach (j, d; rd)
      b = b.setDigit(i * n + j, d);
  }

  auto g = goal;

  auto li = [b: ld(0, false), g: ld(0, true)];
  auto qi = new DList!bld(bld(b, 0, false), bld(g, 0, true));

  int insertQueue(bld q, size_t i, size_t j)
  {
    auto c = q.b.swapDigit(i, j);
    if (c !in li) {
      qi.insertBack(bld(c, q.l + 1, q.d));
      li[c] = ld(q.l + 1, q.d);
    } else if (li[c].d != q.d) {
      return q.l + 1 + li[c].l;
    }
    return -1;
  }

  int loop()
  {
    while (!qi.empty) {
      auto q = qi.front; qi.removeFront;
      auto i = q.b.findZero;
      int r;

      if (i / n > 0     && (r = insertQueue(q, i, i - n)) >= 0) return r;
      if (i / n < n - 1 && (r = insertQueue(q, i, i + n)) >= 0) return r;
      if (i % n > 0     && (r = insertQueue(q, i, i - 1)) >= 0) return r;
      if (i % n < n - 1 && (r = insertQueue(q, i, i + 1)) >= 0) return r;
    }
    return -1;
  }

  writeln(loop);
}

alias Tuple!(ulong, "b", int, "l", bool, "d") bld;
alias Tuple!(int, "l", bool, "d") ld;

ulong goal()
{
  auto r = 0UL;
  foreach (i; 0..n*n-1)
    r = r.setDigit(i, i + 1);
  return r;
}

ulong setDigit(ulong b, size_t i, int val)
{
  return b & (~(((1UL << bits) - 1) << i * bits)) | (val.to!ulong << i * bits);
}

int digit(ulong b, size_t i)
{
  return (b >> i * bits) & ((1UL << bits) - 1);
}

ulong swapDigit(ulong b, size_t i, size_t j)
{
  auto x = b.digit(i), y = b.digit(j);
  return b.setDigit(i, y).setDigit(j, x);
}

ptrdiff_t findZero(ulong b)
{
  foreach (i; 0..n*n)
    if (b.digit(i) == 0)
      return i;
  return -1;
}