#include <iostream>

using namespace std;

enum WindingOrder {
	BOTTOM = 0,
	RIGHT,
	TOP,
	LEFT
};

void tester(const int* square, WindingOrder edge, int* output) {
	switch (edge) {
	case BOTTOM:
		output[0] = square[0]; output[1] = square[1]; output[2] = square[2]; output[3] = square[1];
		break;
	case RIGHT:
		output[0] = square[2]; output[1] = square[1]; output[2] = square[2]; output[3] = square[3];
		break;
	case TOP:
		output[0] = square[2]; output[1] = square[3]; output[2] = square[0]; output[3] = square[3];
		break;
	case LEFT:
		output[0] = square[0]; output[1] = square[3]; output[2] = square[0]; output[3] = square[1];
		break;
	}
}

int getIndex(int i, int edge) {
	const int ib0 = i & 1;
	const int ib1 = (i & 2) >> 1;
	const int eb0 = edge & 1;
	const int eb1 = (edge & 2) >> 1;

	const int iXor = ib0 ^ ib1;

	const int iNXorCondition = eb0 ^ eb1;
	const int iXorCondition = ib1 ^ eb1;

	return ((iNXorCondition & ~iXor | iXorCondition & iXor) << 1) | ib0;
}

int main() {
	const int size = 4;
	const int square[size] = { 0, 1, 2, 3 };
	int test[size];
	int output[size];

	for (WindingOrder edge = BOTTOM; edge <= LEFT; edge = static_cast<WindingOrder>(static_cast<int>(edge) + 1)) {
		tester(square, edge, test);

		for (int i = 0; i < size ; ++i) {
			output[i] = square[getIndex(i, static_cast<int>(edge))];
		}

		const bool firstX = output[0] == test[0];
		const bool firstY = output[1] == test[1];
		const bool secondX = output[2] == test[2];
		const bool secondY = output[3] == test[3];

		if (!firstX) {
			cout << "Mismatch at i = 0: test = " << test[0] << " output = " << output[0] << endl;
		} else if (!firstY) {
			cout << "Mismatch at i = 1: test = " << test[1] << " output = " << output[1] << endl;
		} else if (!secondX) {
			cout << "Mismatch at i = 2: test = " << test[2] << " output = " << output[2] << endl;
		} else if (!secondY) {
			cout << "Mismatch at i = 3: test = " << test[3] << " output = " << output[3] << endl;
		} else {
			cout << "Match: " << output[0] << ' ' << output[1] << ' ' << output[2] << ' ' << output[3] << endl;
		}
	}

	return 0;
}