#define _USE_MATH_DEFINES
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <cstdio>
#include <complex>
#include <numeric>
#include <string.h>
#include <random>
#include <cmath>
#define rep(i,n) for (int i = 0; i < (int)n; i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<ll, ll> pl;
typedef pair<pl, ll> pll;
double PI = 3.141592653589793238462643383279;
const double EPS = 1e-9;
const ll MOD = 998244353;
const int inf = 1 << 30;
const ll linf = 1LL << 60;

struct UF {
    vector<int> par, rank, si;

    void init(int n){
        par.assign(n, 0);
        rank.assign(n, 0);
        si.assign(n, 1);
        iota(par.begin(), par.end(), 0);
    }

    int find(int x){
        if(par[x] == x) return x;
        else return par[x] = find(par[x]);
    }

    void unite(int x, int y){
        x = find(x);
        y = find(y);
        if(x == y) return;
        
        if(rank[x] < rank[y]){
            par[x] = y;
            si[y] += si[x];
        } else{
            par[y] = x;
            if(rank[x] == rank[y]) rank[x]++;
            si[x] += si[y];
        }
    }

    bool same(int x, int y){
        return find(x) == find(y);
    }
};


int N;
char A[1500][1500];
bool saw[1500][1500];
int g[1500][1500];
UF uf;

ll solve (int hoge) {
    memset(saw, 0, sizeof(saw));
    memset(g, 0, sizeof(g));
    int n = 0;
    rep(i,N-1) {
        rep(j,N-1) {
            if (((i+j)&1) == hoge) continue;
            if (saw[i][j]) continue;
            char c = '?';
            int w = 4;
            saw[i][j] = true;
            if (i == j) w--;
            saw[j][i] = true;
            if (N-2-i == i && N-2-j == j) w--;
            saw[N-2-i][N-2-j] = true;
            if (N-2-i == j && N-2-j == i) w--;
            if (w == 3) w = 2;
            saw[N-2-j][N-2-i] = true;
            if (A[i][j] != '?') c = A[i][j];
            if (A[j][i] != '?') {
                if (c != '?' && A[j][i] != c) {
                    return -1;
                }
                c = A[j][i];
            }
            if (A[N-2-i][N-2-j] != '?') {
                if (c != '?' && A[N-2-i][N-2-j] != c) {
                    return -1;
                }
                c = A[N-2-i][N-2-j];
            }
            if (A[N-2-j][N-2-i] != '?') {
                if (c != '?' && A[N-2-j][N-2-i] != c) {
                    return -1;
                }
                c = A[N-2-j][N-2-i];
            }
            if (c == '?') { g[(j-i)/2][(i+j)/2+1] = 2; g[(i+j)/2+1][(j-i)/2] = 2; } else
            if (c == 'o') { g[(j-i)/2][(i+j)/2+1] = 0; g[(i+j)/2+1][(j-i)/2] = 0; } else
            if (c == 'x') { g[(j-i)/2][(i+j)/2+1] = 1; g[(i+j)/2+1][(j-i)/2] = 1; }
            n = max(n, (i+j)/2+2);
        }
    }
    if (n%2 == 0) {
        ll ret = 1;
        rep(i,n) {
            for (int j = i+1; j < n; j++) {
                if (g[i][j] >= 2) ret = ret * g[i][j] % MOD;
            }
        }
        return ret;
    }
    ll ret = 1;
    uf.init(n);
    rep(i,n) {
        for (int j = i+1; j < n; j++) {
            if (g[i][j] >= 2) {
                if (uf.same(i,j)) ret = ret * g[i][j] % MOD;
                uf.unite(i, j);
            }
        }
    }
    vector<int> out(n, 0);
    rep(i,n) {
        int x = uf.find(i);
        rep(j,n) {
            if (i == j) continue;
            if (g[i][j] == 0) {
                out[x]++;
            }
        }
    }
    rep(i,n) {
        if (out[i]%2) {
            return -1;
        }
    }
    return ret;
}

int main() {
    cin >> N;
    rep(i,N-1) rep(j,N-1) cin >> A[i][j];
    ll ans = solve(0);
    if (ans == -1) {
        cout << 0 << endl;
        return 0;
    }
    ll ans2 = solve(1);
    if (ans2 == -1) {
        cout << 0 << endl;
        return 0;
    }
    cout << ans*ans2%MOD << endl;
}

Measured memory_bytes: 13440