#include <bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(int i=a;i<b;i++)

enum { UP = 0, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT };
int dx[8] = { 0,1,1,1,0,-1,-1,-1 };
int dy[8] = { -1,-1,0,1,1,1,0,-1 };

#define INF INT_MAX/2
typedef tuple<int, int, int, int> Node;
typedef pair<Node, int> pii;
typedef tuple<Node, Node, int> pnni;

struct Comp {
	bool operator() (pnni a, pnni b) {
		int aa = get<2>(a);
		int bb = get<2>(b);
		return aa > bb;
	}
};

int main()
{
	int H, W;
	cin >> H >> W;

	vector< vector<char> > S(H+2, vector<char>(W+2, '#'));
	rep(y, 1, H + 1)
	{
		string s; cin >> s;
		rep(x, 1, W + 1) S[y][x] = s[x - 1];
	}

	map<Node, int> dist;
	map<Node, Node> done;
	priority_queue<pnni, vector<pnni>, Comp> que;

	rep(y, 0, H+2) rep(x, 0, W+2)
	{
		if (S[y][x] == '#') continue;
		if (S[y][x] == '.') continue;
		if (S[y][x] == 'G') continue;

		int d;
		switch (S[y][x])
		{
		case '^': d = 0; break;
		case '>': d = 2; break;
		case 'v': d = 4; break;
		case '<': d = 6; break;
		}

		rep(h, 0, 4)
		{
			int xx = x + dx[(d + h) % 8];
			int yy = y + dy[(d + h) % 8];
			if (S[yy][xx] == '#')
			{
				Node s = Node(x, y, d, h);
				dist[s] = 1;
				que.push(pnni(s, Node(-1, -1, -1, -1), 1));
			}
		}
	}

	while (!que.empty())
	{
		pnni p = que.top(); que.pop();
		Node to = get<0>(p);
		Node from = get<1>(p);
		int cost = get<2>(p);
		if (done.find(to) != done.end()) continue;
		done[to] = from;

		int x = get<0>(to);
		int y = get<1>(to);
		int d = get<2>(to);
		int h = get<3>(to);

		if (S[y][x] == 'G')
		{
			set<Node> ans;
			Node n = to;
			while (0 <= get<0>(n))
			{
				ans.insert(Node(get<0>(n), get<1>(n), 0, 0));
				n = done[n];
			}
			cout << ans.size() << endl;
			return 0;
		}

		// ??????
		while(1){
			if (h == 3) break;

			int xx = x + dx[d];
			int yy = y + dy[d];
			if (S[yy][xx] == '#') break;

			Node next(xx, yy, d, h + 1);

			if (dist.find(next) == dist.end()) dist[next] = INF;
			int newcost = cost + 1;
			if (newcost < dist[next])
			{
				dist[next] = newcost;
				que.push(pnni(next, to, newcost));
			}

			break;
		}

		// 90??????????????¢
		while (1)
		{
			if (h < 2) break;

			Node next(x, y, (d + 2) % 8, h - 2);

			if (dist.find(next) == dist.end()) dist[next] = INF;
			int newcost = cost;
			if (newcost < dist[next])
			{
				dist[next] = newcost;
				que.push(pnni(next, to, newcost));
			}

			break;
		}

		// 90??????????????¢
		while (1)
		{
			if (1 < h) break;

			Node next(x, y, (d + 6) % 8, h + 2);

			if (dist.find(next) == dist.end()) dist[next] = INF;
			int newcost = cost;
			if (newcost < dist[next])
			{
				dist[next] = newcost;
				que.push(pnni(next, to, newcost));
			}

			break;
		}

		// 0
		while (1)
		{
			if (h != 0) break;

			int xx = x + dx[(d + h + 2) % 8];
			int yy = y + dy[(d + h + 2) % 8];
			if (S[yy][xx] == '#')
			{
				Node next(x, y, d, (h + 2) % 8);

				if (dist.find(next) == dist.end()) dist[next] = INF;
				int newcost = cost;
				if (newcost < dist[next])
				{
					dist[next] = newcost;
					que.push(pnni(next, to, newcost));
				}
			}
			else
			{
				int xxx = x + dx[(d + h + 1) % 8];
				int yyy = y + dy[(d + h + 1) % 8];
				if (S[yyy][xxx] != '#') break;

				Node next(x, y, d, (h + 1) % 8);

				if (dist.find(next) == dist.end()) dist[next] = INF;
				int newcost = cost;
				if (newcost < dist[next])
				{
					dist[next] = newcost;
					que.push(pnni(next, to, newcost));
				}
			}

			break;
		}

		// 1
		while (1)
		{
			if (h != 1) break;

			int xx = x + dx[(d + h - 1 + 8) % 8];
			int yy = y + dy[(d + h - 1 + 8) % 8];
			if (S[yy][xx] == '#')
			{
				Node next(x, y, d, (h - 1 + 8) % 8);

				if (dist.find(next) == dist.end()) dist[next] = INF;
				int newcost = cost;
				if (newcost < dist[next])
				{
					dist[next] = newcost;
					que.push(pnni(next, to, newcost));
				}
			}
			
			xx = x + dx[(d + h + 1 + 8) % 8];
			yy = y + dy[(d + h + 1 + 8) % 8];
			if (S[yy][xx] == '#')
			{
				Node next(x, y, d, (h + 1 + 8) % 8);

				if (dist.find(next) == dist.end()) dist[next] = INF;
				int newcost = cost;
				if (newcost < dist[next])
				{
					dist[next] = newcost;
					que.push(pnni(next, to, newcost));
				}
			}

			break;
		}

		// 2
		while (1)
		{
			if (h != 2) break;

			int xx = x + dx[(d + h - 2 + 8) % 8];
			int yy = y + dy[(d + h - 2 + 8) % 8];
			if (S[yy][xx] == '#')
			{
				Node next(x, y, d, (h - 2 + 8) % 8);

				if (dist.find(next) == dist.end()) dist[next] = INF;
				int newcost = cost;
				if (newcost < dist[next])
				{
					dist[next] = newcost;
					que.push(pnni(next, to, newcost));
				}
			}
			else
			{
				xx = x + dx[(d + h - 1 + 8) % 8];
				yy = y + dy[(d + h - 1 + 8) % 8];
				if (S[yy][xx] == '#')
				{
					Node next(x, y, d, (h - 1 + 8) % 8);

					if (dist.find(next) == dist.end()) dist[next] = INF;
					int newcost = cost;
					if (newcost < dist[next])
					{
						dist[next] = newcost;
						que.push(pnni(next, to, newcost));
					}
				}
			}

			xx = x + dx[(d + h + 1 + 8) % 8];
			yy = y + dy[(d + h + 1 + 8) % 8];
			if (S[yy][xx] == '#')
			{
				Node next(x, y, d, (h + 1 + 8) % 8);

				if (dist.find(next) == dist.end()) dist[next] = INF;
				int newcost = cost;
				if (newcost < dist[next])
				{
					dist[next] = newcost;
					que.push(pnni(next, to, newcost));
				}
			}

			break;
		}


		// 3
		while (1)
		{
			if (h != 2) break;

			int xx = x + dx[(d + h + 1 + 8) % 8];
			int yy = y + dy[(d + h + 1 + 8) % 8];
			if (S[yy][xx] == '#')
			{
				Node next(x, y, d, (h + 1 + 8) % 8);

				if (dist.find(next) == dist.end()) dist[next] = INF;
				int newcost = cost;
				if (newcost < dist[next])
				{
					dist[next] = newcost;
					que.push(pnni(next, to, newcost));
				}
			}

			break;
		}
	}

	cout << -1 << endl;
}

Measured memory_bytes: 5400