#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 3000

enum DIR{
	North,
	East,
	South,
	West,
};

struct Info{
	int x,y;
	DIR dir;
};

struct Data{
	int index;
	DIR dir;
	bool exist,visited;
};

struct State{
	void set(int arg_y,int arg_x,DIR arg_dir){
		y = arg_y;
		x = arg_x;
		dir = arg_dir;
	}
	int x,y;
	DIR dir;
};

int N;
map<int,int> X_MAP,Y_MAP;
vector<int> Y,X;
int ADJ[NUM][4];
bool visited[NUM];
Info info[NUM];
Data data[NUM][NUM]; //座標圧縮した2次元フィールド

int main(){

	scanf("%d",&N);

	char buf[2];

	for(int i = 0; i < N; i++){
		scanf("%d %d %s",&info[i].x,&info[i].y,buf);
		X.push_back(info[i].x);
		Y.push_back(info[i].y);
		switch(buf[0]){
		case '^':
			info[i].dir = North;
			break;
		case '>':
			info[i].dir = East;
			break;
		case 'v':
			info[i].dir = South;
			break;
		case '<':
			info[i].dir = West;
			break;
		}
	}

	sort(X.begin(),X.end());
	sort(Y.begin(),Y.end());

	X.erase(unique(X.begin(),X.end()),X.end());
	Y.erase(unique(Y.begin(),Y.end()),Y.end());

	//座標圧縮
	for(int i = 0; i < X.size(); i++){
		X_MAP[X[i]] = i;
	}
	for(int i = 0; i < Y.size(); i++){
		Y_MAP[Y[i]] = i;
	}

	int size_X = (int)X.size(),size_Y = (int)Y.size();

	for(int i = 0; i < size_X; i++){
		for(int k = 0; k < size_Y; k++)data[i][k].exist = false;
	}

	//圧縮済座標上に力点を配置
	for(int i = 0; i < N; i++){
		for(int k = 0; k < 4; k++){
			ADJ[i][k] = -1; //隣接している力点のインデックス
		}

		data[Y_MAP[info[i].y]][X_MAP[info[i].x]].exist = true;
		data[Y_MAP[info[i].y]][X_MAP[info[i].x]].dir = info[i].dir;
		data[Y_MAP[info[i].y]][X_MAP[info[i].x]].index = i;
	}

	//隣接リストを作成する
	for(int row = 0; row < size_Y; row++){
		for(int col = 0; col < size_X; col++){
			if(data[row][col].exist == false)continue;

			//北
			for(int tmp_row = row-1; tmp_row >= 0; tmp_row--){
				if(data[tmp_row][col].exist){
					ADJ[data[row][col].index][North] = data[tmp_row][col].index;
					break;
				}
			}

			//東
			for(int tmp_col = col+1; tmp_col <= size_X-1; tmp_col++){
				if(data[row][tmp_col].exist){
					ADJ[data[row][col].index][East] = data[row][tmp_col].index;
					break;
				}
			}

			//南
			for(int tmp_row = row+1; tmp_row <= size_Y-1; tmp_row++){
				if(data[tmp_row][col].exist){
					ADJ[data[row][col].index][South] = data[tmp_row][col].index;
					break;
				}
			}
			//西
			for(int tmp_col = col-1; tmp_col >= 0; tmp_col--){
				if(data[row][tmp_col].exist){
					ADJ[data[row][col].index][West] = data[row][tmp_col].index;
					break;
				}
			}
		}
	}

	int ans = 0;
	int tmp_count,next_index;
	DIR dir;

	for(int start = 0; start < N; start++){
		for(int i = 0; i < N; i++)visited[i] = false;
		visited[start] = true;

		dir = info[start].dir;

		tmp_count = 1;
		next_index = start;

		while(true){

			switch(dir){
			case North:
				while(next_index != -1 && visited[next_index] == true){
					next_index = ADJ[next_index][North];
				}
				break;
			case East:
				while(next_index != -1 && visited[next_index] == true){
					next_index = ADJ[next_index][East];
				}
				break;
			case South:
				while(next_index != -1 && visited[next_index] == true){
					next_index = ADJ[next_index][South];
				}
				break;
			case West:
				while(next_index != -1 && visited[next_index] == true){
					next_index = ADJ[next_index][West];
				}
				break;
			}

			if(next_index == -1)break;

			dir = info[next_index].dir;
			visited[next_index] = true;

			tmp_count++;
		}

		ans = max(ans,tmp_count);
	}

	printf("%d\n",ans);

	return 0;
}



Measured memory_bytes: 35904