#include <bits/stdc++.h>
#define point pair <int, int>
#define x first
#define y second
#define pb push_back
#define For(i, a, b) for(int i = a; i < b; ++i)
#define Out(i, a, b) for(int i = a - 1; i >= b; --i)
#define files(FileName) write(FileName); read(FileName)
#define read(FileName) freopen((FileName + ".in").c_str(), "r", stdin)
#define write(FileName) freopen((FileName + ".out").c_str(), "w", stdout)

using namespace std;

string FileName = "robots";

typedef long long base;

int n, m, q;
int edge[1001][1001];
vector <point> redge[1001][1001];
int dx[4] = {-1, 1, 0, 0};
bool robot[1001][1001];
int dy[4] = {0, 0, 1, -1};
bool used[1001][1001];
int color[1001][1001];
vector <pair <point, int>> ans;

point Next(point a) {
    return {a.x + dx[edge[a.x][a.y]], a.y + dy[edge[a.x][a.y]]};
}

point dfs(point v) {
    if (used[v.x][v.y]) return v;
    used[v.x][v.y] = true;
    return dfs(Next(v));
}

void rdfs(point v, vector <point> &all) {
    used[v.x][v.y] = true;
    if (robot[v.x][v.y]) all.pb(v);
    for(auto u: redge[v.x][v.y]) {
        if (!color[u.x][u.y]) {
            color[u.x][u.y] = color[v.x][v.y] + 1;
            rdfs(u, all);
        }
    }
}

int Dist(int a, int b, int k) {
    if (b < a) b += k;
    return b - a;
}

int main() {
    ios::sync_with_stdio(false);
    files(FileName);
    cin >> n >> m >> q;
    For(i, 0, n) {
        string s; cin >> s;
        For(j, 0, m) {
            if (s[j] == 'N') {edge[i][j] = 0; robot[i][j] = true;}
            if (s[j] == 'S') {edge[i][j] = 1; robot[i][j] = true;}
            if (s[j] == 'E') {edge[i][j] = 2; robot[i][j] = true;}
            if (s[j] == 'W') {edge[i][j] = 3; robot[i][j] = true;}
            if (s[j] == 'n') edge[i][j] = 0;
            if (s[j] == 's') edge[i][j] = 1;
            if (s[j] == 'e') edge[i][j] = 2;
            if (s[j] == 'w') edge[i][j] = 3;
            point N = Next({i, j});
            redge[N.x][N.y].pb({i, j});
        }
    }
    int cnt = 0;
    For(i, 0, n) {
        For(j, 0, m) {
            if (used[i][j]) continue;
            point v, u; v = u = dfs({i, j});
            vector <point> circle;
            circle.pb(u);
            while (Next(u) != v) {
                u = Next(u);
                circle.pb(u);
            }
            int S = circle.size();
            bool T[S];
            int DSU[S];
            vector <point> tree[S];
            for(auto p: circle) color[p.x][p.y] = 1;
            For(k, 0, S) {
                T[k] = false; DSU[k] = (k + 1) % S;
                rdfs(circle[k], tree[k]);
            }
            int cnt = S;
            For(k, 0, S) {
                for(auto u: tree[k]) {
                    if (!cnt) break;
                    int TimeOff = color[u.x][u.y] - 1;
                    if (TimeOff == 0) {
                        T[k] = true;
                        ans.pb({u, 0});
                    } else {
                        int d1, d2;
                        d1 = d2 = TimeOff % S;
                        while (T[DSU[d1]]) {
                            d1 = DSU[d1];
                        }
                        while (T[DSU[d2]]) {
                            d2 = DSU[d2];
                            DSU[d2] = d1;
                        }
                        T[d1] = true;
                        TimeOff += Dist(TimeOff % S, d1, S);
                        ans.pb({u, TimeOff});
                    }
                    --cnt;
                }
            }
        }
    }
    cout << ans.size() << endl;
    if (q) {
        For(i, 0, ans.size()) {
            cout << ans[i].x.x + 1 << ' ' << ans[i].x.y + 1 << ' ' << ans[i].y + 1 << endl;
        }
    }
}
