#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <cstdlib>
#include <cassert>
#include <set>
#include <fstream>
#include <cmath>
using namespace std;


//ofstream Clog(string("bot.log"));

class TMethodDebugInfo {
	string MethodName;
	static int Depth;
public:
	TMethodDebugInfo(string methodName)
		: MethodName(methodName)
	{
		//Clog << string(Depth * 3, ' ') << "Entered " << MethodName << endl;
		++Depth;
	}
	~TMethodDebugInfo()
	{
		--Depth;
		//Clog << string(Depth * 3, ' ') << "Left " << MethodName << endl;
	}
};

typedef vector< vector<int> > TField;

TField playerField, enemyField;
const int W = 8, H = 16;

typedef pair<int, int> pii;
vector<pii> ballSeq;
int currentMove = 0;
pii *aBallSeq;

const int MAXMOVES = 1000000;

const int EMPTY_CELL = 0;
const int BLACK_BALL = 6;

typedef vector<int> vi;

void OnStart() {
	long long x0;
	cin >> x0;
	const long long A = 17235617;
	const long long B = 4311271;
	const long long MOD = 87465851;
	ballSeq.reserve(MAXMOVES);
	for (int i = 0; i < MAXMOVES; i++) {
		int u = x0 % 5 + 1;
		x0 = (x0 * A + B) % MOD;
		int v = x0 % 5 + 1;
		x0 = (x0 * A + B) % MOD;
		ballSeq.push_back(pii(u, v));
	}
	aBallSeq = &ballSeq[0];
	cout << "MIPT Waterogers" << endl;
}

int getTopPoint(const vector<vi> & oldField, int hor) {
	TMethodDebugInfo("getTopPoint");
	int cury = -1;
	while (1) {
		++cury;
		if (cury == H || oldField[cury][hor] != EMPTY_CELL)
			break;
	}
	--cury;
	return cury;
}

bool getFallPos(const vector<vi> & oldField, pii pos, vector<pii> & newPos) {
	TMethodDebugInfo("getFallPos");
	if (pos.second == 2)
		pos.first++;
	pii pos1, pos2;
	pos1.second = pos.first;
	pos1.first = getTopPoint(oldField, pos.first);
	if (pos1.first == -1 || (pos.second == 1 || pos.second == 3) && pos1.first == 0)
		return false;
	if (pos.second == 1 || pos.second == 3) {
		pos2 = pos1;
		pos2.first -= 1;
		if (pos.second == 1) {
			swap(pos1, pos2);
		}
	} else {
		pos2.second = pos1.second - (pos.second - 1);
		pos2.first = getTopPoint(oldField, pos2.second);
		if (pos2.first == -1)
			return false;
	}
	newPos.push_back(pos1);
	newPos.push_back(pos2);
	return true;
}

int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};

bool isIn(int x, int y) {
	return x >= 0 && x < W && y >= 0 && y < H;
}

vector<vi> was(H, vi(W));

void compDfs(const vector<vi> & oldField, int curCol, int y, int x, vector<pii> & curObl, vector<pii> & blackNear, vector<pii> & pushToWas) {
	TMethodDebugInfo("compDfs");
	if (oldField[y][x] == EMPTY_CELL || curCol == EMPTY_CELL || curCol == BLACK_BALL)
		return;
	if (was[y][x])
		return;
	was[y][x] = 1;
	pushToWas.push_back(pii(y, x));
	if (oldField[y][x] == curCol) {
		curObl.push_back(pii(y, x));
		for (int d = 0; d < 4; ++d) {
			int nx = x + dx[d];
			int ny = y + dy[d];
			if (!isIn(nx, ny))
				continue;
			if (oldField[ny][nx] != curCol && oldField[ny][nx] != BLACK_BALL)
				continue;
			if(was[ny][nx])
				continue;
			compDfs(oldField, curCol, ny, nx, curObl, blackNear, pushToWas);
		}
	}
	if (oldField[y][x] == BLACK_BALL)
		blackNear.push_back(pii(y, x));
}

void clearPoses(vector<vi> & field, vector<pii> & poses) {
	TMethodDebugInfo("clearPoses");
	for (int i = 0; i < (int) poses.size(); ++i) {
		assert(field[poses[i].first][poses[i].second] != EMPTY_CELL);
		field[poses[i].first][poses[i].second] = EMPTY_CELL;
	}
}

void fallAllField(vector<vi> & field) {
	TMethodDebugInfo("fallAllField");
	for (int x = 0; x < W; ++x) {
		int toY = H-1;
		int fromY = H-1;
		while (fromY >= 0) {
			if (field[fromY][x] != EMPTY_CELL) {
				field[toY][x] = field[fromY][x];
				--toY;
			}
			--fromY;
		}
	}
}

int TMethodDebugInfo::Depth = 0;

bool caclFall(const vector<vi> & oldField, vector<int> colors, pii pos, vector<vi> & newField, int & blackWillFall, int & maxCompSize, bool lastTurn = false) {
	TMethodDebugInfo("caclFall");
	int colDiff = 0;
	if (colors[0] == colors[1])
		colDiff = 1;
	blackWillFall = 0;
	maxCompSize = 0;
	assert(colors.size() == 2);
	vector<pii> newPos;
	if (!getFallPos(oldField, pos, newPos))
		return false;
	newField = oldField;
	for (int i = 0; i < 2; ++i) {
		newField[newPos[i].first][newPos[i].second] = colors[i];
	}
	vector<pii> pushToWas;
	int colorDels = 0;
	int compsDels = 0;
	for (int i = 0; i < 2; ++i) {
		vector<pii> obl, black;
		compDfs(newField, newField[newPos[i].first][newPos[i].second], newPos[i].first, newPos[i].second, obl, black, pushToWas);
		maxCompSize = max(maxCompSize, ((int)obl.size()) - colDiff);
		if (obl.size() >= 4) {
			colorDels += obl.size();
			++compsDels;
			clearPoses(newField, obl);
			clearPoses(newField, black);
		}
	}
	fallAllField(newField);
	int lavines = 0;
	clearPoses(was, pushToWas);
	pushToWas.clear();
	while (1) {
		++lavines;
		bool wasBurn = false;
		for (int x = 0; x < W; ++x) {
			for (int y = 0; y < H; ++y) {
				if (newField[y][x] != EMPTY_CELL && newField[y][x] != BLACK_BALL) {
					vector<pii> obl, black;
					compDfs(newField, newField[y][x], y, x, obl, black, pushToWas);
					if (obl.size() >= 4) {
						colorDels += obl.size();
						++compsDels;
						clearPoses(newField, obl);
						clearPoses(newField, black);
						wasBurn = true;
					}
				}
			}
		}
		clearPoses(was, pushToWas);
		pushToWas.clear();
		if (!wasBurn)
			break;
		fallAllField(newField);
	}
	if (compsDels > 0) {
		blackWillFall = colorDels - 2 - compsDels;
		if (lavines == 2) 
			blackWillFall += 3;
		if (lavines == 3) 
			blackWillFall += 6;
		if (lavines == 4)
			blackWillFall += 12;
		if (lavines >= 5)
			blackWillFall += 24;
	}
//	if (blackWillFall >= 10) {
//		Clog << "e: " << lavines << " " << blackWillFall << " " << colorDels << " " << compsDels << endl;
//	}
	return true;
}

double EstimatePosition(const TField& field) {
	int countHeight[H + 1];
	memset(countHeight, 0, sizeof(countHeight));
	double averageVal = 0.0;
	double sqSum = 0.0;
	double res = 0.0;
	int prevh = -1;
	for (int i = 0; i < W; i++) {
		int ch = 0;
		for (int j = 0; j < H; j++) {
			if (field[j][i] != EMPTY_CELL) {
				ch = H - j;
				break;
			}
		}
		countHeight[ch]++;
		averageVal+=max(ch-1, 0);
		sqSum += max(ch-1, 0)*max(ch-1,0);
		//if (i != 0)
		//	res -= abs(1.5 - abs(prevh - ch)) * 0.00001;
//		if (ch > 13)
//			res -= 0.3;
		prevh = ch;
	}
	res -= (sqSum - (averageVal*averageVal)) * 0.00001;

	return res;
}

const double DIMINISHING_BASE = log(2.0/3.0) / log(6.0);

double GetBestScore(const TField& field, int numTurn, int countBad) {
	const int iters = 1;
	if (numTurn >= iters + 1)
		return EstimatePosition(field) - countBad*0.005;
	double res = -10.0;
	vector<int> incomingMove(2);
	incomingMove[0] = aBallSeq[numTurn].first;
	incomingMove[1] = aBallSeq[numTurn].second;
	for (int i = 0; i < W; i++) {
		for (int j = 0; j < 4; j++) {
			if (i == W-1 && j % 2 == 0)
				continue;
			int blackF;
			TField newField;
			int mc = 0;
			bool lastIter = numTurn == iters;
			if (!caclFall(field, incomingMove, pii(i, j), newField, blackF, mc, lastIter))
				continue;
			if (blackF == 0 && countBad >= 3)
				continue;
			double sc = GetBestScore(newField, numTurn + 1, countBad + (mc >= 2) ? 0 : 1);
			sc += blackF * exp(DIMINISHING_BASE * numTurn);
			if (res < sc)
				res = sc;
		}
	}
	if (res < 0.0)
		return EstimatePosition(field);
	return res;
}

void OnMove() {
	TMethodDebugInfo("OnMove");
	playerField.resize(H, vector<int>(W));
	enemyField.resize(H, vector<int>(W));
	//////
	for (int i = 0; i < H; i++) {
		string line;
		cin >> line;
		for (int j = 0; j < W; j++) {
			switch (line[j]) {
			case '.':
				playerField[i][j] = EMPTY_CELL;
				break;
			case '*':
				playerField[i][j] = BLACK_BALL;
				break;
			default:
				playerField[i][j] = (int)(line[j] - '0');
			}
		}
	}
	//////
	for (int i = 0; i < H; i++) {
		string line;
		cin >> line;
		for (int j = 0; j < W; j++) {
			switch (line[j]) {
			case '.':
				enemyField[i][j] = EMPTY_CELL;
				break;
			case '*':
				enemyField[i][j] = BLACK_BALL;
				break;
			default:
				enemyField[i][j] = (int)(line[j] - '0');
			}
		}
	}
	//////
	/// Main logic should follow here
	vector<int> incomingMove(2);
	incomingMove[0] = aBallSeq[0].first;
	incomingMove[1] = aBallSeq[0].second;
	double bestRes = -1000000;
	pii bestPos(rand() % (W - 1), rand() % 4);
	for (int i = 0; i < W; i++) {
		for (int j = 0; j < 4; j++) {
			if (i == W-1 && j % 2 == 0)
				continue;
			int blackF;
			TField newField;
			int mc = 0;
			if (!caclFall(playerField, incomingMove, pii(i, j), newField, blackF, mc))
				continue;
			double sc = GetBestScore(newField, 1, (mc >= 2) ? 1 : 0);
			sc += blackF;
			if (sc > bestRes) {
				bestRes = sc;
				bestPos = pii(i, j);
			}
		}
	}
//	Clog << "Can generate " << bestRes << " black balls" << endl;
	cout << bestPos.first << " " << bestPos.second << endl;
//	Clog << bestPos.first << " " << bestPos.second << endl;
	////
	cout.flush();
	++currentMove;
	++aBallSeq;
}

int main() {
	while (true) {
		string command;
		cin >> command;
		if (command == "Quit")
			return 0;
		if (command == "Start")
			OnStart();
		else if (command == "Move")
			OnMove();
		else  {
			assert(false);
			return 1;
		}
	}
	assert(false); // No quit = bad
	return 1;
}
