/*------------------------------------------------------------
TEAM46
A
230
Target: CS35; Platform: Win32; Comment: C Sharp (.Net 3.5)
------------------------------------------------------------*/
﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading;

public class BlockBot
{
	public BlockBot(Func<BlockBot, Func<List<GameMove>, GameMove>> f)
	{
		this.f = f;
		board = new Cell[BOARD_SIZE, BOARD_SIZE];
		for (int x = 0; x < BOARD_SIZE; x++)
		{
			Cell cell = (x <= 1 ? Cell.WHITE : (x >= BOARD_SIZE - 2 ? Cell.BLACK : Cell.EMPTY));
			for (int y = 0; y < BOARD_SIZE; y++)
				board[x, y] = cell;
		}
		currentColor = Cell.WHITE;
		random = new Random();//(314159265);
	}

	private static void Main()
	{
		new BlockBot(b => b.KlinKlinom(b.DefensiveMove)).Run();
		return;
		Test();
		return;
		var best = TestGravity(-10, 10, 0, 10, 15, 3);
		Console.WriteLine("k1: {0}", best.Key);
		Console.WriteLine("k2: {0}", best.Value);
	}

	static KeyValuePair<double, double> TestGravity(double k1down, double k1up, double k2down, double k2up, int steps, int rec)
	{
		double k1step = (k1up - k1down)/steps;
		double k2step = (k2up - k2down) / steps;

		int maxWins = 0;
		var max = new KeyValuePair<double, double>(0,0);

		for (double k1 = k1down; k1 <= k1up; k1 += k1step)
		{
			for (double k2 = k2down; k2 <= k2up; k2 += k2step)
			{
				int wins = TestGravity(k1, k2);
				if (wins > maxWins)
				{
					maxWins = wins;
					max = new KeyValuePair<double, double>(k1, k2);
				}
			}
		}
		double newk1step = (k1up - k1down)/5;
		double newk2step = (k2up - k2down)/5;
		if (rec > 0)
			max = TestGravity(max.Key - newk1step, max.Key + newk1step, max.Value - newk2step, max.Value + newk2step, steps, rec - 1);
		return max;
	}

	static int TestGravity(double k1, double k2)
	{
		int win1 = 0;
		int win2 = 0;
		const int iterations = 30;
		for (int i = 0; i < iterations; i++)
		{
			var bot1 = new BlockBot(b => b.FunnyDefensiveMove);
			var bot2 = new BlockBot(b => b.GravityMove) {k1 = k1, k2 = k2};

			string move = bot1.ProcessCommand("Start");
			while (true)
			{
				move = bot2.ProcessCommand(move);
				if (move == null)
				{
					win1++;
					break;
				}
				if (bot2.WinningMove(GameMove.Parse(move)))
				{
					win2++;
					break;
				}

				move = bot1.ProcessCommand(move);
				if (move == null)
				{
					win2++;
					break;
				}
				if (bot1.WinningMove(GameMove.Parse(move)))
				{
					win1++;
					break;
				}
			}
		}

		return win2;
	}

	static void Test()
	{
		int win1 = 0;
		int win2 = 0;
		const int iterations = 100;
		for (int i = 0; i < iterations; i++)
		{
			var bot1 = new BlockBot(b => b.RandomMove); Thread.Sleep(2);
			var bot2 = new BlockBot(b => b.KlinKlinom(b.DefensiveMove));

			string move = bot1.ProcessCommand("Start");
			while (true)
			{
				move = bot2.ProcessCommand(move);
				if (move == null)
				{
					win1++;
					break;
				}
				if (bot2.WinningMove(GameMove.Parse(move)))
				{
					win2++;
					break;
				}

				move = bot1.ProcessCommand(move);
				if (move == null)
				{
					win2++;
					break;
				}
				if (bot1.WinningMove(GameMove.Parse(move)))
				{
					win1++;
					break;
				}
			}
		}

		Console.WriteLine("In {0} iterations", iterations);
		Console.WriteLine("Win1: {0}", win1);
		Console.WriteLine("Win2: {0}", win2);
	}

	void OutputAndFlush(string line)
	{
		Console.WriteLine(line);
		Console.Out.Flush();
	}
	string Read()
	{
		return Console.ReadLine();
	}

	private void Run()
	{
		while (true)
		{
			string command = Read();
			if (command == "Quit")
				break;
			if (command == "Name")
			{
				OutputAndFlush("GovBot (Oo)");
				continue;
			}
			var moveRes = ProcessCommand(command);
			OutputAndFlush(moveRes);
		}
	}

	public string ProcessCommand(string command)
	{
		if (command != "Start")
			MakeMove(GameMove.Parse(command));
		var moves = GetMoves();
		if (moves.Count == 0)
			return null;

		GameMove move = f(this)(moves);
		MakeMove(move);
		movesDone++;
		return move.ToString();
	}

	private void MakeMove(GameMove move)
	{
		board[move.ex, move.ey] = board[move.sx, move.sy];
		board[move.sx, move.sy] = Cell.EMPTY;
		currentColor = (currentColor == Cell.WHITE ? Cell.BLACK : Cell.WHITE);
	}

	bool InBoard(int ex, int ey)
	{
		return ex >= 0 && ex < BOARD_SIZE && ey >= 0 && ey < BOARD_SIZE;
	}

	int Dx()
	{
		return (currentColor == Cell.WHITE ? 1 : -1);
	}

	bool WinningMove(GameMove move)
	{
		int nx = move.ex + Dx();
		return !InBoard(nx, move.ey);
	}

	bool WillDieAfter(GameMove move)
	{
		for (int dy = -1; dy <= 1; dy += 2)
		{
			int x = move.ex + Dx();
			int y = move.ey + dy;

			if (InBoard(x,y) && board[x, y] != Cell.EMPTY && board[x, y] != currentColor)
				return true;
		}
		return false;
	}

	bool WillKill(GameMove x)
	{
		return board[x.ex, x.ey] != currentColor && board[x.ex, x.ey] != Cell.EMPTY;
	}

	void RandomShuffle<T>(List<T> moves)
	{
		for(int i = 0; i < moves.Count; i++)
			for(int j = 0; j < moves.Count; j++)
				if (random.NextDouble() > 0.5)
				{
					T temp = moves[i];
					moves[i] = moves[j];
					moves[j] = temp;
				}
	}

	GameMove OffensiveMove(List<GameMove> moves)
	{
		RandomShuffle(moves);
		moves.Sort((x, y) =>
			{
				if (WinningMove(x) && WinningMove(y)) return 0;
				if (WinningMove(x))
					return -1;
				if (WinningMove(y))
					return 1;

				bool xKill = WillKill(x);
				bool yKill = WillKill(y);

				if (xKill && !yKill)
					return -1;

				if (!xKill && yKill)
					return 1;

				bool xDie = WillDieAfter(x);
				bool yDie = WillDieAfter(y);

				if (xDie && !yDie)
					return 1;

				if (!xDie && yDie)
					return -1;

				return -Dx()*(x.ex - y.ex);
			});
		return moves.First();
	}

	GameMove GravityMove(List<GameMove> moves)
	{
		return moves.OrderByDescending(m =>
			{
				double res = 0;
				int b = -1;
				for (int x = m.ex; InBoard(x, m.ey) ; x += Dx())
				{
					b++;
					for (int dy = -b; dy <= b; dy++)
					{
						int y =  m.ey + dy;
						if (InBoard(x, y))
						{
							if (board[x, y] != currentColor && board[x, y] != Cell.EMPTY)
							{
								double r = Math.Sqrt(Math.Pow(m.ex - x + 0.001, 2) + Math.Pow(m.ey - y + 0.001, 2));
								res += k1/r + k2/Math.Pow(r, 2);
							}
						}
					}
				}
				return res;
			}).First();
	}

	GameMove FunnyDefensiveMove(List<GameMove> moves)
	{
		RandomShuffle(moves);

		moves.Sort((x, y) =>
		{
			if (WinningMove(x) && WinningMove(y)) return 0;
			if (WinningMove(x))
				return -1;
			if (WinningMove(y))
				return 1;

			bool xKill = WillKill(x);
			bool yKill = WillKill(y);

			if (xKill && !yKill)
				return -1;

			if (!xKill && yKill)
				return 1;

			if (!xKill && !yKill)
			{
				bool xDie = WillDieAfter(x);
				bool yDie = WillDieAfter(y);

				if (xDie && !yDie)
					return 1;

				if (!xDie && yDie)
					return -1;

				return -Dx() * (x.ex - y.ex);
			}
			else
			{
				return Dx() * (x.ex - y.ex);
			}
		});
		if (moves.Count < 2)
			return moves.Last();
		return moves[1];
	}

	GameMove DefensiveMove(List<GameMove> moves)
	{
		RandomShuffle(moves);
	
		moves.Sort((x, y) =>
		{
			if (WinningMove(x) && WinningMove(y)) return 0;
			if (WinningMove(x))
				return -1;
			if (WinningMove(y))
				return 1;

			bool xKill = WillKill(x);
			bool yKill = WillKill(y);

			if (xKill && !yKill)
				return -1;

			if (!xKill && yKill)
				return 1;

			if (!xKill && !yKill)
			{
				bool xDie = WillDieAfter(x);
				bool yDie = WillDieAfter(y);

				if (xDie && !yDie)
					return 1;

				if (!xDie && yDie)
					return -1;

				return -Dx() * (x.ex - y.ex);
			}
			else
			{
				return Dx() * (x.ex - y.ex);
			}
		});
		return moves.First();
	}

	static GameMove Invert(GameMove move)
	{
		var res = new GameMove(7 - move.sx, 7 - move.sy, 7 - move.ex, 7 - move.ey);
		return res;
	}

	Func<List<GameMove>, GameMove> KlinKlinom(Func<List<GameMove>, GameMove> f)
	{
		return ms =>
			{
				if (movesDone == 0)
				{
					var move = GameMove.Parse("c2c3");
					if (currentColor != Cell.WHITE)
						move = Invert(move);					
					return move;
				}
				if (movesDone == 1)
				{
					var move = GameMove.Parse("f2f3");
					if (currentColor != Cell.WHITE)
						move = Invert(move);
					return move;
				}

				return f(ms);
			};
	}
	int movesDone = 0;

	GameMove RandomMove(List<GameMove> moves)
	{
		return moves[random.Next(moves.Count)];
	}

	private List<GameMove> GetMoves()
	{
		List<GameMove> moves = new List<GameMove>();
		for (int sx = 0; sx < BOARD_SIZE; sx++)
		{
			for (int sy = 0; sy < BOARD_SIZE; sy++)
			{
				if (board[sx, sy] == currentColor)
				{
					for (int dy = -1; dy <= 1; dy++)
					{
						int ex = sx + (currentColor == Cell.WHITE ? 1 : -1);
						int ey = sy + dy;
						if ((ex >= 0 && ex < BOARD_SIZE && ey >= 0 && ey < BOARD_SIZE) &&
						   (dy != 0 && board[ex, ey] != currentColor || board[ex, ey] == Cell.EMPTY))
							moves.Add(new GameMove(sx, sy, ex, ey));
					}
				}
			}
		}
		return moves;
	}

	private readonly Random random;
	private readonly Cell[,] board;
	private Cell currentColor;
	private const int BOARD_SIZE = 8;
	Func<BlockBot, Func<List<GameMove>, GameMove>> f;
	double k1 = 0, k2 = 1;

	private enum Cell
	{
		EMPTY,
		WHITE,
		BLACK
	}

	public class GameMove
	{
		public GameMove(int sx, int sy, int ex, int ey)
		{
			this.sx = sx;
			this.sy = sy;
			this.ex = ex;
			this.ey = ey;
		}

		public static GameMove Parse(string move)
		{
			return new GameMove(move[1] - '1'
				, move[0] - 'a', move[3] - '1', move[2] - 'a');
		}

		public override string ToString()
		{
			return string.Format("{0}{1}{2}{3}", (char)(sy + 'a'), sx + 1, (char)(ey + 'a'), ex + 1);
		}

		public readonly int sx;
		public readonly int sy;
		public readonly int ex;
		public readonly int ey;
	}
}
