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

class Point implements Comparable<Point> {
	int x, y;

	public Point(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}

	public String toString() {
		return Integer.toString(x) + " " + Integer.toString(y);
	}

	@Override
	public int compareTo(Point p2) {
		if (x < p2.x)
			return -1;
		if (x > p2.x)
			return 1;
		if (y < p2.y)
			return -1;
		if (y > p2.y)
			return 1;
		return 0;
	}

}

public class Gen {

	static int done = 0;
	static Point[][] polygon = new Point[2][];

	static final Random rand = new Random(556668949239L);
	static final int maxShift = 1000;
	static final int maxCoord = (int) 1e9 - 3 * maxShift;
	static final int maxN = 100000;

	static void print() throws IOException {
		done++;
		System.err.println(done);
		PrintWriter out;
		if (done < 10)
			out = new PrintWriter("../tests/0" + String.valueOf(done));
		else
			out = new PrintWriter("../tests/" + String.valueOf(done));
		
		out.println(polygon[0].length);
		for (int i = 0; i < 2; i++) {
			for (int j = 0; j < polygon[i].length; j++) {
				out.println(polygon[i][j]);
			}
			polygon[i] = null;
		}
		out.close();
	}

	static void invertX() {
		for (Point p : polygon[0]) {
			p.x = -p.x;
		}
	}

	static void invertY() {
		for (Point p : polygon[0]) {
			p.y = -p.y;
		}
	}

	static void invert45() {
		for (Point p : polygon[0]) {
			int tmp = p.x;
			p.x = p.y;
			p.y = tmp;
		}
	}

	static void shift(Point sh) {
		for (Point p : polygon[0]) {
			p.x += sh.x;
			p.y += sh.y;
		}
	}

	static void reverse(Point[] a) {
		int i = 0, j = a.length - 1;
		while (i < j) {
			Point tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
			i++;
			j--;
		}
	}

	static void changeOrder() {
		int n = polygon[0].length;
		Point[] newOrder = new Point[n];
		int shift = rand.nextInt(n);
		for (int i = 0; i < n; i++) {
			newOrder[i] = polygon[0][(i + shift) % n];
		}
		if (rand.nextBoolean()) {
			reverse(newOrder);
		}
		polygon[0] = newOrder;
	}

	// invert135 doesn't need because it's invert45 + invertX + invertY

	static void genSample1() throws IOException {
		polygon[0] = new Point[3];
		polygon[1] = new Point[3];
		polygon[0][0] = new Point(0, 0);
		polygon[0][1] = new Point(1, 1);
		polygon[0][2] = new Point(1, 0);

		polygon[1][0] = new Point(2, 2);
		polygon[1][1] = new Point(3, 2);
		polygon[1][2] = new Point(3, 1);

		print();
	}

	static double cross(Point a, Point b, Point c) {
		return ((double) b.x - a.x) * ((double) c.y - b.y)
				- ((double) b.y - a.y) * ((double) c.x - b.x);
	}

	static Point[] copyArray(Point[] old, int n) {
		Point[] res = new Point[n];
		for (int i = 0; i < n; i++) {
			res[i] = new Point(old[i].x, old[i].y);
		}
		return res;
	}

	static Point[] convexHull(Point[] P) {
		int n = P.length, k = 0;
		Point[] H = new Point[2 * n];

		// Sort points lexicographically
		Arrays.sort(P);

		// Build lower hull
		for (int i = 0; i < n; i++) {
			while (k >= 2 && cross(H[k - 2], H[k - 1], P[i]) <= 0)
				k--;
			H[k++] = P[i];
		}

		// Build upper hull
		for (int i = n - 2, t = k + 1; i >= 0; i--) {
			while (k >= t && cross(H[k - 2], H[k - 1], P[i]) <= 0)
				k--;
			H[k++] = P[i];
		}

		k--;
		Point[] ans = new Point[k];
		for (int i = 0; i < k; i++) {
			ans[i] = H[i];
		}
		return ans;
	}

	static void genFullyRandomPolygon(int num) {
		Point[] a = new Point[maxN];
		for (int i = 0; i < maxN; i++) {
			a[i] = new Point(rand.nextInt() % maxCoord, rand.nextInt()
					% maxCoord);
		}
		polygon[num] = convexHull(a);
	}

	static void genBigRandomPolygon(int num) {
		Point[] a = new Point[maxN];
		double alpha = 2 * Math.PI / maxN;
		double r = 1000000 + rand.nextInt((int) (5 * 1e8));
		for (int i = 0; i < maxN; i++) {
			double beta = alpha * i;
			a[i] = new Point((int) (r * Math.cos(beta)),
					(int) (r * Math.sin(beta)));
		}
		polygon[num] = convexHull(a);
	}

	public static void main(String[] args) throws IOException {
		File dir = new File("../tests");
		if (!dir.exists())
			dir.mkdir();
		done = 0;

		// Tests for YES
		// Sample
		genSample1();

		// Fully random tests with all possible Transformation
		for (int p = 0; p < 8; p++) {
			genFullyRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			if ((p & 1) != 0) {
				invertX();
			}
			if ((p & 2) != 0) {
				invertY();
			}
			if ((p & 4) != 0) {
				invert45();
			}
			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}

		// Big Test with all possible composition of Transformation, vertex by
		// Circle
		for (int p = 0; p < 8; p++) {
			genBigRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			if ((p & 1) != 0) {
				invertX();
			}
			if ((p & 2) != 0) {
				invertY();
			}
			if ((p & 4) != 0) {
				invert45();
			}
			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}

		// Tests with answer NO
		// Big Random
		for (int i = 0; i < 2; i++) {
			genFullyRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			int best = 0;
			for (int j = 0; j < polygon[1].length; j++) {
				if (polygon[1][j].y < polygon[1][best].y) {
					best = j;
				}
			}
			polygon[1][best].y--;

			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}

		for (int i = 0; i < 2; i++) {
			genFullyRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			int best = 0;
			for (int j = 0; j < polygon[1].length; j++) {
				if (polygon[1][j].y > polygon[1][best].y) {
					best = j;
				}
			}
			polygon[1][best].y++;

			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}

		for (int i = 0; i < 2; i++) {
			genFullyRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			int best = 0;
			for (int j = 0; j < polygon[1].length; j++) {
				if (polygon[1][j].x > polygon[1][best].x) {
					best = j;
				}
			}
			polygon[1][best].x++;

			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}

		for (int i = 0; i < 3; i++) {
			genFullyRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			int best = 0;
			for (int j = 0; j < polygon[1].length; j++) {
				if (polygon[1][j].x < polygon[1][best].x) {
					best = j;
				}
			}
			polygon[1][best].x--;

			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}

		// Big Circles
		for (int i = 0; i < 1; i++) {
			genBigRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			int best = 0;
			for (int j = 0; j < polygon[1].length; j++) {
				if (polygon[1][j].x < polygon[1][best].x) {
					best = j;
				}
			}
			polygon[1][best].x--;
			//Maybe not convex, but in this random still convex and ok

			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}
		
		for (int i = 0; i < 3; i++) {
			genBigRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			int x = rand.nextInt() % 100;
			int middle = rand.nextInt() % 1000000;
			for (Point p : polygon[1]) {
				if (p.x >= middle) {
					p.x += x;
				}
			}
			
			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}
		
		for (int i = 0; i < 4; i++) {
			genBigRandomPolygon(0);
			polygon[1] = copyArray(polygon[0], polygon[0].length);

			int y = rand.nextInt() % 100;
			if (i == 1) {
				continue;
			}
			int middle = rand.nextInt() % 1000000;
			for (Point p : polygon[1]) {
				if (p.y >= middle) {
					p.y += y;
				}
			}
			
			Point sh = new Point(rand.nextInt() % maxShift, rand.nextInt()
					% maxShift);
			shift(sh);
			changeOrder();

			print();
		}
		
	}
}
