#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 4
#define LIMIT 5

enum DIR{
	North,
	East,
	South,
	West,
};
DIR dir_array[4] = {North,East,South,West};
int diff_row[4] = {-1,0,1,0},diff_col[4] = {0,1,0,-1};


struct Info{
	int table[NUM][NUM],max_value,click_count;
};

struct Data{
	Data(){
		row = col = 0;
		dir = North;
	}

	Data(int arg_row,int arg_col,DIR arg_dir){
		row = arg_row;
		col = arg_col;
		dir = arg_dir;
	}
	int row,col;
	DIR dir;
};

bool rangeCheck(int row,int col){
	if(row >= 0 && row <= NUM-1 && col >= 0 && col <= NUM-1)return true;
	else{
		return false;
	}
}

int getMaxValue(int table[NUM][NUM]){

	int ret = 0;

	for(int row = 0; row < NUM; row++){
		for(int col = 0; col < NUM; col++){
			ret = max(ret,table[row][col]);
		}
	}

	return ret;
}

void copyInfo(Info& to,Info from){

	for(int row = 0; row < NUM; row++){
		for(int col = 0; col < NUM; col++){
			to.table[row][col] = from.table[row][col];
		}
	}

	to.click_count = from.click_count+1;
}

void calc(Info& info,int first_row,int first_col){

	info.table[first_row][first_col] = 0;

	queue<Data> Q,NEXT;

	int adj_row,adj_col;

	for(int i = 0; i < 4; i++){
		adj_row = first_row+diff_row[i];
		adj_col = first_col+diff_col[i];

		if(!rangeCheck(adj_row,adj_col))continue;

		Q.push(Data(adj_row,adj_col,dir_array[i]));
	}

	Data tmp;
	int next_row,next_col;

	while(true){

		while(!Q.empty()){
			tmp = Q.front();
			Q.pop();

			if(info.table[tmp.row][tmp.col] == 0){

				switch(tmp.dir){
				case North:
					next_row = tmp.row-1;
					next_col = tmp.col;
					break;
				case East:
					next_row = tmp.row;
					next_col = tmp.col+1;
					break;
				case South:
					next_row = tmp.row+1;
					next_col = tmp.col;
					break;
				case West:
					next_row = tmp.row;
					next_col = tmp.col-1;
					break;
				}

				if(rangeCheck(next_row,next_col)){
					NEXT.push(Data(next_row,next_col,tmp.dir));
				}

			}else{
				info.table[tmp.row][tmp.col]++;
			}
		}

		for(int row = 0; row < NUM; row++){
			for(int col = 0; col < NUM; col++){
				if(info.table[row][col] >= 5){
					info.table[row][col] = 0;

					for(int i = 0; i < 4; i++){

						adj_row = row+diff_row[i];
						adj_col = col+diff_col[i];

						if(!rangeCheck(adj_row,adj_col))continue;

						NEXT.push(Data(adj_row,adj_col,dir_array[i]));
					}
				}
			}
		}

		if(NEXT.empty())break;
		while(!NEXT.empty()){
			Q.push(NEXT.front());
			NEXT.pop();
		}
	}
}


int main(){

	Info first;
	for(int row = 0; row < NUM; row++){
		for(int col = 0; col < NUM; col++)scanf("%d",&first.table[row][col]);
	}

	first.max_value = getMaxValue(first.table);
	first.click_count = 0;

	queue<Info> Q;
	Q.push(first);

	bool cleard = false;

	while(!Q.empty()){

		if(Q.front().max_value == 0){
			printf("%d\n",Q.front().click_count);
			cleard = true;
			break;
		}else if(Q.front().click_count == LIMIT){
			Q.pop();
		}else if(LIMIT-Q.front().click_count < LIMIT-Q.front().max_value){
			Q.pop();
		}else{

			for(int row = 0; row < NUM; row++){
				for(int col = 0; col < NUM; col++){

					Info next_info;
					copyInfo(next_info,Q.front());
					next_info.table[row][col]++;

					if(next_info.table[row][col] == 5){
						calc(next_info,row,col);
					}
					next_info.max_value = getMaxValue(next_info.table);
					Q.push(next_info);				}
			}

			Q.pop();
		}
	}

	if(!cleard){
		printf("-1\n");
	}

	return 0;
}



Measured memory_bytes: 79124