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

public class TestsGen {
	static int testcount = 0;

	static Random random = new Random(8475324);
	
	static int MAXFL = 5000;
	static int MAXN = 50;
	
	static boolean[] used = new boolean[MAXFL];
	
	static void resetNum() {
		Arrays.fill(used, false);
	}
	
	static int getNum(int maxfl) {
		int ret = random.nextInt(maxfl);
		while (used[ret]) {
			ret = random.nextInt(maxfl);
		}
		used[ret] = true;
		return ret + 1;
	}

	static void write(int[][] fl, boolean[][] li, boolean[][] need) throws IOException {
		PrintWriter out = new PrintWriter(String.format("%02d", ++testcount));
		System.out.println("Generating test #" + testcount);
		out.println(fl.length + " " + fl[0].length);
		for (int i = 0; i < fl.length; i++) {
			for (int j = 0; j < fl[i].length; j++) {
				if (j > 0) {
					out.print(" ");
				}
				out.print(fl[i][j]);
			}
			out.println();
		}
		for (int i = 0; i < li.length; i++) {
			for (int j = 0; j < li[i].length; j++) {
				if (li[i][j]) {
					out.print("#");
				} else {
					out.print(".");
				}
			}
			out.println();
		}
		out.println(need.length + " " + need[0].length);
		for (int i = 0; i < need.length; i++) {
			for (int j = 0; j < need[i].length; j++) {
				if (need[i][j]) {
					out.print("#");
				} else {
					out.print(".");
				}
			}
			out.println();
		}
		out.close();
	}
	
	public static void writeRand(int n, int m, int a, int b, int maxfl, double eps) throws IOException {
		resetNum();
		maxfl = Math.max(maxfl, n);
		int[][] fl = new int[n][m];
		boolean[][] li = new boolean[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (random.nextDouble() < eps && j > 0) {
					fl[i][j] = fl[i][j - 1];
				} else {
					fl[i][j] = getNum(maxfl);
				}
				li[i][j] = random.nextBoolean();
			}
		}
		boolean[][] need = new boolean[a][b];
		for (int i = 0; i < a; i++) {
			for (int j = 0; j < b; j++) {
				need[i][j] = random.nextBoolean();
			}
		}
		write(fl, li, need);
	}
	
	public static void writeRand(int n, int m, int maxfl) throws IOException {
		writeRand(n, m, random.nextInt(n) + 1, random.nextInt(m) + 1, maxfl, 1 - maxfl / n / m * random.nextDouble());
	}

	public static void write1(int n, int m, int a, int b, int maxfl, double eps, boolean fill) throws IOException {
		resetNum();
		maxfl = Math.max(maxfl, n);
		if (n * m * (1 - eps) > maxfl) {
			eps = 1 - maxfl / n / m * random.nextDouble();
		}
		int[][] fl = new int[n][m];
		boolean[][] li = new boolean[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (random.nextDouble() < eps && j > 0) {
					fl[i][j] = fl[i][j - 1];
				} else {
					fl[i][j] = getNum(maxfl);
				}
				li[i][j] = fill;
			}
		}
		boolean[][] need = new boolean[a][b];
		for (int i = 0; i < a; i++) {
			for (int j = 0; j < b; j++) {
				need[i][j] = !fill;
			}
		}
		write(fl, li, need);
	}
	
	public static void write2(int n, int m, int maxfl, double eps) throws IOException {
		resetNum();
		maxfl = Math.max(maxfl, 2 * n);
		int[][] fl = new int[n][m];
		boolean[][] li = new boolean[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (random.nextDouble() < eps && j > 0) {
					fl[i][j] = fl[i][j - 1];
				} else {
					fl[i][j] = getNum(maxfl);
				}
				li[i][j] = random.nextBoolean();
			}
		}
		boolean[][] need = new boolean[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				need[i][j] = !li[i][j];
			}
		}
		write(fl, li, need);
	}
	
	public static void write3(int n, int m, int a, int b, int maxfl, double eps) throws IOException {
		resetNum();
		maxfl = Math.max(maxfl, 2 * n);
		int[][] fl = new int[n][m];
		boolean[][] li = new boolean[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (random.nextDouble() < eps && j > 0) {
					fl[i][j] = fl[i][j - 1];
				} else {
					fl[i][j] = getNum(maxfl);
				}
				li[i][j] = random.nextBoolean();
			}
		}
		boolean[][] need = new boolean[a][b];
		int di = random.nextInt(n - a + 1);
		int dj = random.nextInt(m - b + 1);
		for (int i = 0; i < a; i++) {
			for (int j = 0; j < b; j++) {
				need[i][j] = li[di + i][dj + j];
			}
		}
		write(fl, li, need);
	}
	
	public static void main(String[] args) throws IOException {
		while (new File(String.format("%02d.t", testcount + 1)).exists()) {
			testcount++;
		}
		write2(1, MAXN, 1, 1);
		write2(MAXN, 1, MAXFL, 1);
		write3(10, 10, 5, 5, 200, 0.2);
		// 8
		for (int i = 0; i < 10; i++) {
			writeRand(random.nextInt(MAXN) + 1, random.nextInt(MAXN) + 1, random.nextInt(MAXFL) + 1);
		}
		// 18
		for (int i = 0; i < 5; i++) {
			writeRand(MAXN, MAXN, MAXFL);
			writeRand(MAXN, MAXN, random.nextInt(MAXFL) + 1);
		}
		// 28
		writeRand(MAXN, MAXN, 1);
		writeRand(MAXN, MAXN, MAXN, MAXN, 1, 1);
		// 30
		writeRand(MAXN, MAXN, MAXN, MAXN, MAXFL, 0);
		writeRand(MAXN, MAXN, 1, 1, 1, 1);
		writeRand(MAXN, MAXN, 1, 1, MAXFL, 0);
		write1(MAXN, MAXN, 1, 1, random.nextInt(MAXFL) + 1, random.nextDouble(), true);
		write1(MAXN, MAXN, 1, 1, random.nextInt(MAXFL) + 1, random.nextDouble(), false);
		// 35
		write1(MAXN, MAXN, MAXN, MAXN, random.nextInt(MAXFL) + 1, random.nextDouble(), true);
		write1(MAXN, MAXN, MAXN, MAXN, random.nextInt(MAXFL) + 1, random.nextDouble(), false);
		write1(MAXN, MAXN, MAXN, MAXN, MAXFL, 0, true);
		write1(MAXN, MAXN, MAXN, MAXN, MAXFL, 1, false);
		write2(MAXN, MAXN, MAXFL, 0);
		// 40
		write2(MAXN, MAXN, MAXFL, 1);
		write2(MAXN, MAXN, 2 * MAXN, 1);
		write3(MAXN, MAXN, random.nextInt(MAXN) + 1, random.nextInt(MAXN) + 1, MAXFL, 0.2);
		write3(MAXN, MAXN, random.nextInt(MAXN) + 1, random.nextInt(MAXN) + 1, MAXFL, 0.5);
		write3(MAXN, MAXN, random.nextInt(MAXN) + 1, random.nextInt(MAXN) + 1, MAXFL, 1);
		// 45
		write3(MAXN, MAXN, 10, 10, MAXFL, 0.05);
	}

}
