Go: package main

import "fmt"

var h, w int
var maze [][]byte

var visited [][]bool

type dice struct {
	top, bottom, right, left, up, down int
}

func move(d *dice, dir byte) {
	now := d.top
	switch dir {
	case 'N':
		d.top = d.down
		d.down = d.bottom
		d.bottom = d.up
		d.up = now
	case 'S':
		d.top = d.up
		d.up = d.bottom
		d.bottom = d.down
		d.down = now
	case 'W':
		d.top = d.right
		d.right = d.bottom
		d.bottom = d.left
		d.left = now
	case 'E':
		d.top = d.left
		d.left = d.bottom
		d.bottom = d.right
		d.right = now
	}
}

var dx = [4]int{1, -1, 0, 0}
var dy = [4]int{0, 0, 1, -1}

func dfs(x, y int, d *dice) bool {
	// fmt.Printf("dfs(%d,%d) en: dice.bottom=%d\n", x, y, d.bottom)
	visited[y][x] = true // (x,y)に到達した
	if (y == h-1) && (x == w-1) {
		return true
	}
	// 4方のマス目に進めるかどうかチェック
	for i := 0; i < 4; i++ {
		nx := x + dx[i]
		ny := y + dy[i]
		dir := []byte{'E', 'W', 'S', 'N'}
		dc := *d
		move(&dc, dir[i]) // 動かしてみる
		if 0 <= nx && nx < w && 0 <= ny && ny < h && maze[ny][nx] != '#' && !visited[ny][nx] && dc.bottom == int(maze[ny][nx]-'0') {
			// fmt.Printf("move dir %c, new bottom=%d, move to (nx, ny)=(%d,%d)\n", dir[i], dc.bottom, nx, ny)
			if dfs(nx, ny, &dc) {
				return true
			}
		} else {
			continue
		}
	}
	return false
}

func main() {
	fmt.Scan(&h, &w)
	maze = make([][]byte, h)
	visited = make([][]bool, h)
	for i := 0; i < h; i++ {
		visited[i] = make([]bool, w)
		maze[i] = make([]byte, w)
		fmt.Scan(&maze[i])
	}
	// fmt.Println("h", h, "w", w, "maze", maze)
	// visited[0][0] = true
	var d dice
	d.bottom = 6
	d.top = 1
	d.right = 3
	d.left = 4
	d.down = 2
	d.up = 5
	if dfs(0, 0, &d) {
		fmt.Println("YES")
	} else {
		fmt.Println("NO")
	}
}

C++: #include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
mt19937 mrand(random_device{}()); 
const ll mod=1000000007;
int rnd(int x) { return mrand() % x;}
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head

const int N=110;

set<VI> grid[N][N];
queue<VI> q;
char g[N][N];
int h,w;

// f,b,u,d,l,r
const int F=0,B=1,U=2,D=3,L=4,R=5;

void add(int x,int y,VI s) {
	if (grid[x][y].count(s)) return;
	grid[x][y].insert(s);
	s.pb(x); s.pb(y);
	q.push(s);
}

int main() {
	scanf("%d%d",&h,&w);
	rep(i,0,h) scanf("%s",g[i]);
	add(0,0,VI{2,5,1,6,4,3});
	while (!q.empty()) {
		auto v=q.front(); q.pop();
		VI d(v.begin(),v.begin()+6);
		int x=v[6],y=v[7];
		if (x==h-1&&y==w-1) { puts("YES"); return 0; }
		if (y<w-1&&g[x][y+1]!='#') {
			VI newd{d[F],d[B],d[L],d[R],d[D],d[U]};
			if (newd[D]==g[x][y+1]-'0') {
				add(x,y+1,newd);
			}
		}

		if (y>0&&g[x][y-1]!='#') {
			VI newd{d[F],d[B],d[R],d[L],d[U],d[D]};
			if (newd[D]==g[x][y-1]-'0') {
				add(x,y-1,newd);
			}
		}

		if (x<h-1&&g[x+1][y]!='#') {
			VI newd{d[U],d[D],d[B],d[F],d[L],d[R]};
			if (newd[D]==g[x+1][y]-'0') {
				add(x+1,y,newd);
			}
		}

		if (x>0&&g[x-1][y]!='#') {
			VI newd{d[D],d[U],d[F],d[B],d[L],d[R]};
			if (newd[D]==g[x-1][y]-'0') {
				add(x-1,y,newd);
			}
		}
	}
	puts("NO");
}

C++: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> l_l;
typedef pair<int, int> i_i;
template<class T>
inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return true;
    }
    return false;
}

const long long INF = 1e18;
//const ll mod = 1000000007;
int H, W;
bool field[105][105];
string S[105];
bool reach[105][105];


int main() {
    cin >> H >> W;
    for(int h = 0; h < H; h++) {
        cin >> S[h];
    }
    for(int h = 0; h < H; h++) {
        for(int w = 0; w < W; w++) {
            if((h&1) & (w & 1)) continue;
            if(h % 2 == 0 and w % 2 == 0) {
                if((h + w) % 4 == 0) {
                    if(S[h][w] == '6') field[h][w] = true;
                } else {
                    if(S[h][w] == '1') field[h][w] = true;
                }
            } else {
                if(h % 4 == 1) {
                    if(S[h][w] == '2') field[h][w] = true;
                }
                if(h % 4 == 3) {
                    if(S[h][w] == '5') field[h][w] = true;
                }
                if(w % 4 == 1) {
                    if(S[h][w] == '3') field[h][w] = true;
                }
                if(w % 4 == 3) {
                    if(S[h][w] == '4') field[h][w] = true;
                }
            }
        }
    }
    reach[0][0] = true;
    queue<i_i> que;
    que.push({0, 0});
    int dh[4] = {1, -1, 0, 0};
    int dw[4] = {0, 0, 1, -1};
    while(!que.empty()) {
        auto now = que.front();
        que.pop();
        int nowh = now.first;
        int noww = now.second;
        for(int i = 0; i < 4; i++) {
            int newh = nowh + dh[i];
            int neww = noww + dw[i];
            if(newh < 0 or newh >= H) continue;
            if(neww < 0 or neww >= W) continue;
            if(!field[newh][neww]) continue;
            if(reach[newh][neww]) continue;
            que.push({newh, neww});
            reach[newh][neww] = true;
        }
    }
    if(reach[H-1][W-1]) cout << "YES" << endl;
    else cout << "NO" << endl;
    return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;

struct dsu {
  int cc;
  vector<int> p, sz;
  dsu(int n = 0) : cc(n), p(n, -1), sz(n, 1) {}
  int root(int v) const {
    while (p[v] != -1) v = p[v];
    return v;
  }
  bool unite(int u, int v) {
    u = root(u), v = root(v);
    if (u == v) return false;
    --cc;
    if (sz[u] < sz[v]) swap(u, v);
    p[v] = u;
    sz[u] += sz[v];
    return true;
  }
  bool same(int u, int v) const { return root(u) == root(v); }
  int size(int v) const { return sz[root(v)]; }
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int h, w;
  cin >> h >> w;
  vector<string> s(h);
  for (auto&& e : s) {
    cin >> e;
  }
  dsu d(h * w);
  auto $ = [&](int i, int j) {
    return i * w + j;
  };
  vector<string> t{"6314", "2.2.", "1364", "5.5."};
  auto chk = [&](int i, int j) {
    return s[i][j] == t[i % 4][j % 4];
  };
  for (int i = 0; i < h; ++i) {
    for (int j = 0; j < w; ++j) {
      if (i + 1 < h and chk(i, j) and chk(i + 1, j)) {
        d.unite($(i, j), $(i + 1, j));
      }
      if (j + 1 < w and chk(i, j) and chk(i, j + 1)) {
        d.unite($(i, j), $(i, j + 1));
      }
    }
  }
  if (d.same($(0, 0), $(h - 1, w - 1))) {
    cout << "YES\n";
  } else {
    cout << "NO\n";
  }
}