import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;

import com.vividsolutions.jts.algorithm.ConvexHull;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;

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

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

		@Override
		public int compareTo(Point o) {
			if (x != o.x)
				return x - o.x;
			return y - o.y;
		}

	}

	class Test {
		Point[] ps;
		int n;

		public Test(int n, Point... ps) {
			super();
			this.ps = ps;
			this.n = n;
		}

	}

	private int testCount = 2;

	private void write(Test t) {
		try {
			++testCount;
			String filename = testCount / 10 + "" + testCount % 10;
			PrintWriter out = new PrintWriter(filename);
			out.println(t.n + " " + t.ps.length);
			for (Point p : t.ps) {
				out.println(p.x + " " + p.y);
			}
			System.err.println(testCount);
			out.flush();
			out.close();
		} catch (IOException ex) {
			throw new RuntimeException(ex);
		}
	}

	void myAssert(boolean b) {
		if (!b)
			throw new AssertionError();
	}

	static Random rand = new Random(1);

	public void run() throws IOException {
		write(new Test(1, getPoly1(3, 10)));
		write(new Test(1, getPoly2(3, 10, 20)));
		write(new Test(2, getPoly1(3, 10)));
		write(new Test(2, getPoly2(3, 10, 20)));
		write(new Test(3, getPoly1(3, 10)));
		write(new Test(3, getPoly2(3, 10, 20)));
		write(new Test(15, getPoly1(3, 10)));
		write(new Test(15, getPoly2(3, 10, 20)));
		for (int i = 0; i < 10; i++) {
			write(new Test(rand.nextInt(15) + 1, getPoly1(rand.nextInt(100 - 3) + 3, rand.nextInt(500) + 500)));
			write(new Test(rand.nextInt(15) + 1, getPoly2(rand.nextInt(100 - 3) + 3, rand.nextInt(250) + 250,
					rand.nextInt(250) + 250)));
		}
		write(new Test(1, new Point(-1000, -1000), new Point(1000, -1000), new Point(1000, 1000),
				new Point(-1000, 1000)));
		write(new Test(2, new Point(-1000, -1000), new Point(1000, -1000), new Point(1000, 1000),
				new Point(-1000, 1000)));
		write(new Test(3, new Point(-1000, -1000), new Point(1000, -1000), new Point(1000, 1000),
				new Point(-1000, 1000)));
		write(new Test(7, new Point(-1000, -1000), new Point(1000, -1000), new Point(1000, 1000),
				new Point(-1000, 1000)));
		write(new Test(14, new Point(-1000, -1000), new Point(1000, -1000), new Point(1000, 1000), new Point(-1000,
				1000)));
	}

	Point[] getPoly1(int n, int r) {
//		System.out.println(n + " " + r);
		wh: while (true) {
			Coordinate[] ps = new Coordinate[n];
			for (int j = 0; j < ps.length; j++) {
				double alpha = rand.nextDouble() * Math.PI;
				if (rand.nextInt(n) < n / 10) {
					alpha = alpha + Math.PI;
				}
				ps[j] = new Coordinate((int) (r * Math.cos(alpha)), (int) (r * Math.sin(alpha)));
			}
			Coordinate[] c;
			try {
				c = new ConvexHull(ps, new GeometryFactory()).getConvexHull().getCoordinates();
			} catch (Throwable e) {
				continue wh;
			}
			// System.err.println(Arrays.toString(c));
			Point[] p = new Point[c.length - 1];
			for (int i = 0; i < p.length; i++) {
				p[i] = new Point((int) c[i].x, (int) c[i].y);
			}
			Collections.reverse(Arrays.asList(p));
			for (int i = 0; i < p.length; i++) {
				if ((p[(i + 2) % p.length].x - p[i].x) * (p[(i + 1) % p.length].y - p[i].y)
						- (p[(i + 2) % p.length].y - p[i].y) * (p[(i + 1) % p.length].x - p[i].x) == 0) {
					continue wh;
				}
			}
			Point[] p2 = p.clone();
			Arrays.sort(p2);
			for (int i = 0; i < p2.length - 1; i++) {
				if (p2[i].compareTo(p2[i + 1]) == 0)
					continue wh;
			}
			for (int i = 0; i < p.length; ++i) {
				int j = (i + 1) % p.length;

				double a = p[j].y - p[i].y;
				double b = p[i].x - p[j].x;
				double cc = -a * p[i].x - b * p[i].y;

				for (int k = 0; k < p.length; ++k) {
					if (k == i || k == j)
						continue;
					if (a * p[k].x + b * p[k].y + cc >= 0) {
						continue wh;
					}
				}
			}
			return p;
		}
	}

	Point[] getPoly2(int n, int r1, int r2) {
		wh: while (true) {
			Coordinate[] ps = new Coordinate[n];
			for (int j = 0; j < ps.length; j++) {
				double alpha = rand.nextDouble() * Math.PI;
				if (rand.nextInt(n) < n / 10) {
					alpha = alpha + Math.PI;
				}

				ps[j] = new Coordinate((int) (r1 * Math.cos(alpha) + r2 * rand.nextDouble() * Math.sin(alpha)),
						(int) (r1 * Math.sin(alpha) - r2 * rand.nextDouble() * Math.cos(alpha)));
			}
			Coordinate[] c = new ConvexHull(ps, new GeometryFactory()).getConvexHull().getCoordinates();
			// System.err.println(Arrays.toString(c));
			Point[] p = new Point[c.length - 1];
			for (int i = 0; i < p.length; i++) {
				p[i] = new Point((int) c[i].x, (int) c[i].y);
			}
			Collections.reverse(Arrays.asList(p));
			for (int i = 0; i < p.length; i++) {
				if ((p[(i + 2) % p.length].x - p[i].x) * (p[(i + 1) % p.length].y - p[i].y)
						- (p[(i + 2) % p.length].y - p[i].y) * (p[(i + 1) % p.length].x - p[i].x) == 0) {
					continue wh;
				}
			}
			Point[] p2 = p.clone();
			Arrays.sort(p2);
			for (int i = 0; i < p2.length - 1; i++) {
				if (p2[i].compareTo(p2[i + 1]) == 0)
					continue wh;
			}

			return p;
		}
	}

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

}
