import ru.ifmo.testlib.Checker;
import ru.ifmo.testlib.InStream;
import ru.ifmo.testlib.Outcome;
import ru.ifmo.testlib.Outcome.Type;

public class Check implements Checker {

	final double EPS = 5e-6;

	public Outcome test(InStream inf, InStream ouf, InStream ans) {
		Point[] jp = readPoly(ans, Type.FAIL);
		Point[] pp = readPoly(ouf, Type.WA);
		if (jp.length != pp.length) {
			return new Outcome(Type.WA, "Expected " + jp.length + ", found " + pp.length);
		}
		Outcome o1 = match(jp, pp);
		if (o1.getType().equals(Type.OK)) {
			return o1;			
		}
		Outcome o2 = match(jp, reverse(pp));
		if (o2.getType().equals(Type.OK)) {
			return o2;			
		}
		return new Outcome(Type.WA, "Clockwise: " + o1.getComment() + "; counterclockwise: " + o2.getComment());
	}
	
	Outcome match(Point[] jp, Point[] pp) {		
		double md = jp[0].dist(pp[0]);
		int mi = 0;
		for (int i = 1; i < pp.length; ++i) {
			double td = jp[0].dist(pp[i]);
			if (td < md) {
				md = td;
				mi = i;
			}
		}
		int j = mi;
		for (int i = 0; i < jp.length; ++i) {
			if (jp[i].dist(pp[j]) > EPS) {
				return new Outcome(Type.WA, "No match for point #" + (i + 1));
			}	
			j = (j + 1) % pp.length;
		}
		return new Outcome(Type.OK, "Ok: " + jp.length + " points");
	}

	Point[] reverse(Point[] p) {
		Point[] ans = new Point[p.length];
		int m = ans.length;
		for (Point a : p) {
			ans[--m] = a;
		}
		return ans;
	}
	
	class Point {
		double x, y;

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

		double dist(Point o) {
			return Math.sqrt((x - o.x) * (x - o.x) + (y - o.y) * (y - o.y));
		}
	}

	Point[] readPoly(InStream f, Type t) {
		int k = f.nextInt();
		if (k <= 0) {
			throw new Outcome(t, "Too few points: " + k);
		}
		Point[] ans = new Point[k];
		for (int i = 0; i < k; ++i) {
			ans[i] = new Point(f.nextDouble(), f.nextDouble());
		}
		return ans;
	}
}
