import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) throws Exception {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);

		Task task = new Task();
		task.solve(in, out);
		out.close();

	}

	static class Rectangle {
		int x1, y1;
		int x2, y2;
	}

	static class Task {
		/**
		 * BEFORE SUBMITTING!!!
		 * MAKE SURE IT IS RIGHT!!!!!
		 * LONG!!
		 * Check if m,n aren't misused
		 * Make sure the output format is right (YES/NO vs Yes/No, newlines vs spaces)
		 * Run with n = 1 or n = 0
		 * Make sure two ints aren't multiplied to get a long

		 *
		 */
		public void solve(InputReader in, PrintWriter out) {
			int n = in.nextInt();

			//ideas: procurar linha que os divide e procurar dentro desses sub-retangulos
			// procurar até ser 1

			//corner cases: se procurar até ser 1 e não verificar se tem 1 do outro lado posso chegar a 1,2...not good
			// tenho que procurar 1,1

			int l = 1;
			int r = n;

			int ans = 0;

			while(r >= l) {
				int mid = (r + l) / 2;
				if(ask(in,out,1,1,mid, n) == 0) {
					l = mid + 1;
				} else {
					ans = mid;
					r = mid - 1;
				}
			}
			//par 1,1
			//FDS ISTO
			if(ans < n && ask(in,out,ans + 1, 1,n,n) == 1) {
				Rectangle r1 = find(in,out,1,1,ans,n,n);
				Rectangle r2 = find(in,out,ans + 1,1,n,n,n);
				System.out.printf("! %d %d %d %d %d %d %d %d\n", r1.x1, r1.y1, r1.x2, r1.y2, r2.x1, r2.y1, r2.x2, r2.y2);
			} else {
				l = 1;
				r = n;

				ans = 0;

				while(r >= l) {
					int mid = (r + l) / 2;
					if(ask(in,out,1,1,n, mid) == 0) {
						l = mid + 1;
					} else {
						ans = mid;
						r = mid - 1;
					}
				}

				Rectangle r1 = find(in,out,1,1,n,ans,n);
				Rectangle r2 = find(in,out,1,ans + 1,n,n,n);
				System.out.printf("! %d %d %d %d %d %d %d %d\n", r1.x1, r1.y1, r1.x2, r1.y2, r2.x1, r2.y1, r2.x2, r2.y2);

			}

		}
		//HASDFDSJGHDFJKSGDFJSGJDFSGJDSFGJF
		//FKING WORK
		public Rectangle find(InputReader in, PrintWriter out,int x1, int y1, int x2, int y2, int n) {
			Rectangle rec = new Rectangle();

			int ansx1 = x1;
			int ansx2 = x2;
			int ansy1 = y1;
			int ansy2 = y2;

			int l = x1;
			int r = x2;

			// quero o minimo v >= x2
			while(r >= l) {
				int mid = (r + l) / 2;

				if(ask(in,out,x1,y1,mid,y2) == 1) {
					ansx2 = mid;
					r = mid - 1;
				} else {
					l = mid + 1;
				}

			}

			//out.printf("x2 = %d", ansx2);

			r = x2;
			l = x1;

			// quero o maximo v <= x1

			while(r >= l) {
				int mid = (r + l) / 2;

				if(ask(in,out,mid,y1,x2,y2) == 1) {
					ansx1 = mid;
					l = mid + 1;
				} else {
					r = mid - 1;
				}

			}

			//out.printf("x1 = %d", ansx1);

			l = y1;
			r = y2;

			// quero o minimo v >= y2
			while(r >= l) {
				int mid = (r + l) / 2;

				if(ask(in,out,x1,y1,x2,mid) == 1) {
					ansy2 = mid;
					r = mid - 1;
				} else {
					l = mid + 1;
				}

			}

			//out.printf("y2 = %d", ansy2);

			r = y2;
			l = y1;

			// quero o maximo v <= y1

			while(r >= l) {
				int mid = (r + l) / 2;

				if(ask(in,out,x1,mid,x2,y2) == 1) {
					ansy1 = mid;
					l = mid + 1;
				} else {
					r = mid - 1;
				}

			}

			//out.printf("y1 = %d", ansy1);

			rec.x1 = ansx1;
			rec.x2 = ansx2;
			rec.y1 = ansy1;
			rec.y2 = ansy2;

			return rec;
		}

		public int ask(InputReader in, PrintWriter out, int x1, int y1, int x2, int y2) {
			System.out.printf("? %d %d %d %d\n",x1,y1,x2,y2);
			System.out.flush();
			return in.nextInt();
		}
	}

	static class InputReader {
		public BufferedReader reader;
		public StringTokenizer tokenizer;

		public InputReader(InputStream stream) {
			reader = new BufferedReader(new InputStreamReader(stream), 32768);
			tokenizer = null;
		}

		public String next() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

		public long nextLong() {
            return Long.parseLong(next());
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }

        public String nextLine() {
            try {
                return reader.readLine();

            } catch (IOException e) {
            }
            return null;
        }

	}
}


import java.io.*;
import java.util.*;

public class B {

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;
	boolean eof;

//	int X1, Y1, X2, Y2;
//	int X3, Y3, X4, Y4;
//	{
//		X1 = 1;
//		Y1 = 2;
//		X2 = 3;
//		Y2 = 4;
//
//		X3 = 5;
//		Y3 = 1;
//		X4 = 5;
//		Y4 = 5;
//	}

	int ask(int x1, int y1, int x2, int y2) throws IOException {
		out.println("? " + x1 + " " + y1 + " " + x2 + " " + y2);
		out.flush();
		return nextInt();
	}

	int inside(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
		return inside(x1, x2, x3, x4) & inside(y1, y2, y3, y4);
	}

	int inside(int x1, int x2, int y1, int y2) {
		return (x1 <= y1 && y2 <= x2) ? 1 : 0;
	}

//	int ask(int x1, int y1, int x2, int y2) throws IOException {
//		return inside(x1, y1, x2, y2, X1, Y1, X2, Y2) + inside(x1, y1, x2, y2, X3, Y3, X4, Y4);
//	}

	int askFlipped(int x1, int y1, int x2, int y2) throws IOException {
		return ask(y1, x1, y2, x2);
	}

	boolean check(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) throws IOException {
		if (x1 > x2 || y1 > y2 || x3 > x4 || y3 > y4) {
			return false;
		}

		if (Math.max(x1, x3) <= Math.min(x2, x4) && Math.max(y1, y3) <= Math.min(y2, y4)) {
			return false;
		}

		return check(x1, y1, x2, y2) && check(x3, y3, x4, y4);
	}

	boolean check(int x1, int y1, int x2, int y2) throws IOException {
		if (ask(x1, y1, x2, y2) != 1) {
			return false;
		}
		if (x1 != x2) {
			if (ask(x1 + 1, y1, x2, y2) != 0 || ask(x1, y1, x2 - 1, y2) != 0) {
				return false;
			}
		}

		if (y1 != y2) {
			if (ask(x1, y1 + 1, x2, y2) != 0 || ask(x1, y1, x2, y2 - 1) != 0) {
				return false;
			}
		}
		return true;
	}

	void solve() throws IOException {
		int n = nextInt();

		int low = 0; // 0
		int high = n; // >0
		while (high - low > 1) {
			int mid = (low + high) >> 1;
			int ret = ask(1, 1, mid, n);
			if (ret == 0) {
				low = mid;
			} else {
				high = mid;
			}
		}

		int minX2 = high;

		low = 0; // <2
		high = n; // 2
		while (high - low > 1) {
			int mid = (low + high) >> 1;
			int ret = ask(1, 1, mid, n);
			if (ret == 2) {
				high = mid;
			} else {
				low = mid;
			}
		}

		int maxX2 = high;

		low = 1; // >0
		high = n + 1; // 0
		while (high - low > 1) {
			int mid = (low + high) >> 1;
			int ret = ask(mid, 1, n, n);
			if (ret == 0) {
				high = mid;
			} else {
				low = mid;
			}
		}

		int maxX1 = low;

		low = 1; // 2
		high = n + 1; // <2
		while (high - low > 1) {
			int mid = (low + high) >> 1;
			int ret = ask(mid, 1, n, n);
			if (ret == 2) {
				low = mid;
			} else {
				high = mid;
			}
		}
		int minX1 = low;

		// / NOW Y

		low = 0; // 0
		high = n; // >0
		while (high - low > 1) {
			int mid = (low + high) >> 1;
			int ret = askFlipped(1, 1, mid, n);
			if (ret == 0) {
				low = mid;
			} else {
				high = mid;
			}
		}

		int minY2 = high;

		low = 0; // <2
		high = n; // 2
		while (high - low > 1) {
			int mid = (low + high) >> 1;
			int ret = askFlipped(1, 1, mid, n);
			if (ret == 2) {
				high = mid;
			} else {
				low = mid;
			}
		}

		int maxY2 = high;

		low = 1; // >0
		high = n + 1; // 0
		while (high - low > 1) {
			int mid = (low + high) >> 1;
			int ret = askFlipped(mid, 1, n, n);
			if (ret == 0) {
				high = mid;
			} else {
				low = mid;
			}
		}

		int maxY1 = low;

		low = 1; // 2
		high = n + 1; // <2
		while (high - low > 1) {
			int mid = (low + high) >> 1;
			int ret = askFlipped(mid, 1, n, n);
			if (ret == 2) {
				low = mid;
			} else {
				high = mid;
			}
		}
		int minY1 = low;

		int[] x1s = { minX1, maxX1 };
		int[] x2s = { minX2, maxX2 };
		int[] y1s = { minY1, maxY1 };
		int[] y2s = { minY2, maxY2 };

		for (int mask = 0; mask < 8; mask++) {
			int x1 = x1s[0];
			int x3 = x1s[1];

			int x2 = x2s[get(mask, 0)];
			int x4 = x2s[get(mask, 0) ^ 1];

			int y1 = y1s[get(mask, 1)];
			int y3 = y1s[get(mask, 1) ^ 1];

			int y2 = y2s[get(mask, 2)];
			int y4 = y2s[get(mask, 2) ^ 1];

			if (check(x1, y1, x2, y2, x3, y3, x4, y4)) {
				out.printf("! %d %d %d %d %d %d %d %d\n", x1, y1, x2, y2, x3, y3, x4, y4);
				out.flush();
				return;
			}
		}
	}

	int get(int mask, int i) {
		return (mask >> i) & 1;
	}

	B() throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		solve();
		out.close();
	}

	public static void main(String[] args) throws IOException {
		new B();
	}

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (Exception e) {
				eof = true;
				return null;
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			eof = true;
			return null;
		}
	}

	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}
}


import java.io.*;
import java.math.*;
import java.util.*;

public class Main {
	static int mod = (int) 1e9 + 7;

	public static void main(String[] args) throws FileNotFoundException {
		FasterScanner s = new FasterScanner();
		int test = 1;
		testloop: while (test-- > 0) {
			int n = s.nextInt();
			int left = 1;
			int right = n;
			int x[][] = new int[2][2];
			int y[][] = new int[2][2];
			while (left < right) {
				int mid = (left + right) / 2;
				query(1, mid, 1, n);
				int ans = s.nextInt();
				if (ans < 2) {
					left = mid + 1;
				} else {
					right = mid;
				}
			}
			x[0][0] = left;
			left = 1;
			right = n;
			while (left < right) {
				int mid = (left + right) / 2;
				query(1, mid, 1, n);
				int ans = s.nextInt();
				if (ans < 1) {
					left = mid + 1;
				} else {
					right = mid;
				}
			}
			x[0][1] = left;
			left = 1;
			right = n;
			while (left < right) {
				int mid = (left + right + 1) / 2;
				query(mid, n, 1, n);
				int ans = s.nextInt();
				if (ans < 2) {
					right = mid - 1;
				} else {
					left = mid;
				}
			}
			x[1][0] = left;
			left = 1;
			right = n;
			while (left < right) {
				int mid = (left + right + 1) / 2;
				query(mid, n, 1, n);
				int ans = s.nextInt();
				if (ans < 1) {
					right = mid - 1;
				} else {
					left = mid;
				}
			}
			x[1][1] = left;
			// System.out.println(Arrays.deepToString(x));

			left = 1;
			right = n;
			while (left < right) {
				int mid = (left + right) / 2;
				query(1, n, 1, mid);
				int ans = s.nextInt();
				if (ans < 2) {
					left = mid + 1;
				} else {
					right = mid;
				}
			}
			y[0][0] = left;
			left = 1;
			right = n;
			while (left < right) {
				int mid = (left + right) / 2;
				query(1, n, 1, mid);
				int ans = s.nextInt();
				if (ans < 1) {
					left = mid + 1;
				} else {
					right = mid;
				}
			}
			y[0][1] = left;
			left = 1;
			right = n;
			while (left < right) {
				int mid = (left + right + 1) / 2;
				query(1, n, mid, n);
				int ans = s.nextInt();
				if (ans < 2) {
					right = mid - 1;
				} else {
					left = mid;
				}
			}
			y[1][0] = left;
			left = 1;
			right = n;
			while (left < right) {
				int mid = (left + right + 1) / 2;
				query(1, n, mid, n);
				int ans = s.nextInt();
				if (ans < 1) {
					right = mid - 1;
				} else {
					left = mid;
				}
			}
			y[1][1] = left;
//			System.out.println(Arrays.deepToString(x));
//			System.out.println(Arrays.deepToString(y));

			int x11 = 0, x12 = 0, y11 = 0, y12 = 0;
			int x21 = 0, x22 = 0, y21 = 0, y22 = 0;
			for (int x1 = 0; x1 < 2; x1++) {
				x11 = x[1][x1];
				x21 = x[1][1 - x1];
				for (int x2 = 0; x2 < 2; x2++) {
					x12 = x[0][x2];
					x22 = x[0][1 - x2];
					if (x11 > x12)
						continue;
					if (x21 > x22)
						continue;
					for (int y1 = 0; y1 < 2; y1++) {
						y11 = y[1][y1];
						y21 = y[1][1 - y1];
						for (int y2 = 0; y2 < 2; y2++) {
							y12 = y[0][y2];
							y22 = y[0][1 - y2];
							if (y11 > y12)
								continue;
							if (y21 > y22)
								continue;
							query(x11, x12, y11, y12);
							int ans1 = s.nextInt();

							query(x21, x22, y21, y22);
							int ans2 = s.nextInt();
							if (ans1 == 1 && ans2 == 1) {
								System.out.println("! " + x11 + " " + y11 + " " + x12 + " " + y12 + " " + x21 + " "
										+ y21 + " " + x22 + " " + y22);
								System.out.flush();
								break testloop;
							}
						}
					}
				}
			}

		}
	}

	public static void query(int x1, int x2, int y1, int y2) {
		 System.out.println("? " + x1 + " " + y1 + " " + x2 + " " + y2);
		 System.out.flush();
//		int count = 0;
//		if (x1 <= 2 && y1 <= 2 && x2 >= 2 && y2 >= 2)
//			count++;
//
//		if (x1 <= 3 && y1 <= 4 && x2 >= 3 && y2 >= 5)
//			count++;
//		System.out.println(count);
	}

	public static void set(int[] t, int i, int value) {
		i += t.length / 2;
		t[i] = value;
		for (; i > 1; i >>= 1)
			t[i >> 1] = Math.max(t[i], t[i ^ 1]);
	}

	// max[a, b]
	public static int max(int[] t, int a, int b) {
		int res = 0;
		for (a += t.length / 2, b += t.length / 2; a <= b; a = (a + 1) >> 1, b = (b - 1) >> 1) {
			if ((a & 1) != 0)
				res = Math.max(res, t[a]);
			if ((b & 1) == 0)
				res = Math.max(res, t[b]);
		}
		return res;
	}

	public static int[] generateDivisorTable(int n) {
		int[] divisor = new int[n + 1];
		for (int i = 1; i <= n; i++)
			divisor[i] = i;
		for (int i = 2; i * i <= n; i++)
			if (divisor[i] == i)
				for (int j = i * i; j <= n; j += i)
					if (divisor[j] == j)
						divisor[j] = i;
		return divisor;
	}

	public static long pow(long x, long n, long mod) {
		long res = 1;
		for (long p = x; n > 0; n >>= 1, p = (p * p) % mod) {
			if ((n & 1) != 0) {
				res = (res * p % mod);
			}
		}
		return res;
	}

	static long gcd(long n1, long n2) {
		long r;
		while (n2 != 0) {
			r = n1 % n2;
			n1 = n2;
			n2 = r;
		}
		return n1;
	}

	static class FasterScanner {
		private byte[] buf = new byte[1024];
		private int curChar;
		private int snumChars;

		public int read() {
			if (snumChars == -1)
				throw new InputMismatchException();
			if (curChar >= snumChars) {
				curChar = 0;
				try {
					snumChars = System.in.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (snumChars <= 0)
					return -1;
			}
			return buf[curChar++];
		}

		public String nextLine() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndOfLine(c));
			return res.toString();
		}

		public String nextString() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public long nextLong() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			int sgn = 1;
			if (c == '-') {
				sgn = -1;
				c = read();
			}
			long res = 0;
			do {
				if (c < '0' || c > '9')
					throw new InputMismatchException();
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			return res * sgn;
		}

		public int nextInt() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			int sgn = 1;
			if (c == '-') {
				sgn = -1;
				c = read();
			}
			int res = 0;
			do {
				if (c < '0' || c > '9')
					throw new InputMismatchException();
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			return res * sgn;
		}

		public int[] nextIntArray(int n) {
			int[] arr = new int[n];
			for (int i = 0; i < n; i++) {
				arr[i] = nextInt();
			}
			return arr;
		}

		public long[] nextLongArray(int n) {
			long[] arr = new long[n];
			for (int i = 0; i < n; i++) {
				arr[i] = nextLong();
			}
			return arr;
		}

		private boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		private boolean isEndOfLine(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}
	}
}


import java.awt.*;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.List;

import static java.lang.Math.max;
import static java.lang.Math.min;

public class B implements Runnable{

    private final static Random rnd = new Random();

    // SOLUTION!!!
    // HACK ME PLEASE IF YOU CAN!!!
    // PLEASE!!!
    // PLEASE!!!
    // PLEASE!!!

    int n;

    private void solve() {
        this.query = 0;

        this.n = readInt();

        int left1 = 0;

        int l = 1, r = n;
        while (l <= r) {
            int m = (l + r) / 2;
            int answer = getAnswer(m, 1, n, n);

            if (answer < 2) {
                r = m - 1;
            } else {
                left1 = m;
                l = m + 1;
            }
        }

        int left2 = left1;

        l = left1 + 1;
        r = n;
        while (l <= r) {
            int m = (l + r) / 2;
            int answer = getAnswer(m, 1, n, n);

            if (answer < 1) {
                r = m - 1;
            } else {
                left2 = m;
                l = m + 1;
            }
        }

        int right2 = n + 1;

        l = 1;
        r = n;
        while (l <= r) {
            int m = (l + r) / 2;
            int answer = getAnswer(1, 1, m, n);

            if (answer < 2) {
                l = m + 1;
            } else {
                right2 = m;
                r = m - 1;
            }
        }

        int right1 = right2;

        l = 1;
        r = right2 - 1;
        while (l <= r) {
            int m = (l + r) / 2;
            int answer = getAnswer(1, 1, m, n);

            if (answer < 1) {
                l = m + 1;
            } else {
                right1 = m;
                r = m - 1;
            }
        }

        int bottom1 = 0;

        l = 1;
        r = n;
        while (l <= r) {
            int m = (l + r) / 2;
            int answer = getAnswer(1, m, n, n);

            if (answer < 2) {
                r = m - 1;
            } else {
                bottom1 = m;
                l = m + 1;
            }
        }

        int bottom2 = bottom1;

        l = bottom1 + 1;
        r = n;
        while (l <= r) {
            int m = (l + r) / 2;
            int answer = getAnswer(1, m, n, n);

            if (answer < 1) {
                r = m - 1;
            } else {
                bottom2 = m;
                l = m + 1;
            }
        }

        int top2 = n + 1;

        l = 1;
        r = n;
        while (l <= r) {
            int m = (l + r) / 2;
            int answer = getAnswer(1, 1, n, m);

            if (answer < 2) {
                l = m + 1;
            } else {
                top2 = m;
                r = m - 1;
            }
        }

        int top1 = top2;

        l = 1;
        r = top2 - 1;
        while (l <= r) {
            int m = (l + r) / 2;
            int answer = getAnswer(1, 1, n, m);

            if (answer < 1) {
                l = m + 1;
            } else {
                top1 = m;
                r = m - 1;
            }
        }

        int ansLeftRightMask = -1, ansBottomTopMask = -1;
        long answerS = 2L * n * n;

        for (int leftRightMask = 0; leftRightMask < 4; ++leftRightMask) {
            int left = (checkBit(leftRightMask, 0) ? left1 : left2);
            int right = (checkBit(leftRightMask, 1) ? right1 : right2);

            for (int bottomTopMask = 0; bottomTopMask < 4; ++bottomTopMask) {
                int bottom = (checkBit(bottomTopMask, 0) ? bottom1 : bottom2);
                int top = (checkBit(bottomTopMask, 1) ? top1 : top2);

                int curTry = getAnswer(left, bottom, right, top);
                if (curTry == 1) {
                    long s = (right - left + 1L) * (top - bottom + 1L);
                    if (s < answerS) {
                        answerS = s;
                        ansLeftRightMask = leftRightMask;
                        ansBottomTopMask = bottomTopMask;
                    }
                }
            }
        }

        int left = (checkBit(ansLeftRightMask, 0) ? left1 : left2);
        int right = (checkBit(ansLeftRightMask, 1) ? right1 : right2);
        int bottom = (checkBit(ansBottomTopMask, 0) ? bottom1 : bottom2);
        int top = (checkBit(ansBottomTopMask, 1) ? top1 : top2);

        printAnswer(left, bottom, right, top,
                left1 + left2 - left, bottom1 + bottom2 - bottom,
                right1 + right2 - right, top1 + top2 - top);
    }

    private void printAnswer(int... values) {
        printQuery("!", values);
    }

    private void printQuery(String sign, int... values) {
        out.print(sign);
        for (int value : values) {
            out.print(" " + value);
        }
        out.println();
        out.flush();
    }

    int query = 0;
    final int MAX_QUERY = 200;

    private int getAnswer(int left, int bottom, int right, int top) {
        if (left < 1 || right > n) {
            while (true);
        }

        if (bottom < 1 || top > n) {
            throw new RuntimeException();
        }

        if (left > right || bottom > top) {
            return 0;
        }

        if (query == MAX_QUERY) {
            throw new RuntimeException();
        }

        ++query;

        printQuery("?",  left, bottom, right, top);

        int answer = readInt();
        return answer;
    }

    /////////////////////////////////////////////////////////////////////

    private final static boolean FIRST_INPUT_STRING = false;
    private final static boolean MULTIPLE_TESTS = true;
    private final static boolean INTERACTIVE = true;
    private final boolean ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null;

    private final static int MAX_STACK_SIZE = 128;

    private final static boolean OPTIMIZE_READ_NUMBERS = false;

    /////////////////////////////////////////////////////////////////////

    public void run(){
        try{
            timeInit();
            Locale.setDefault(Locale.US);

            init();

            if (ONLINE_JUDGE) {
                solve();
            } else {
                do {
                    try {
                        timeInit();
                        solve();
                        time();

                        out.println();
                    } catch (NumberFormatException e) {
                        break;
                    } catch (NullPointerException e) {
                        if (FIRST_INPUT_STRING) break;
                        else throw e;
                    }
                } while (MULTIPLE_TESTS);
            }

            out.close();
            time();
        }catch (Exception e){
            e.printStackTrace(System.err);
            System.exit(-1);
        }
    }

    /////////////////////////////////////////////////////////////////////

    private BufferedReader in;
    private OutputWriter out;
    private StringTokenizer tok = new StringTokenizer("");

    public static void main(String[] args){
        new Thread(null, new B(), "", MAX_STACK_SIZE * (1L << 20)).start();
    }

    /////////////////////////////////////////////////////////////////////

    private void init() throws FileNotFoundException{
        Locale.setDefault(Locale.US);

        if (INTERACTIVE || ONLINE_JUDGE){
            in = new BufferedReader(new InputStreamReader(System.in));
            out = new OutputWriter(System.out);
        }else{
            in = new BufferedReader(new FileReader("input.txt"));
            out = new OutputWriter("output.txt");
        }
    }

    ////////////////////////////////////////////////////////////////

    private long timeBegin;

    private void timeInit() {
        this.timeBegin = System.currentTimeMillis();
    }

    private void time(){
        long timeEnd = System.currentTimeMillis();
        System.err.println("Time = " + (timeEnd - timeBegin));
    }

    private void debug(Object... objects){
        if (ONLINE_JUDGE){
            for (Object o: objects){
                System.err.println(o.toString());
            }
        }
    }

    /////////////////////////////////////////////////////////////////////

    private String delim = " ";

    private String readLine() {
        try {
            return in.readLine();
        } catch (IOException e) {
            throw new RuntimeIOException(e);
        }
    }

    private String readString() {
        try {
            while(!tok.hasMoreTokens()){
                tok = new StringTokenizer(readLine());
            }

            return tok.nextToken(delim);
        } catch (NullPointerException e) {
            return null;
        }
    }

    /////////////////////////////////////////////////////////////////

    private final char NOT_A_SYMBOL = '\0';

    private char readChar() {
        try {
            int intValue = in.read();

            if (intValue == -1){
                return NOT_A_SYMBOL;
            }

            return (char) intValue;
        } catch (IOException e) {
            throw new RuntimeIOException(e);
        }
    }

    private char[] readCharArray() {
        return readLine().toCharArray();
    }

    private char[][] readCharField(int rowsCount) {
        char[][] field = new char[rowsCount][];
        for (int row = 0; row < rowsCount; ++row) {
            field[row] = readCharArray();
        }

        return field;
    }

    /////////////////////////////////////////////////////////////////

    private long optimizedReadLong() {
        long result = 0;
        boolean started = false;
        while (true) {
            try {
                int j = in.read();
                if (-1 == j) {
                    if (started) return result;
                    throw new NumberFormatException();
                }

                if ('0' <= j && j <= '9') {
                    result = result * 10 + j - '0';
                    started = true;
                } else if (started) {
                    return result;
                }
            } catch (IOException e) {
                throw new RuntimeIOException(e);
            }
        }
    }

    private int readInt() {

        if (!OPTIMIZE_READ_NUMBERS) {
            return Integer.parseInt(readString());
        } else {
            return (int) optimizedReadLong();
        }
    }

    private int[] readIntArray(int size) {
        int[] array = new int[size];

        for (int index = 0; index < size; ++index){
            array[index] = readInt();
        }

        return array;
    }

    private int[] readSortedIntArray(int size) {
        Integer[] array = new Integer[size];

        for (int index = 0; index < size; ++index) {
            array[index] = readInt();
        }
        Arrays.sort(array);

        int[] sortedArray = new int[size];
        for (int index = 0; index < size; ++index) {
            sortedArray[index] = array[index];
        }

        return sortedArray;
    }

    private int[] readIntArrayWithDecrease(int size) {
        int[] array = readIntArray(size);

        for (int i = 0; i < size; ++i) {
            array[i]--;
        }

        return array;
    }

    ///////////////////////////////////////////////////////////////////

    private int[][] readIntMatrix(int rowsCount, int columnsCount) {
        int[][] matrix = new int[rowsCount][];

        for (int rowIndex = 0; rowIndex < rowsCount; ++rowIndex) {
            matrix[rowIndex] = readIntArray(columnsCount);
        }

        return matrix;
    }

    private int[][] readIntMatrixWithDecrease(int rowsCount, int columnsCount) {
        int[][] matrix = new int[rowsCount][];

        for (int rowIndex = 0; rowIndex < rowsCount; ++rowIndex) {
            matrix[rowIndex] = readIntArrayWithDecrease(columnsCount);
        }

        return matrix;
    }

    ///////////////////////////////////////////////////////////////////

    private long readLong() {
        if (!OPTIMIZE_READ_NUMBERS) {
            return Long.parseLong(readString());
        } else {
            return optimizedReadLong();
        }
    }

    private long[] readLongArray(int size) {
        long[] array = new long[size];

        for (int index = 0; index < size; ++index){
            array[index] = readLong();
        }

        return array;
    }

    ////////////////////////////////////////////////////////////////////

    private double readDouble() {
        return Double.parseDouble(readString());
    }

    private double[] readDoubleArray(int size) {
        double[] array = new double[size];

        for (int index = 0; index < size; ++index){
            array[index] = readDouble();
        }

        return array;
    }

    ////////////////////////////////////////////////////////////////////

    private BigInteger readBigInteger() {
        return new BigInteger(readString());
    }

    private BigDecimal readBigDecimal() {
        return new BigDecimal(readString());
    }

    /////////////////////////////////////////////////////////////////////

    private Point readPoint() {
        int x = readInt();
        int y = readInt();
        return new Point(x, y);
    }

    private Point[] readPointArray(int size) {
        Point[] array = new Point[size];

        for (int index = 0; index < size; ++index){
            array[index] = readPoint();
        }

        return array;
    }

    /////////////////////////////////////////////////////////////////////

    private List<Integer>[] readGraph(int vertexNumber, int edgeNumber) {
        @SuppressWarnings("unchecked")
        List<Integer>[] graph = new List[vertexNumber];

        for (int index = 0; index < vertexNumber; ++index){
            graph[index] = new ArrayList<Integer>();
        }

        while (edgeNumber-- > 0){
            int from = readInt() - 1;
            int to = readInt() - 1;

            graph[from].add(to);
            graph[to].add(from);
        }

        return graph;
    }

    /////////////////////////////////////////////////////////////////////

    private static class IntIndexPair {

        static Comparator<IntIndexPair> increaseComparator = new Comparator<B.IntIndexPair>() {

            @Override
            public int compare(B.IntIndexPair indexPair1, B.IntIndexPair indexPair2) {
                int value1 = indexPair1.value;
                int value2 = indexPair2.value;

                if (value1 != value2) return value1 - value2;

                int index1 = indexPair1.index;
                int index2 = indexPair2.index;

                return index1 - index2;
            }
        };

        static Comparator<IntIndexPair> decreaseComparator = new Comparator<B.IntIndexPair>() {

            @Override
            public int compare(B.IntIndexPair indexPair1, B.IntIndexPair indexPair2) {
                int value1 = indexPair1.value;
                int value2 = indexPair2.value;

                if (value1 != value2) return -(value1 - value2);

                int index1 = indexPair1.index;
                int index2 = indexPair2.index;

                return index1 - index2;
            }
        };

        int value, index;

        IntIndexPair(int value, int index) {
            super();
            this.value = value;
            this.index = index;
        }

        int getRealIndex() {
            return index + 1;
        }
    }

    private IntIndexPair[] readIntIndexArray(int size) {
        IntIndexPair[] array = new IntIndexPair[size];

        for (int index = 0; index < size; ++index) {
            array[index] = new IntIndexPair(readInt(), index);
        }

        return array;
    }

    /////////////////////////////////////////////////////////////////////

    private static class OutputWriter extends PrintWriter {

        final int DEFAULT_PRECISION = 12;

        private int precision;
        private String format, formatWithSpace;

        {
            precision = DEFAULT_PRECISION;

            format = createFormat(precision);
            formatWithSpace = format + " ";
        }

        OutputWriter(OutputStream out) {
            super(out);
        }

        OutputWriter(String fileName) throws FileNotFoundException {
            super(fileName);
        }

        int getPrecision() {
            return precision;
        }

        void setPrecision(int precision) {
            precision = max(0, precision);
            this.precision = precision;

            format = createFormat(precision);
            formatWithSpace = format + " ";
        }

        String createFormat(int precision){
            return "%." + precision + "f";
        }

        @Override
        public void print(double d){
            printf(format, d);
        }

        void printWithSpace(double d){
            printf(formatWithSpace, d);
        }

        void printAll(double...d){
            for (int i = 0; i < d.length - 1; ++i){
                printWithSpace(d[i]);
            }

            print(d[d.length - 1]);
        }

        @Override
        public void println(double d){
            printlnAll(d);
        }

        void printlnAll(double... d){
            printAll(d);
            println();
        }
    }

    /////////////////////////////////////////////////////////////////////

    private static class RuntimeIOException extends RuntimeException {

        /**
         *
         */
        private static final long serialVersionUID = -6463830523020118289L;

        RuntimeIOException(Throwable cause) {
            super(cause);
        }
    }

    /////////////////////////////////////////////////////////////////////
    //////////////// Some useful constants and functions ////////////////
    /////////////////////////////////////////////////////////////////////

    private static final int[][] steps = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    private static final int[][] steps8 = {
            {-1, 0}, {1, 0}, {0, -1}, {0, 1},
            {-1, -1}, {1, 1}, {1, -1}, {-1, 1}
    };

    private static boolean checkCell(int row, int rowsCount, int column, int columnsCount) {
        return checkIndex(row, rowsCount) && checkIndex(column, columnsCount);
    }

    private static boolean checkIndex(int index, int lim){
        return (0 <= index && index < lim);
    }

    /////////////////////////////////////////////////////////////////////

    private static boolean checkBit(int mask, int bit){
        return (mask & (1 << bit)) != 0;
    }
    private static boolean checkBit(long mask, int bit){
        return (mask & (1L << bit)) != 0;
    }

    /////////////////////////////////////////////////////////////////////

    private static long getSum(int[] array) {
        long sum = 0;
        for (int value: array) {
            sum += value;
        }

        return sum;
    }

    private static Point getMinMax(int[] array) {
        int min = array[0];
        int max = array[0];

        for (int index = 0, size = array.length; index < size; ++index, ++index) {
            int value = array[index];

            if (index == size - 1) {
                min = min(min, value);
                max = max(max, value);
            } else {
                int otherValue = array[index + 1];

                if (value <= otherValue) {
                    min = min(min, value);
                    max = max(max, otherValue);
                } else {
                    min = min(min, otherValue);
                    max = max(max, value);
                }
            }
        }

        return new Point(min, max);
    }

    /////////////////////////////////////////////////////////////////////

    private static int[] getPrimes(int n) {
        boolean[] used = new boolean[n];
        used[0] = used[1] = true;

        int size = 0;
        for (int i = 2; i < n; ++i) {
            if (!used[i]) {
                ++size;
                for (int j = 2 * i; j < n; j += i) {
                    used[j] = true;
                }
            }
        }

        int[] primes = new int[size];
        for (int i = 0, cur = 0; i < n; ++i) {
            if (!used[i]) {
                primes[cur++] = i;
            }
        }

        return primes;
    }

    /////////////////////////////////////////////////////////////////////

    private static long lcm(long a, long b) {
        return a / gcd(a, b) * b;
    }

    private static long gcd(long a, long b) {
        return (a == 0 ? b : gcd(b % a, a));
    }

    /////////////////////////////////////////////////////////////////////

    private static class IdMap<KeyType> extends HashMap<KeyType, Integer> {

        /**
         *
         */
        private static final long serialVersionUID = -3793737771950984481L;

        public IdMap() {
            super();
        }

        int getId(KeyType key) {
            Integer id = super.get(key);
            if (id == null) {
                super.put(key, id = size());
            }

            return id;
        }
    }
}


import java.io.*;
import java.util.*;

public class Template implements Runnable {

    BufferedReader in;
    PrintWriter out;
    StringTokenizer tok = new StringTokenizer("");

    void init() throws FileNotFoundException {
        in = new BufferedReader(new InputStreamReader(System.in));
        out = new PrintWriter(System.out);
    }

    String readString() throws IOException {
        while (!tok.hasMoreTokens()) {
            try {
                tok = new StringTokenizer(in.readLine(), " :");
            } catch (Exception e) {
                return null;
            }
        }
        return tok.nextToken();
    }

    int readInt() throws IOException {
        return Integer.parseInt(readString());
    }

    int[] readIntArray(int size) throws IOException {
        int[] res = new int[size];
        for (int i = 0; i < size; i++) {
            res[i] = readInt();
        }
        return res;
    }

    long readLong() throws IOException {
        return Long.parseLong(readString());
    }

    double readDouble() throws IOException {
        return Double.parseDouble(readString());
    }

    <T> List<T>[] createGraphList(int size) {
        List<T>[] list = new List[size];
        for (int i = 0; i < size; i++) {
            list[i] = new ArrayList<>();
        }
        return list;
    }

    public static void main(String[] args) {
        new Thread(null, new Template(), "", 1l * 200 * 1024 * 1024).start();
    }

    long timeBegin, timeEnd;

    void time() {
        timeEnd = System.currentTimeMillis();
        System.err.println("Time = " + (timeEnd - timeBegin));
    }

    long memoryTotal, memoryFree;

    void memory() {
        memoryFree = Runtime.getRuntime().freeMemory();
        System.err.println("Memory = " + ((memoryTotal - memoryFree) >> 10)
                + " KB");
    }

    public void run() {
        try {
            timeBegin = System.currentTimeMillis();
            memoryTotal = Runtime.getRuntime().freeMemory();
            init();
            solve();
            out.close();
            if (System.getProperty("ONLINE_JUDGE") == null) {
                time();
                memory();
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }

    int fx = -1;
    int sx = -1;
    int fy = -1;
    int sy = -1;

    int query(int x1, int y1, int x2, int y2) throws IOException {
        out.println("? " + x1 + " " + y1 + " " + x2 + " " + y2);
        out.flush();
        int res = readInt();
        if (fx >= x1 && sx <= x2 && fy >= y1 && sy <= y2) res--;
        return res;
    }

    int[] bs(int n) throws IOException {
        int l = 1;
        int r = n;

        int lx = 0, rx = 0, ly = 0, ry = 0;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (query(1, 1, mid, n) > 0) {
                rx = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }

        l = 1;
        r = rx;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (query(mid, 1, rx, n) > 0) {
                lx = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }

        l = 1;
        r = n;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (query(lx, mid, rx, n) > 0) {
                ly = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }

        l = ly;
        r = n;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (query(lx, ly, rx, mid) > 0) {
                ry = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        fx = lx;
        sx = rx;
        fy = ly;
        sy = ry;
        return new int[] {lx, ly, rx, ry};
    }

    void solve() throws IOException {
        int n = readInt();
        int[] a = bs(n);
        int[] b = bs(n);

        out.print("! ");
        for (int i : a) out.print(i + " ");
        for (int i : b) out.print(i + " ");
    }

}


import java.util.*;

public class B {

	public static void main(String[] args) {
		Scanner qwe = new Scanner(System.in);

		int n = qwe.nextInt();

		//! x11 y11 x12 y12 x21 y21 x22 y22"

		int x11 = bins(true,1,2,n,qwe,true);
		int y11 = bins(true,1,2,n,qwe,false);
		int x12 = bins(false,0,1,n,qwe,true);
		int y12 = bins(false,0,1,n,qwe,false);
		int x21 = bins(true,0,1,n,qwe,true);
		int y21 = bins(true,0,1,n,qwe,false);
		int x22 = bins(false,1,2,n,qwe,true);
		int y22 = bins(false,1,2,n,qwe,false);

		int[] xsl = {x11,x21};
		int[] xsr = {x12,x22};
		int[] ysl = {y11,y21};
		int[] ysr = {y12,y22};

		int[] ans = new int[8];

		for(int xpl = 0; xpl < 2; xpl++){
			for(int xpr = 0; xpr < 2; xpr++)
				for(int ypl = 0; ypl < 2; ypl++){
					for(int ypr = 0; ypr < 2; ypr++){

						if(xsl[xpl] <= xsr[xpr] && xsl[1-xpl] <= xsr[1-xpr] && ysl[ypl] <= ysr[ypr] && ysl[1-ypl] <= ysr[1-ypr]){
							System.out.printf("? %d %d %d %d",xsl[xpl],ysl[ypl],xsr[xpr],ysr[ypr]);
							System.out.println();
							System.out.flush();
							int response1 = qwe.nextInt();

							System.out.printf("? %d %d %d %d",xsl[1-xpl],ysl[1-ypl],xsr[1-xpr],ysr[1-ypr]);
							System.out.println();
							System.out.flush();
							int response2 = qwe.nextInt();

							if(response1 == 1 && response2 == 1){
								ans = new int[]{xsl[xpl],ysl[ypl],xsr[xpr],ysr[ypr],xsl[1-xpl],ysl[1-ypl],xsr[1-xpr],ysr[1-ypr]};
							}

						}

					}

			}
		}

		System.out.printf("! %d %d %d %d %d %d %d %d",ans[0],ans[1],ans[2],ans[3],ans[4],ans[5],ans[6],ans[7]);
		System.out.println();
		System.out.flush();

		qwe.close();
	}

	static int bins(boolean leftbound, int small, int big, int n, Scanner qwe, boolean isx){

		int min = 0;
		int max = n;

		if(leftbound){
			min++;
			max++;
		}

		int y1 = 1;
		int y2 = n;
		int x1 = 1;
		int x2 = n;
		//"? x1 y1 x2 y2"
		while(min+1 < max){

			int med = (min+max)/2;
			if(isx){
				if(!leftbound) x2 = med;
				else x1 = med;
			}
			else{
				if(!leftbound) y2 = med;
				else y1 = med;
			}

			System.out.printf("? %d %d %d %d",x1,y1,x2,y2);
			System.out.println();
			System.out.flush();

			int response = qwe.nextInt();
			if(leftbound){
				if(response >= big) min = med;
				else max= med;
			}
			else{
				if(response < big){
					min = med;
				}
				else{
					max = med;
				}
			}
		}

		if(leftbound) max--;

		return max;

	}

}


import java.io.*;
import java.util.*;
import java.util.function.IntPredicate;

import static java.lang.Math.*;

public class Main {
    FastScanner in;
    PrintWriter out;

    static final String FILE = "";

    public static final int TEST = 0;

    class Interact {
        Rect a, b;

        public Interact(int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22) {
            a = new Rect(x11, y11, x12, y12);
            b = new Rect(x21, y21, x22, y22);
        }

        int query(int x1, int y1, int x2, int y2) {
            int ans = 0;
            if (x1 <= a.x1 && x2 >= a.x2 && y1 <= a.y1 && y2 >= a.y2)
                ans++;
            if (x1 <= b.x1 && x2 >= b.x2 && y1 <= b.y1 && y2 >= b.y2)
                ans++;
            return ans;
        }
    }
    Interact interact;

    class Rect {
        int x1, y1, x2, y2;

        public Rect() {
        }

        public Rect(int x1, int y1, int x2, int y2) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }

        @Override
        public String toString() {
            return x1 + " " + y1 + " " + x2 + " " + y2;
        }
    }

    int calls;

    int query(int x1, int y1, int x2, int y2, Rect rect) {
        calls++;
        if (calls >= 190)
            throw new RuntimeException();

        if (TEST == 0) {
            out.println("? " + x1 + " " + y1 + " " + x2 + " " + y2);
            out.flush();
            int ans = in.nextInt();
            if (x1 <= rect.x1 && x2 >= rect.x2 && y1 <= rect.y1 && y2 >= rect.y2)
                ans--;
            return ans;
        } else {
            int ans = interact.query(x1, y1, x2, y2);
            if (x1 <= rect.x1 && x2 >= rect.x2 && y1 <= rect.y1 && y2 >= rect.y2)
                ans--;
            return ans;
        }
    }

    static int binarySearchFirstTrue(IntPredicate predicate, int fromInclusive, int toInclusive) {
        int a = fromInclusive, b = toInclusive;
        while (a != b) {
            int la = a, lb = b;
            int mid = (a + b) / 2;
            if (predicate.test(mid))
                b = mid;
            else
                a = mid;
            if (la == a && lb == b) {
                if (predicate.test(a))
                    b = a;
                else
                    a = b;
            }
        }
        return a;
    }

    static int binarySearchLastTrue(IntPredicate predicate, int fromInclusive, int toInclusive) {
        int a = fromInclusive, b = toInclusive;
        while (a != b) {
            int la = a, lb = b;
            int mid = (a + b) / 2;
            if (predicate.test(mid))
                a = mid;
            else
                b = mid;
            if (la == a && lb == b) {
                if (predicate.test(b))
                    a = b;
                else
                    b = a;
            }
        }
        return a;
    }

    static Rect rect;

    void test() {
        Random random = new Random(13);
        for (int test = 0; test < 1000; test++) {

        }
    }

    void solve() {
        rect = new Rect();

        if (TEST == 0) {
            int n = in.nextInt();
            List<Rect> list = new ArrayList<>();
            for (int r = 0; r < 2; r++) {
                int x2 = binarySearchFirstTrue(i -> query(1, 1, i, n, rect) >= 1, 1, n);
                int x1 = binarySearchLastTrue(i -> query(i, 1, x2, n, rect) >= 1, 1, x2);
                int y2 = binarySearchFirstTrue(i -> query(x1, 1, x2, i, rect) >= 1, 1, n);
                int y1 = binarySearchLastTrue(i -> query(x1, i, x2, y2, rect) >= 1, 1, y2);
                rect = new Rect(x1, y1, x2, y2);
                list.add(rect);
            }
            out.println("! " + list.get(0) + " " + list.get(1));
            out.flush();
        } else {
            int n = in.nextInt();
            int x11 = in.nextInt(), y11 = in.nextInt(), x12 = in.nextInt(), y12 = in.nextInt();
            int x21 = in.nextInt(), y21 = in.nextInt(), x22 = in.nextInt(), y22 = in.nextInt();
            interact = new Interact(x11, y11, x12, y12, x21, y21, x22, y22);
            List<Rect> list = new ArrayList<>();
            for (int r = 0; r < 2; r++) {
                int x2 = binarySearchFirstTrue(i -> query(1, 1, i, n, rect) >= 1, 1, n);
                int x1 = binarySearchLastTrue(i -> query(i, 1, x2, n, rect) >= 1, 1, x2);
                int y2 = binarySearchFirstTrue(i -> query(x1, 1, x2, i, rect) >= 1, 1, n);
                int y1 = binarySearchLastTrue(i -> query(x1, i, x2, y2, rect) >= 1, 1, y2);
                rect = new Rect(x1, y1, x2, y2);
                list.add(rect);
            }
            out.println("! " + list.get(0) + " " + list.get(1));
            out.flush();
        }
    }

    public void run() {
        if (FILE.equals("")) {
            in = new FastScanner(System.in);
            out = new PrintWriter(System.out);
        } else {
            try {
                in = new FastScanner(new FileInputStream(FILE +
                        ".in"));
                out = new PrintWriter(new FileOutputStream(FILE +
                        ".out"));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        solve();
        out.close();
    }

    public static void main(String[] args) {
        (new Main()).run();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(InputStream is) {
            br = new BufferedReader(new InputStreamReader(is));
        }

        public String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        public String nextLine() {
            st = null;
            try {
                return br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }

        public float nextFloat() {
            return Float.parseFloat(next());
        }
    }

}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.PrintStream;
import java.io.BufferedWriter;
import java.util.Random;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Jialin Ouyang (Jialin.Ouyang@gmail.com)
 */
public class Main {
  public static void main(String[] args) {
    InputStream inputStream = System.in;
    OutputStream outputStream = System.out;
    QuickScanner in = new QuickScanner(inputStream);
    QuickWriter out = new QuickWriter(outputStream);
    TaskB solver = new TaskB();
    solver.solve(1, in, out);
    out.close();
  }

  static class TaskB {
    static boolean LOCAL = false;
    static int TEST_CASE = 10000;
    QuickScanner in;
    QuickWriter out;
    int n;
    Server server;

    public void solve(int testNumber, QuickScanner in, QuickWriter out) {
      this.in = in;
      this.out = out;
      n = LOCAL ? 1 << 16 : in.nextInt();
      server = new Server();
      for (int remCases = LOCAL ? TEST_CASE : 1; remCases > 0; --remCases) {
        server.init(n);
        Rect[] rects = split(0);
        if (rects == null) {
          rects = split(1);
        }
        rects[0] = shrink(rects[0]);
        rects[1] = shrink(rects[1]);
        server.answer(rects[0], rects[1]);
      }
    }

    Rect[] split(int dim) {
      int lower = 1, upper = n - 1, res = 0;
      Rect fullRect = new Rect(1, 1, n, n);
      while (lower <= upper) {
        int medium = (lower + upper) >> 1;
        if (server.ask(fullRect.update(1, dim, medium)) == 0) {
          res = medium;
          lower = medium + 1;
        } else {
          upper = medium - 1;
        }
      }
      Rect[] rects = new Rect[]{
          fullRect.update(1, dim, res + 1),
          fullRect.update(0, dim, res + 2)};
      return server.ask(rects[0]) == 1
          && server.ask(rects[1]) == 1
          ? rects : null;
    }

    Rect shrink(Rect rect) {
      rect = shrink(rect, 0);
      rect = shrink(rect, 1);
      return rect;
    }

    Rect shrink(Rect rect, int dim) {
      int lower, upper, res;
      // lower
      lower = rect.getValue(0, dim) + 1;
      upper = rect.getValue(1, dim);
      res = lower - 1;
      while (lower <= upper) {
        int medium = (lower + upper) >> 1;
        if (server.ask(rect.update(0, dim, medium)) == 1) {
          res = medium;
          lower = medium + 1;
        } else {
          upper = medium - 1;
        }
      }
      rect = rect.update(0, dim, res);
      // upper
      lower = rect.getValue(0, dim);
      upper = rect.getValue(1, dim) - 1;
      res = upper + 1;
      while (lower <= upper) {
        int medium = (lower + upper) >> 1;
        if (server.ask(rect.update(1, dim, medium)) == 1) {
          res = medium;
          upper = medium - 1;
        } else {
          lower = medium + 1;
        }
      }
      return rect.update(1, dim, res);
    }

    class Server {
      Rect rect1;
      Rect rect2;

      Server() {
        rect1 = new Rect();
        rect2 = new Rect();
      }

      void init(int n) {
        if (LOCAL) {
          do {
            rect1.initRandom(n);
            rect2.initRandom(n);
          } while (!rect1.valid(rect2));
          //rect1 = new Rect(2, 2, 2, 2);
          //rect2 = new Rect(3, 4, 3, 5);
        }
      }

      int ask(Rect rect) {
        out.print("? ");
        rect.print();
        out.println();
        out.flush();
        if (LOCAL) {
          return (rect1.in(rect) ? 1 : 0)
              + (rect2.in(rect) ? 1 : 0);
        } else {
          return in.nextInt();
        }
      }

      void answer(Rect rect1, Rect rect2) {
        out.print("! ");
        rect1.print();
        out.print(' ');
        rect2.print();
        out.println();
        out.flush();
        if (LOCAL) {
          if ((rect1.equals(this.rect1) && rect2.equals(this.rect2))
              || (rect2.equals(this.rect1) && rect1.equals(this.rect2))) {
            System.out.println("AC!");
          } else {
            System.out.println("WA!");
            throw new IllegalArgumentException();
          }
        }
      }

    }

    class Rect {
      final Random random = new Random();
      int x1;
      int y1;
      int x2;
      int y2;

      Rect() {
      }

      Rect(int x1, int y1, int x2, int y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
      }

      void initRandom(int n) {
        x1 = random.nextInt(n);
        x2 = random.nextInt(n - x1) + x1 + 1;
        ++x1;
        y1 = random.nextInt(n);
        y2 = random.nextInt(n - y1) + y1 + 1;
        ++y1;
      }

      int getValue(int idx1, int idx2) {
        switch ((idx1 << 1) | idx2) {
          case 0:
            return x1;
          case 1:
            return y1;
          case 2:
            return x2;
          case 3:
            return y2;
        }
        throw new IllegalArgumentException();
      }

      Rect update(int idx1, int idx2, int value) {
        switch ((idx1 << 1) | idx2) {
          case 0:
            return new Rect(value, y1, x2, y2);
          case 1:
            return new Rect(x1, value, x2, y2);
          case 2:
            return new Rect(x1, y1, value, y2);
          case 3:
            return new Rect(x1, y1, x2, value);
        }
        return null;
      }

      boolean valid(Rect o) {
        if (x2 < o.x1) return true;
        if (y2 < o.y1) return true;
        if (o.x2 < x1) return true;
        if (o.y2 < y1) return true;
        return false;
      }

      boolean in(Rect o) {
        return o.x1 <= x1 && x2 <= o.x2
            && o.y1 <= y1 && y2 <= o.y2;
      }

      boolean equals(Rect o) {
        return x1 == o.x1 && y1 == o.y1
            && x2 == o.x2 && y2 == o.y2;
      }

      void print() {
        out.printf("%d %d %d %d", x1, y1, x2, y2);
      }

    }

  }

  static class QuickScanner {
    private static final int BUFFER_SIZE = 1024;
    private InputStream stream;
    private byte[] buffer;
    private int currentPostion;
    private int numberOfChars;

    public QuickScanner(InputStream stream) {
      this.stream = stream;
      this.buffer = new byte[BUFFER_SIZE];
      this.currentPostion = 0;
      this.numberOfChars = 0;
    }

    public int nextInt() {
      int c = nextNonSpaceChar();
      boolean positive = true;
      if (c == '-') {
        positive = false;
        c = nextChar();
      }
      int res = 0;
      do {
        if (c < '0' || '9' < c) throw new RuntimeException();
        res = res * 10 + c - '0';
        c = nextChar();
      } while (!isSpaceChar(c));
      return positive ? res : -res;
    }

    public int nextNonSpaceChar() {
      int res = nextChar();
      for (; isSpaceChar(res) || res < 0; res = nextChar()) ;
      return res;
    }

    public int nextChar() {
      if (numberOfChars == -1) {
        throw new RuntimeException();
      }
      if (currentPostion >= numberOfChars) {
        currentPostion = 0;
        try {
          numberOfChars = stream.read(buffer);
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
        if (numberOfChars <= 0) {
          return -1;
        }
      }
      return buffer[currentPostion++];
    }

    public boolean isSpaceChar(int c) {
      return c == ' '
          || c == '\n'
          || c == '\r'
          || c == '\t'
          || c < 0;
    }

  }

  static class QuickWriter {
    private final PrintWriter writer;

    public QuickWriter(OutputStream outputStream) {
      this.writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
    }

    public QuickWriter(Writer writer) {
      this.writer = new PrintWriter(writer);
    }

    public void print(Object... objects) {
      for (int i = 0; i < objects.length; ++i) {
        if (i > 0) {
          writer.print(' ');
        }
        writer.print(objects[i]);
      }
    }

    public void println(Object... objects) {
      print(objects);
      writer.print('\n');
    }

    public void printf(String format, Object... objects) {
      writer.printf(format, objects);
    }

    public void close() {
      writer.close();
    }

    public void flush() {
      writer.flush();
    }

  }
}


//make sure to make new file!
import java.io.*;
import java.util.*;

public class B713{

   public static BufferedReader f;
   public static PrintWriter out;

   public static void main(String[] args)throws IOException{
      f = new BufferedReader(new InputStreamReader(System.in));
      out = new PrintWriter(System.out);

      int n = Integer.parseInt(f.readLine());

      int l;
      int r;
      int mid;
      int ans;

      l = 1;
      r = n;
      ans = -1;
      //see if you can draw vertical line between them

      while(l <= r){
         mid = l + (r-l)/2;
         if(mid == n) break;

         int il = query(1,1,n,mid);
         int ir = query(1,mid+1,n,n);

         if(il == 1 && ir == 1){
            ans = mid;
            break;
         }

         if(il > ir){
            r = mid-1;
         } else {
            l = mid+1;
         }
      }

      int x11 = -1;
      int y11 = -1;
      int x12 = -1;
      int y12 = -1;
      int x21 = -1;
      int y21 = -1;
      int x22 = -1;
      int y22 = -1;
      if(ans == -1){
         //find horizontal line
         l = 1;
         r = n;
         ans = -1;

         while(l <= r){
            mid = l + (r-l)/2;

            int il = query(1,1,mid,n);
            int ir = query(mid+1,1,n,n);

            if(il == 1 && ir == 1){
               ans = mid;
               break;
            }

            if(il > ir){
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         int bar = ans;

                  //find top line of top block
         l = 1;
         r = bar;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(mid,1,bar,n);
            if(i == 1){
               ans = mid;
               l = mid+1;
            } else {
               r = mid-1;
            }
         }

         x11 = ans;

         //find bottom line of top block
         l = 1;
         r = bar;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,1,mid,n);
            if(i == 1){
               ans = mid;
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         x12 = ans;

         //find left of top block

         l = 1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,mid,bar,n);

            if(i == 1){
               ans = mid;
               l = mid+1;
            } else {
               r = mid-1;
            }
         }

         y11 = ans;

         //find right of top block
         l = 1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,1,bar,mid);

            if(i == 1){
               ans = mid;
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         y12 = ans;

         //find top line of bottom block
         l = bar+1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(mid,1,n,n);
            if(i == 1){
               ans = mid;
               l = mid+1;
            } else {
               r = mid-1;
            }
         }

         x21 = ans;

         //find bottom line of bottom block
         l = bar+1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(bar+1,1,mid,n);
            if(i == 1){
               ans = mid;
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         x22 = ans;

         //find left of bottom block

         l = 1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(bar+1,mid,n,n);

            if(i == 1){
               ans = mid;
               l = mid+1;
            } else {
               r = mid-1;
            }
         }

         y21 = ans;

         //find right of bottom block
         l = 1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(bar+1,1,n,mid);

            if(i == 1){
               ans = mid;
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         y22 = ans;

      } else {
         //ans is the vertical line between
         int bar = ans;
         //find left line of left block
         l = 1;
         r = bar;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,mid,n,bar);
            if(i == 1){
               ans = mid;
               l = mid+1;
            } else {
               r = mid-1;
            }
         }

         y11 = ans;

         //find right line of left block
         l = 1;
         r = bar;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,1,n,mid);
            if(i == 1){
               ans = mid;
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         y12 = ans;

         //find top of left block

         l = 1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(mid,1,n,bar);

            if(i == 1){
               ans = mid;
               l = mid+1;
            } else {
               r = mid-1;
            }
         }

         x11 = ans;

         //find bottom of left block
         l = 1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,1,mid,bar);

            if(i == 1){
               ans = mid;
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         x12 = ans;

         //find left line of right block
         l = bar+1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,mid,n,n);
            if(i == 1){
               ans = mid;
               l = mid+1;
            } else {
               r = mid-1;
            }
         }

         y21 = ans;

         //find right line of right block
         l = bar+1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,bar+1,n,mid);
            if(i == 1){
               ans = mid;
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         y22 = ans;

         //find top of right block

         l = 1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(mid,bar+1,n,n);

            if(i == 1){
               ans = mid;
               l = mid+1;
            } else {
               r = mid-1;
            }
         }

         x21 = ans;

         //find bottom of right block
         l = 1;
         r = n;
         ans = -1;
         while(l <= r){
            mid = l + (r-l)/2;

            int i = query(1,bar+1,mid,n);

            if(i == 1){
               ans = mid;
               r = mid-1;
            } else {
               l = mid+1;
            }
         }

         x22 = ans;

      }

      out.println("! " + x11 + " " + y11 + " " + x12 + " " + y12 + " " + x21 + " " + y21 + " " + x22 + " " + y22);

      out.close();
   }

   public static int query(int a,int b, int c, int d)throws IOException{
      out.println("? " + a + " " + b + " " + c + " " + d);
      out.flush();

      return Integer.parseInt(f.readLine());
   }

}


//package round371;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;

public class BT {
	Scanner in;
	PrintWriter out;
	String INPUT = "";

	int q(int r1, int c1, int r2, int c2)
	{
		out.printf("? %d %d %d %d\n", r1+1, c1+1, r2+1, c2+1);
		out.flush();
		return ni();
	}

	void e(int r1, int c1, int r2, int c2, int r3, int c3, int r4, int c4)
	{
		out.printf("! %d %d %d %d %d %d %d %d\n",
				r1+1, c1+1, r2+1, c2+1,
				r3+1, c3+1, r4+1, c4+1
				);
		out.flush();
	}

	void solve()
	{
		int n = ni();
		int cu = -1, cv = -1;
		{
			int low = -1, high = n-1;
			while(high - low > 1){
				int h = high+low>>1;
				if(q(0, 0, n-1, h) >= 2){
					high = h;
				}else{
					low = h;
				}
			}
			cu = high;
		}
		{
			int low = -1, high = n-1;
			while(high - low > 1){
				int h = high+low>>1;
				if(q(0, 0, n-1, h) >= 1){
					high = h;
				}else{
					low = h;
				}
			}
			cv = high;
		}

		int du = -1, dv = -1;
		{
			int low = 0, high = n;
			while(high - low > 1){
				int h = high+low>>1;
				if(q(0, h, n-1, n-1) >= 2){
					low = h;
				}else{
					high = h;
				}
			}
			du = low;
		}
		{
			int low = 0, high = n;
			while(high - low > 1){
				int h = high+low>>1;
				if(q(0, h, n-1, n-1) >= 1){
					low = h;
				}else{
					high = h;
				}
			}
			dv= low;
		}

		int eu = -1, ev = -1;
		{
			int low = -1, high = n-1;
			while(high - low > 1){
				int h = high+low>>1;
				if(q(0, 0, h, n-1) >= 2){
					high = h;
				}else{
					low = h;
				}
			}
			eu = high;
		}
		{
			int low = -1, high = n-1;
			while(high - low > 1){
				int h = high+low>>1;
				if(q(0, 0, h, n-1) >= 1){
					high = h;
				}else{
					low = h;
				}
			}
			ev = high;
		}

		int fu = -1, fv = -1;
		{
			int low = 0, high = n;
			while(high - low > 1){
				int h = high+low>>1;
				if(q(h, 0, n-1, n-1) >= 2){
					low = h;
				}else{
					high = h;
				}
			}
			fu = low;
		}
		{
			int low = 0, high = n;
			while(high - low > 1){
				int h = high+low>>1;
				if(q(h, 0, n-1, n-1) >= 1){
					low = h;
				}else{
					high = h;
				}
			}
			fv= low;
		}

		// cv <= cu
		// du <= dv
		int[][][] canc = {
				{{du, cu}, {dv, cv}},
				{{du, cv}, {dv, cu}}
		};
		int[][][] canr = {
				{{fu, eu}, {fv, ev}},
				{{fu, ev}, {fv, eu}}
		};
		for(int[][] cr : canr){
			if(cr[0][0] > cr[0][1])continue;
			if(cr[1][0] > cr[1][1])continue;
			for(int[][] cc : canc){
				if(cc[0][0] > cc[0][1])continue;
				if(cc[1][0] > cc[1][1])continue;
				for(int z = 0;z < 2;z++){
					if(
							q(cr[0][0], cc[0^z][0], cr[0][1], cc[0^z][1]) == 1 &&
							q(cr[1][0], cc[1^z][0], cr[1][1], cc[1^z][1]) == 1){
						e(cr[0][0], cc[0^z][0], cr[0][1], cc[0^z][1], cr[1][0], cc[1^z][0], cr[1][1], cc[1^z][1]);
						return;
					}
				}
			}
		}
		throw new RuntimeException();
	}

	void run() throws Exception
	{
		in = oj ? new Scanner(System.in) : new Scanner(INPUT);
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception
	{
		new BT().run();
	}

	int ni() { return Integer.parseInt(in.next()); }
	long nl() { return Long.parseLong(in.next()); }
	double nd() { return Double.parseDouble(in.next()); }
	boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import javax.crypto.AEADBadTagException;
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author AlexFetisov
 */
public class TaskB_AF {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskB_cf371 solver = new TaskB_cf371();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskB_cf371 {
        List<Rectangle> rects;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();

            int xLeft = 1, xRight = n;
            int xSeparate = -1;
            while (xLeft <= xRight) {
                int e = (xLeft + xRight) / 2;
                int t = makeRequest(in, out, 1, 1, e, n);
                if (t == 1) {
                    xSeparate = e;
                    xRight = e - 1;
                } else if (t == 0) {
                    xLeft = e + 1;
                } else {
                    xRight = e - 1;
                }
            }
            rects = new ArrayList<Rectangle>();
            if (xSeparate != -1 && makeRequest(in, out, xSeparate + 1, 1, n, n) == 1) {
                detectRectangle(in, out, 1, 1, xSeparate, n);
                detectRectangle(in, out, xSeparate + 1, 1, n, n);

                out.print("! ");
                for (Rectangle r : rects) {
                    out.print(r.toString() + " ");
                }
                out.println();
                out.flush();
                return;
            }

            int yLeft = 1, yRight = n;
            int ySeparate = -1;
            while (yLeft <= yRight) {
                int e = (yLeft + yRight) / 2;
                int t = makeRequest(in, out, 1, 1, n, e);
                if (t == 1) {
                    ySeparate = e;
                    yRight = e - 1;
                } else if (t == 0) {
                    yLeft = e + 1;
                } else {
                    yRight = e - 1;
                }
            }

            if (ySeparate != -1) {
                detectRectangle(in, out, 1, 1, n, ySeparate);
                detectRectangle(in, out, 1, ySeparate + 1, n, n);

                out.print("! ");
                for (Rectangle r : rects) {
                    out.print(r.toString() + " ");
                }
                out.println();
                out.flush();
                return;
            }
            throw new AssertionError("!");
        }

        private void detectRectangle(InputReader in, PrintWriter out, int xMin, int yMin, int xMax, int yMax) {
            int xLeft = -1, xRight = -1, yLeft = -1, yRight = -1;

            int left = xMin, right = xMax;
            while (left <= right) {
                int e = (left + right) / 2;
                if (makeRequest(in, out, xMin, yMin, e, yMax) == 1) {
                    xRight = e;
                    right = e - 1;
                } else {
                    left = e + 1;
                }
            }

            left = xMin;
            right = xRight;
            while (left <= right) {
                int e = (left + right) / 2;
                if (makeRequest(in, out, e, yMin, xRight, yMax) == 1) {
                    xLeft = e;
                    left = e + 1;
                } else {
                    right = e - 1;
                }
            }

            left = yMin;
            right = yMax;
            while (left <= right) {
                int e = (left + right) / 2;
                if (makeRequest(in, out, xLeft, yMin, xRight, e) == 1) {
                    yRight = e;
                    right = e - 1;
                } else {
                    left = e + 1;
                }
            }

            left = yMin;
            right = yRight;
            while (left <= right) {
                int e = (left + right) / 2;
                if (makeRequest(in, out, xLeft, e, xRight, yRight) == 1) {
                    yLeft = e;
                    left = e + 1;
                } else {
                    right = e - 1;
                }
            }
            rects.add(new Rectangle(xLeft, yLeft, xRight, yRight));
        }

        private int makeRequest(InputReader in, PrintWriter out, int x1, int y1, int x2, int y2) {
            out.print("? " + x1 + " " + y1 + " " + x2 + " " + y2);
            out.println();
            out.flush();
            return in.nextInt();
        }

        class Rectangle {
            int x1;
            int x2;
            int y1;
            int y2;

            public Rectangle(int x1, int y1, int x2, int y2) {
                this.x1 = x1;
                this.x2 = x2;
                this.y1 = y1;
                this.y2 = y2;
            }

            public String toString() {
                StringBuilder b = new StringBuilder("");
                b.append(x1).append(' ');
                b.append(y1).append(' ');
                b.append(x2).append(' ');
                b.append(y2);
                return b.toString();
            }

        }

    }

    static class InputReader {
        private BufferedReader reader;
        private StringTokenizer stt;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
        }

        public String nextLine() {
            try {
                return reader.readLine();
            } catch (IOException e) {
                return null;
            }
        }

        public String nextString() {
            while (stt == null || !stt.hasMoreTokens()) {
                stt = new StringTokenizer(nextLine());
            }
            return stt.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(nextString());
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskB solver = new TaskB();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskB {
        int[][] dr = new int[][]{{0, 0, 0, -1}, {0, 0, -1, 0}, {0, 1, 0, 0}, {1, 0, 0, 0}};
        int[][] dd = new int[][]{{1, 3}, {0, 2}, {1, 3}, {0, 2}};
        PrintWriter out;
        InputReader in;
        int[] re1;
        int[] re2;
        int N;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            N = in.nextInt();
            int r[] = new int[]{1, 1, N, N};

            this.out = out;
            this.in = in;

            re1 = new int[]{1, 1, 1, 1};
            re2 = new int[]{2, 1, 2, 1};

            //probuje najpierw lewa sciane

            int fr[] = moveSide(r, dr[2], dd[2]);
            int sr[] = subtract(r, fr);
            if (!validSeparation(sr)) {
                fr = moveSide(r, dr[1], dd[1]);
                sr = subtract(r, fr);
            }

            fr = boundary(fr);
            sr = boundary(sr);

            out.println(String.format("! %d %d %d %d %d %d %d %d", fr[0], fr[1], fr[2], fr[3], sr[0], sr[1], sr[2], sr[3]));
        }

        private boolean validSeparation(int[] sr) {
            if (!validRectangle(sr)) return false;
            out.println(String.format("? %d %d %d %d", sr[0], sr[1], sr[2], sr[3]));
            out.flush();
            return in.nextInt() == 1;
        }

        private boolean validRectangle(int[] sr) {
            for (int i = 0; i < 4; i++) {
                if (sr[i] < 1 || sr[i] > N) return false;
            }
            return true;
        }

        private int[] boundary(int[] r) {
            for (int d = 0; d < 4; d++) {
                r = moveSide(r, dr[d], dd[d]);
            }
            return r;
        }

        private int[] subtract(final int[] r, final int[] fr) {
            if (r[1] == fr[1]) {
                //jesli lewy dolny taki sam to ucieto horyzontalnie od gory
                return new int[]{fr[2] + 1, r[1], r[2], r[3]};
            }
            //else ucieto wertykalnie od lewej
            return new int[]{r[0], r[1], r[2], fr[1] - 1};
        }

        private int[] moveSide(final int[] rect, final int[] factors, final int[] widths) {
            int width = Math.abs(rect[widths[0]] - rect[widths[1]]);

            int lo = -1, hi = width + 1;

            while (lo + 1 < hi) {
                int m = lo + (hi - lo) / 2;
                int qr[] = new int[4];
                for (int d = 0; d < 4; d++) qr[d] = rect[d] + factors[d] * m;
                int ans = query(qr);
                if (ans != 0) {
                    lo = m;
                } else {
                    hi = m;
                }
            }

            int ans_rect[] = new int[4];
            for (int d = 0; d < 4; d++) ans_rect[d] = rect[d] + factors[d] * lo;

            return ans_rect;
        }

        private int query(final int[] qr) {
            int ans = 0;
            out.println(String.format("? %d %d %d %d", qr[0], qr[1], qr[2], qr[3]));
            out.flush();

            ans = in.nextInt();

//        if (contains(qr, re1)) ans++;
//        if (contains(qr, re2)) ans++;
            return ans;
        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Solution {
	static BufferedReader br;
	static int[] ans;
	public static void main(String[] args) throws Exception{
		br = new BufferedReader(new InputStreamReader(System.in));
		ans = new int[8];
		int n = Integer.parseInt(br.readLine());
		System.out.println("?"+"1 1 "+n+" "+n);
		System.out.flush();
		int q = Integer.parseInt(br.readLine());
		cut(n);
		System.out.print("! ");
		for(int i=0 ; i<8 ; i++)	System.out.print(ans[i]+" ");
		System.out.println();
	}

	public static void solve(int x1, int y1, int x2, int y2, int t) throws Exception{
		int l=x1, r=x2;
		int xx1,yy1,xx2,yy2;
		while(l<r){
			int mid = (l+r)/2;
			if(query(x1,y1,mid,y2)==1)	r=mid;
			else	l=mid+1;
		}
		xx2 = l;
		l=x1; r=x2;
		while(r>l){
			int mid = (l+r+1)/2;
			if(query(mid,y1,x2,y2)==1)	l = mid;
			else r=mid-1;
		}
		xx1 = l;
		l=y1; r=y2;
		while(l<r){
			int mid = (l+r)/2;
			if(query(x1,y1,x2,mid)==1)	r=mid;
			else	l=mid+1;
		}
		yy2=l;
		l=y1;r=y2;
		while(r>l){
			int mid = (l+r+1)/2;
			if(query(x1,mid,x2,y2)==1)	l=mid;
			else	r=mid-1;
		}
		yy1 = l;
		ans[t] = xx1;	ans[t+1] = yy1 ; ans[t+2] = xx2;	ans[t+3] = yy2;
	//	System.out.println("!"+xx1+" "+yy1+" "+xx2+" "+yy2);
	}
	public static void cut(int n) throws Exception{
		int l=1, r=n;
		while(l<r){
			int mid = (l+r)/2;
			if(query(1,1,n,mid)==0)	l=mid+1;
			else	r = mid;
		}
		if(query(1,1,n,l)==1 && query(1,l+1,n,n)==1){
			solve(1,1,n,l,0);
			solve(1,l+1,n,n,4);
			return;
		}
		l=1;r=n;
		while(l<r){
			int mid = (l+r)/2;
			if(query(1,1,mid,n)==0)	l=mid+1;
			else	r=mid;
		}
		solve(1,1,l,n,0);
		solve(l+1,1,n,n,4);
	}
	public static int query(int x1, int y1, int x2, int y2) throws Exception{
		System.out.println("?"+x1+" "+y1+" "+x2+" "+y2);
		System.out.flush();
		int q = Integer.parseInt(br.readLine());
		return q;
	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Egor Kulikov (egor@egork.net)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskB solver = new TaskB();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskB {
        int stage;
        int n;
        OutputWriter out;
        InputReader in;

        void query(int end) {
            switch (stage) {
            case 0:
                out.printLine('?', 1, 1, end, n);
                break;
            case 1:
                out.printLine('?', 1, 1, n, end);
                break;
            case 2:
                out.printLine('?', n + 1 - end, 1, n, n);
                break;
            case 3:
                out.printLine('?', 1, n + 1 - end, n, n);
                break;
            }
            out.flush();
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            this.out = out = new OutputWriter(System.out);
            this.in = in = new InputReader(System.in);
            n = in.readInt();
            int[] endx = new int[2];
            int[] endy = new int[2];
            int[] stx = new int[2];
            int[] sty = new int[2];
            find(endx);
            stage++;
            find(endy);
            stage++;
            find(stx);
            for (int i = 0; i < 2; i++) {
                stx[i] = n + 1 - stx[i];
            }
            stage++;
            find(sty);
            for (int i = 0; i < 2; i++) {
                sty[i] = n + 1 - sty[i];
            }
            for (int i = 0; i < 8; i++) {
                if (stx[i & 1] > endx[i >> 2 & 1] || sty[i >> 1 & 1] > endy[0]) {
                    continue;
                }
                if (stx[1 - (i & 1)] > endx[1 - (i >> 2 & 1)] || sty[1 - (i >> 1 & 1)] > endy[1]) {
                    continue;
                }
                out.printLine('?', stx[i & 1], sty[i >> 1 & 1], endx[i >> 2 & 1], endy[0]);
                out.flush();
                if (in.readInt() == 0) {
                    continue;
                }
                out.printLine('?', stx[1 - (i & 1)], sty[1 - (i >> 1 & 1)], endx[1 - (i >> 2 & 1)], endy[1]);
                out.flush();
                if (in.readInt() != 0) {
                    out.printLine("!", stx[i & 1], sty[i >> 1 & 1], endx[i >> 2 & 1], endy[0], stx[1 - (i & 1)],
                            sty[1 - (i >> 1 & 1)], endx[1 - (i >> 2 & 1)], endy[1]);
                    out.flush();
                    return;
                }
            }
        }

        private void find(int[] endx) {
            int left = 1;
            int right = n;
            while (left < right) {
                int middle = (left + right) >> 1;
                query(middle);
                if (in.readInt() == 2) {
                    right = middle;
                } else {
                    left = middle + 1;
                }
            }
            endx[0] = left;
            left = 0;
            right--;
            while (left < right) {
                int middle = (left + right + 1) >> 1;
                query(middle);
                if (in.readInt() == 0) {
                    left = middle;
                } else {
                    right = middle - 1;
                }
            }
            endx[1] = left + 1;
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void printLine(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

        public void flush() {
            writer.flush();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


import java.io.*;
import java.util.Arrays;
import java.util.Scanner;
import java.util.StringTokenizer;

public class DTask {

    static Scanner in;
    static int[] first = new int[4];
    static int[] second = new int[4];
    static PrintWriter out;
    static int n;

    public static void main(String[] args) throws IOException {
        in = new Scanner(System.in);
        out = new PrintWriter(System.out);
        n = in.nextInt() + 1;
        first = new int[]{0, 0, n, n};
        second = new int[]{0, 0, n, n};
        for (int i = 0; i < first.length; i++) {
            boolean inc = i < 2;
            search(first, i, inc, false);
            if (!inc) {
                first[i] += 1;
            }
        }

        for (int i = 0; i < second.length; i++) {
            boolean inc = i < 2;
            search(second, i, inc, true);
            if (!inc) {
                second[i] += 1;
            }
        }
        String s = "!";
        for (int i = 0; i < 4; i++) {
            s += " " + second[i];
        }
        for (int i = 0; i < 4; i++) {
            s += " " + first[i];
        }
        out.println(s);
        out.flush();
    }

    static void search(int arr[], int i, boolean inc, boolean cond) {
        int start = 0;
        int end = n;
        while (true) {
            if (end - start <= 1) {
                arr[i] = start;
                return;
            }
            int mid = (start + end) / 2;
            arr[i] = mid;
            int n = ask(arr, cond);
            if (n > 0) {
                if (inc) {
                    start = mid;
                } else {
                    end = mid;
                }
            } else {
                if (inc) {
                    end = mid;
                } else {
                    start = mid;
                }
            }
        }
    }

    static int ask(int arr[], boolean cond) {
        if (arr[1] > arr[3] || arr[0] > arr[2]) {
            return 0;
        }
        arr = Arrays.copyOf(arr, 4);
        String q = "";
        q += "?";
        for (int i = 0; i < arr.length; i++) {
            int x = Math.min(arr[i], n - 1);
            x = Math.max(x, 1);
            q += " " + x;
        }
        out.println(q);
        out.flush();
        int x = in.nextInt();
        if (cond) {
            x -= within(arr, first) ? 1 : 0;
        }
        return x;
        /*if (arr[1] > arr[3] || arr[0] > arr[2]) {
            return 0;
        }
        int[] check = new int[]{1, 1, 10, 1};
        int[] check1 = new int[]{5, 5, 5, 10};
        int result = within(arr, check) ? 1 : 0;
        result += within(arr, check1) ? 1 : 0;
        if (cond) {
            result -= within(arr, first) ? 1 : 0;
        }
        return result;*/

    }

    static boolean within(int outer[], int inner[]) {
        return (outer[0] <= inner[0] && outer[1] <= inner[1] && outer[2] >= inner[2] && outer[3] >= inner[3]);
    }

    static class MyInputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public MyInputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }
    }

}


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

public class B {

	static StringTokenizer st;
	static BufferedReader br;
	static PrintWriter pw;
	public static void main(String[] args) throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
		int n = nextInt();
		int left = 0, right = n;
		int x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0, x4 = 0, y4 = 0;
		while (right-left > 1) {
			int mid = (left+right) >> 1;
			System.out.println("? "+1+" "+1+" "+mid+" "+n);
			int ans = nextInt();
			if (ans==2)
				right = mid;
			else
				left = mid;
		}
		x4 = right;
		left = 0;
		right = n;
		while (right-left > 1) {
			int mid = (left+right) >> 1;
			System.out.println("? "+1+" "+1+" "+mid+" "+n);
			int ans = nextInt();
			if (ans >= 1)
				right = mid;
			else
				left = mid;
		}
		x2 = right;
		left = 1;
		right = n+1;
		while (right-left > 1) {
			int mid = (left+right) >> 1;
			System.out.println("? "+mid+" "+1+" "+n+" "+n);
			int ans = nextInt();
			if (ans >= 1)
				left = mid;
			else
				right = mid;
		}
		x3 = left;
		left = 1;
		right = n+1;
		while (right-left > 1) {
			int mid = (left+right) >> 1;
			System.out.println("? "+mid+" "+1+" "+n+" "+n);
			int ans = nextInt();
			if (ans >= 2)
				left = mid;
			else
				right = mid;
		}
		x1 = left;

		left = 0;
		right = n;
		while (right-left > 1) {
			int mid = (left+right) >> 1;
			System.out.println("? "+1+" "+1+" "+n+" "+mid);
			int ans = nextInt();
			if (ans>=2)
				right = mid;
			else
				left = mid;
		}
		y4 = right;
		left = 0;
		right = n;
		while (right-left > 1) {
			int mid = (left+right) >> 1;
			System.out.println("? "+1+" "+1+" "+n+" "+mid);
			int ans = nextInt();
			if (ans >= 1)
				right = mid;
			else
				left = mid;
		}
		y2 = right;
		left = 1;
		right = n+1;
		while (right-left > 1) {
			int mid = (left+right) >> 1;
			System.out.println("? "+1+" "+mid+" "+n+" "+n);
			int ans = nextInt();
			if (ans >= 1)
				left = mid;
			else
				right = mid;
		}
		y3 = left;
		left = 1;
		right = n+1;
		while (right-left > 1) {
			int mid = (left+right) >> 1;
			System.out.println("? "+1+" "+mid+" "+n+" "+n);
			int ans = nextInt();
			if (ans >= 2)
				left = mid;
			else
				right = mid;
		}
		y1 = left;
		if (y3 <= y2 && x3 <= x2) {
			System.out.println("! "+x3+" "+y3+" "+x2+" "+y2+" "+x1+" "+y1+" "+x4+" "+y4);
			return;
		}

		System.out.println("? "+x1+" "+y1+" "+x2+" "+y2);
		int ans1 = nextInt();
		System.out.println("? "+x3+" "+y3+" "+x4+" "+y4);
		int ans2 = nextInt();
		if (ans1==1 && ans2==1) {
			System.out.println("! "+x1+" "+y1+" "+x2+" "+y2+" "+x3+" "+y3+" "+x4+" "+y4);
			return;
		}

		System.out.println("? "+x1+" "+y3+" "+x2+" "+y4);
		ans1 = nextInt();
		System.out.println("? "+x3+" "+y1+" "+x4+" "+y2);
		ans2 = nextInt();
		if (ans1==1 && ans2==1) {
			System.out.println("! "+x1+" "+y3+" "+x2+" "+y4+" "+x3+" "+y1+" "+x4+" "+y2);
			return;
		}

		System.out.println("? "+x1+" "+y1+" "+x4+" "+y2);
		ans1 = nextInt();
		System.out.println("? "+x3+" "+y3+" "+x2+" "+y4);
		ans2 = nextInt();
		if (ans1==1 && ans2==1) {
			System.out.println("! "+x1+" "+y1+" "+x4+" "+y2+" "+x3+" "+y3+" "+x2+" "+y4);
			return;
		}

		System.out.println("? "+x1+" "+y3+" "+x2+" "+y2);
		ans1 = nextInt();
		System.out.println("? "+x3+" "+y1+" "+x4+" "+y4);
		ans2 = nextInt();
		if (ans1==1 && ans2==1) {
			System.out.println("! "+x1+" "+y3+" "+x2+" "+y2+" "+x3+" "+y1+" "+x4+" "+y4);
			return;
		}

		pw.close();
	}
	private static int nextInt() throws IOException {
		return Integer.parseInt(next());
	}
	private static long nextLong() throws IOException {
		return Long.parseLong(next());
	}
	private static double nextDouble() throws IOException {
		return Double.parseDouble(next());
	}
	private static String next() throws IOException {
		while (st==null || !st.hasMoreTokens())
			st = new StringTokenizer(br.readLine());
		return st.nextToken();
	}
}