/*
TASK:lab101
LANG:C++
*/
/*****************************
MAXSTATE!!!!!!!!!!!!!!!!!!!
*****************************/
#include <cstdio>
#include <utility>
#include <queue>
#include <cassert>

const int MAXN = 1 << 3;
const int MAXM = 1 << 4;
const int MAXS = 1 << 4;
const int MAXSTATE = /*1 << 17;*/5120000;
const int MAXMOVE = 5;

const int difx [] = {0, 1, 0, -1};
const int dify [] = {1, 0, -1, 0};

struct state {
	int x1, y1;
	int x2, y2;
	int keys;
	bool f;
	state () {}
	state (int _x1, int _y1, int _x2, int _y2, int _keys, bool _f) : x1 (_x1), y1 (_y1), x2 (_x2), y2 (_y2), keys (_keys), f (_f) {}
};

std::queue <int> q;

int NN;
int N, M;
int P, S;//S - spec cnt;
bool board[MAXN][MAXM];//use this board at generating (only fill with 0 at spec[].f, spec[].s)
int key[MAXN][MAXM];
int _x1, _y1, _x2, _y2;
int Fx, Fy;
std::pair <int, int> spec[MAXS];

int vec[MAXSTATE][MAXMOVE];
char vc[MAXSTATE];
char in[MAXSTATE];
char opt[MAXSTATE];

int __fk;
int getid (int x, int y) {
	std::pair <int, int> _new (x, y);
	int i;
	for (i = 0; i < S && spec[i] != _new; ++i);
	if (i == S) {
		++S;
		spec[i] = _new;
		__fk <<= 1;
		__fk |= (int)board[x][y];
		board[x][y] = 0;
	}

	return i;
}

void input () {
	scanf ("%d %d", &N, &M);
	
	int tmp;
	int i, j;
	for (i = 0; i < N; ++i)
		for (j = 0; j < M; ++j) {
			scanf ("%d", &tmp);
			board[i][j] = tmp;
			key[i][j] = -1;
		}

	int x, y, a, b;
	scanf ("%d", &P);
	for (i = 0; i < P; ++i) {
		scanf ("%d %d %d %d", &x, &y, &a, &b);
		--x; --y; --a; --b;
		key[x][y] = getid (a, b);
	}
	
	scanf ("%d %d", &_x1, &_y1); --_x1; --_y1;
	scanf ("%d %d", &_x2, &_y2); --_x2; --_y2;
	scanf ("%d %d", &Fx, &Fy); --Fx, --Fy;

/*
	for (i = 0; i < S; ++i)
		printf ("%d %d\n", spec[i].first, spec[i].second);

	for (i = 0; i < N; ++i) {
		for (j = 0; j < M; ++j)
			printf ("(%2d %2d)", board[i][j], key[i][j]);
		printf ("\n");
	}
	printf ("-%x-\n", __fk);
*/
}

int _T1, _T2, _T3;
int code (state s) {
//	printf ("%d %d %d %d---(%d) %d, %x %x\n", s.x1 * _T1, s.x2 * _T2, s.y1 * _T3, s.y2, S, ((s.x1 * _T1 + s.x2 * _T2 + s.y1 * _T3 + s.y2) << (S + 1)), s.f << S, s.keys);
	return ((s.x1 * _T1 + s.x2 * _T2 + s.y1 * _T3 + s.y2) << (S + 1)) | (s.f << S) | s.keys;
}

state decode (int a) {
	static state ss;
	ss.keys = a & ((1 << S) - 1); a >>= S;
	ss.f = a & 1; a >>= 1;
	ss.x1 = a / _T1; a %= _T1;
	ss.x2 = a / _T2; a %= _T2;
	ss.y1 = a / _T3; a %= _T3;
	ss.y2 = a;
	for (int i = 0; i < S; ++i)
		board[spec[i].first][spec[i].second] = ss.keys & (1 << S - 1 - i);
	return ss;
}

void prnt (state s) {
	printf ("(%d %d) (%d %d) %d %x\n", s.x1, s.y1, s.x2, s.y2, (int)s.f, s.keys);
}

void prntbd () {
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < M; ++j)
			printf ("%d ", board[i][j]);
		printf ("\n");
	}
}

bool not_there (state s, int sc) {
	int xx = spec[sc].first, yy = spec[sc].second;
	return (!(xx == s.x1 && yy == s.y1) && !(xx == s.x2 && yy == s.y2));
}

bool ok (int a, int b) {
	return (a >= 0 && a < N && b >= 0 && b < M);
}

int fin_kid (int a) {
	return a ^ 1 << S;//switch the man-on-move bit
}

void generate () {
	_T1 = M * M * N, _T2 = M * M, _T3 = M;

/*	state xx (_x1, _y1, _x2, _y2, __fk, 0);
	printf ("xx.k == %x\n", xx.keys);
	int yy = code (xx);
	printf ("%d\n", yy);
	state zz = decode (yy);
*//*	prnt (xx);
	prnt (zz);
*/
//	prntbd ();
	NN = ((_T1 * N) << (S + 1));
//	for (int i = 0; i < NN; ++i) opt[i] = -1;//not calced ---- will be 0
	int i, k;
	int to;
	int kid;
	int *_x, *_y;
//	int spc = 0;
	state crnt;
	for (i = 0; i < NN; ++i) {
		in[i] = 1;
		crnt = decode (i);
//		prnt (crnt);
		//check final
		if (crnt.x1 == Fx && crnt.y1 == Fy) {//1viq e na finala
			if (crnt.f) {//2riq e na hod
//				printf ("1st win\n");
				opt[i] = 1;//1viq bie
				q.push (i);
			} else {
//				++spc;
//				opt[i] = 3;//stupid position :)
			}
		}
		if (crnt.x2 == Fx && crnt.y2 == Fy) {//2ruq e na finala
			if (!crnt.f) {//1vuq e na hod
//				printf ("2nd win\n");
				opt[i] = 2;//2riq bie
				q.push (i);
			} else {
//				++spc;
//				opt[i] = 3;//stupid position :)
			}
		}

		//move the current player
		if (crnt.f) {
			_x = &crnt.x2;
			_y = &crnt.y2;
		} else {
			_x = &crnt.x1;
			_y = &crnt.y1;
		}
		crnt.f = !crnt.f;
		for (k = 0; k < 4; ++k) {
			if (ok (*_x += difx[k], *_y += dify[k]) && !board[*_x][*_y]) {
//				printf ("\t"); prnt (crnt);
				to = code (crnt);
				++in[i];
				vec[to][vc[to]++] = i;
			}

			*_x -= difx[k]; *_y -= dify[k];
		}

		//add change key
//		if (i == 1308) printf ("!!!!(%d %d)%d\n", kid = key[*_x][*_y]));
		if ((kid = key[*_x][*_y]) != -1 && not_there (crnt, kid)) {
//			printf ("---%d(%d %d)\n", i, kid, S - 1 - kid);
			crnt.keys ^= 1 << (S - 1 - kid);
//			printf ("\t"); prnt (crnt);
			to = code (crnt);
//			if (i == 1308) {printf ("-!(%d)!-", to); prnt (crnt);}
			++in[i];
			vec[to][vc[to]++] = i;
		}
	}
//	printf ("%d spc!\n", spc);
}

int bfs () {
	int crnt, i;
	while (!q.empty ()) {
		crnt = q.front (); q.pop ();
//		printf ("%d popped --\n", crnt);// prnt (decode (crnt));
//		++cntr;

		if (opt[crnt] == 1 && crnt & (1 << S) ||
			opt[crnt] == 2 && !(crnt & (1 << S))) {
		
			for (i = 0; i < vc[crnt]; ++i) {
				assert (in[vec[crnt][i]]);
				if (!opt[vec[crnt][i]]) {
					opt[vec[crnt][i]] = opt[crnt];
					q.push (vec[crnt][i]);
				}
			}
			assert (in[vec[crnt][i]]);
			if (!opt[fin_kid (crnt)]) {
				opt[fin_kid (crnt)] = opt[crnt];
				q.push (fin_kid (crnt));
			}
		} else {
			for (i = 0; i < vc[crnt]; ++i)
				if (!opt[vec[crnt][i]] && !(--in[vec[crnt][i]])) {
					opt[vec[crnt][i]] = opt[crnt];
					q.push (vec[crnt][i]);
				}
			if (!opt[fin_kid (crnt)] && !(--in[fin_kid (crnt)])) {
				opt[fin_kid (crnt)] = opt[crnt];
				q.push (fin_kid (crnt));
			}
		}
	}
//	printf ("popped all = %d(%d) (from %d)\n", cntr, cntr2, NN);
	return (int)opt[code (state (_x1, _y1, _x2, _y2, __fk, 0))];
}

int main () {
	input ();
	generate ();
	int ret = bfs ();
	printf ("%d\n", ret);

//	printf ("%d\n", opt[1311]);
//	printf ("%d(%d)\n", opt[code (state (2, 0, 3, 2, 0, 0))], code (state (2, 0, 3, 2, 0, 0)));
	
	return 0;
}

