#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 20000
#define HEAD MOD
#define FOOT MOD+1

typedef pair<int,int> Point;

enum Type{
	TATE,
	YOKO,
};

struct Info{
	int row,col;
	Type dir;
};

struct Data{
	Data(int arg_row,int arg_col,int arg_index,int arg_which){
		row = arg_row;
		col = arg_col;
		index = arg_index;
		which = arg_which;
	}

	int row,col,index,which;
};


map<Point,int> MAP;
Info info[NUM];
vector<int> Group[NUM];

int near_row[4] = {1,0,0,-1},near_col[4] = {0,-1,1,0};
int diff_row[2][6] = {{2,1,1,0,0,-1},{-1,-1,0,0,1,1}},diff_col[2][6] = {{0,-1,1,-1,1,0},{0,1,-1,2,0,1}};

int N;
int boss[NUM],height[NUM];

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	//高さが高い方に吸収する
	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

void init(){
	for(int i = 0; i < N; i++){
		boss[i] = i;
		height[i] = 0;
	}
}

bool check(int group_id){

	map<Point,int> ROOM;
	queue<Data> Q;

	ROOM[Point(info[group_id].row,info[group_id].col)] = HEAD;
	Q.push(Data(info[group_id].row,info[group_id].col,group_id,HEAD));

	bool FLG = true;

	int adj_row,adj_col,adj_index;

	while(!Q.empty()){

		for(int i = 0; i < 4; i++){
			adj_row = Q.front().row+near_row[i];
			adj_col = Q.front().col+near_col[i];

			auto at = MAP.find(Point(adj_row,adj_col));
			if(at == MAP.end())continue;

			adj_index = MAP[Point(adj_row,adj_col)];

			if(adj_index != Q.front().index){

				at = ROOM.find(Point(adj_row,adj_col));

				if(at == ROOM.end()){
					if(Q.front().which == HEAD){
						ROOM[Point(adj_row,adj_col)] = HEAD;
						Q.push(Data(adj_row,adj_col,adj_index,HEAD));
					}else{
						ROOM[Point(adj_row,adj_col)] = FOOT;
						Q.push(Data(adj_row,adj_col,adj_index,FOOT));
					}
				}else{
					if((ROOM[Point(adj_row,adj_col)] == FOOT && Q.front().which == HEAD) ||
							(ROOM[Point(adj_row,adj_col)] == HEAD && Q.front().which == FOOT)){
						FLG = false;
						break;
					}
				}

			}else{
				at = ROOM.find(Point(adj_row,adj_col));

				if(at == ROOM.end()){
					if(Q.front().which == HEAD){
						ROOM[Point(adj_row,adj_col)] = FOOT;
						Q.push(Data(adj_row,adj_col,Q.front().index,FOOT));
					}else{
						ROOM[Point(adj_row,adj_col)] = HEAD;
						Q.push(Data(adj_row,adj_col,Q.front().index,HEAD));
					}
				}else{
					if(ROOM[Point(adj_row,adj_col)] == Q.front().which){
						FLG = false;
						break;
					}
				}
			}
		}

		if(!FLG)break;

		Q.pop();
	}

	if(FLG)return true;


	FLG = true;
	ROOM.clear();

	ROOM[Point(info[group_id].row,info[group_id].col)] = FOOT;
	Q.push(Data(info[group_id].row,info[group_id].col,group_id,FOOT));

	while(!Q.empty()){

		for(int i = 0; i < 4; i++){
			adj_row = Q.front().row+near_row[i];
			adj_col = Q.front().col+near_col[i];

			auto at = MAP.find(Point(adj_row,adj_col));
			if(at == MAP.end())continue;

			adj_index = MAP[Point(adj_row,adj_col)];

			if(adj_index != Q.front().index){

				at = ROOM.find(Point(adj_row,adj_col));

				if(at == ROOM.end()){
					if(Q.front().which == HEAD){
						ROOM[Point(adj_row,adj_col)] = HEAD;
						Q.push(Data(adj_row,adj_col,adj_index,HEAD));
					}else{
						ROOM[Point(adj_row,adj_col)] = FOOT;
						Q.push(Data(adj_row,adj_col,adj_index,FOOT));
					}
				}else{
					if((ROOM[Point(adj_row,adj_col)] == FOOT && Q.front().which == HEAD) ||
							(ROOM[Point(adj_row,adj_col)] == HEAD && Q.front().which == FOOT)){
						FLG = false;
						break;
					}
				}

			}else{
				at = ROOM.find(Point(adj_row,adj_col));

				if(at == ROOM.end()){
					if(Q.front().which == HEAD){
						ROOM[Point(adj_row,adj_col)] = FOOT;
						Q.push(Data(adj_row,adj_col,Q.front().index,FOOT));
					}else{
						ROOM[Point(adj_row,adj_col)] = HEAD;
						Q.push(Data(adj_row,adj_col,Q.front().index,HEAD));
					}
				}else{
					if(ROOM[Point(adj_row,adj_col)] == Q.front().which){
						FLG = false;
						break;
					}
				}
			}
		}

		if(!FLG)break;

		Q.pop();
	}


	return FLG;
}

void func(){

	MAP.clear();
	for(int i = 0; i < N; i++)Group[i].clear();

	init();

	char buf[2];

	for(int i = 0; i < N; i++){
		scanf("%d %d %s",&info[i].col,&info[i].row,buf);
		if(buf[0] == 'x'){
			info[i].dir = YOKO;
		}else{
			info[i].dir = TATE;
		}
		MAP[Point(info[i].row,info[i].col)] = i;
		if(info[i].dir == YOKO){
			MAP[Point(info[i].row,info[i].col+1)] = i;
		}else{
			MAP[Point(info[i].row+1,info[i].col)] = i;
		}
	}

	int adj_row,adj_col;
	for(int i = 0; i < N; i++){
		for(int k = 0; k < 6; k++){
			adj_row = info[i].row+diff_row[info[i].dir][k];
			adj_col = info[i].col+diff_col[info[i].dir][k];

			auto at = MAP.find(Point(adj_row,adj_col));
			if(at == MAP.end())continue;

			unite(i,MAP[Point(adj_row,adj_col)]);
		}
	}

	vector<int> BOSS;
	for(int i = 0; i < N; i++){
		Group[get_boss(i)].push_back(i);
		if(boss[i] == i){
			BOSS.push_back(i);
		}
	}

	for(int i = 0; i < BOSS.size(); i++){
		if(check(BOSS[i]) == false){
			printf("No\n");
			return;
		}
	}

	printf("Yes\n");
}

int main(){

	while(true){
		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}



Measured memory_bytes: 8956