#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cassert>
#include <tuple>
#include <bitset>
#define mp make_pair
#define pb push_back
#define NAME "robots"
#define mt make_tuple
#define y1 y1_123

using namespace std;

typedef long long ll;
typedef long double ld;

const int nmax = 1000 + 10;
const ld pi = acos(-1.0);
const int mod = 1000 * 1000 * 1000 + 7;
const int inf = 1000 * 1000 * 1000;
const ll infl = 1000ll * 1000 * 1000 * 1000 * 1000 * 1000;

struct point {
	int x, y;
	point(){}
	point(int X, int Y) {
		x = X;
		y = Y;
	}
};

point operator + (point a, point b) {
	return point(a.x + b.x, a.y + b.y);
}

bool operator == (point a, point b) {
	return a.x == b.x && a.y == b.y;
}

int color = 1;
vector<point> now, topsort;
int sz[nmax * nmax];
int onc[nmax][nmax], used[nmax][nmax], is[nmax][nmax], col[nmax][nmax], enter[nmax][nmax], dist[nmax][nmax];
int index[nmax][nmax];
vector<point> li[nmax * nmax];
point go[nmax][nmax];
vector<pair<point, int> > answer;

void dfs(point v) {
	now.pb(v);
	used[v.x][v.y] = 1;
	point nv = v + go[v.x][v.y];
	if (used[nv.x][nv.y] == 1) {
		int cnt = 0;
		for (int j = (int)now.size() - 1; j >= 0; j--) {
			onc[now[j].x][now[j].y] = color;
			cnt++;
			if (now[j] == nv) {
				break;
			}
		}
		sz[color++] = cnt;
	} else if (!used[nv.x][nv.y]) {
		dfs(nv);
		now.pop_back();
	}
	topsort.pb(v);
	used[v.x][v.y] = 2;
}

void dfsa(point v, int top = 0) {
	used[v.x][v.y] = true;
	index[v.x][v.y] = top;
	point nv = v + go[v.x][v.y];
	if (!used[nv.x][nv.y]) {
		dfsa(nv, top + 1);
	}
}

int n, m, g;
string s;

int main() {
	freopen(NAME".in", "r", stdin); freopen(NAME".out", "w", stdout);
	cin >> n >> m >> g;
	getline(cin, s);
	for (int i = 0; i < n; i++) {
		getline(cin, s);
		for (int j = 0; j < m; j++) {
			if (s[j] == 'E' || s[j] == 'W' || s[j] == 'S' || s[j] == 'N') {
				is[i][j] = 1;
				s[j] = s[j] - 'A' + 'a';
			}
		}
		for (int j = 0; j < m; j++) {
			if (s[j] == 'n') {
				go[i][j] = point(-1, 0);
			} else if (s[j] == 'e') {
				go[i][j] = point(0, 1);
			} else if (s[j] == 's') {
				go[i][j] = point(1, 0);
			} else {
				go[i][j] = point(0, -1);
			}
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (!used[i][j]) {
				dfs(point(i, j));
			}
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			used[i][j] = 0;
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (!onc[i][j] || used[i][j]) {
				continue;
			}
			dfsa(point(i, j), 0);
		}
	}
	for (auto v : topsort) {
		if (onc[v.x][v.y]) {
			enter[v.x][v.y] = index[v.x][v.y];
			col[v.x][v.y] = onc[v.x][v.y];
			if (is[v.x][v.y]) {
				li[col[v.x][v.y]].pb(v);
       	 	}	
			continue;
		}
		point nv = v + go[v.x][v.y];
		col[v.x][v.y] = col[nv.x][nv.y];
		if (is[v.x][v.y]) {
			li[col[v.x][v.y]].pb(v);
        }
		dist[v.x][v.y] = dist[nv.x][nv.y] + 1;
		enter[v.x][v.y] = enter[nv.x][nv.y];
	}
	for (int i = 0; i < color; i++) {
		for (int j = 0; j < min((int)li[i].size(), sz[i]); j++) {
			//cerr << dist[li[i][j].x][li[i][j].y] << " " << enter[li[i][j].x][li[i][j].y] << " " << index[li[i][j].x][li[i][j].y] << endl;
			int tim = enter[li[i][j].x][li[i][j].y] - j;
			if (tim < 0) {
				tim += sz[i];
			}
			int di = dist[li[i][j].x][li[i][j].y];
			int add = tim - (di % sz[i]);
			if (add < 0) {
				add += sz[i];
			}
			answer.pb(mp(li[i][j], di + add));
		}
	}
	cout << answer.size() << endl;
	if (g) {
		for (auto v : answer) {
			cout << v.first.x + 1 << " " << v.first.y + 1 << " " << v.second << endl;
		}
	}
}