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;

int main() {
	int H, W, dx[4] = { 1, -1, 0, 0 }, dy[4] = { 0, 0, 1, -1 };
	cin >> H >> W;
	vector<string> S(H);
	for (int i = 0; i < H; i++) cin >> S[i];
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (i % 2 == 0 && j % 2 == 0) {
				if ((i + j) % 4 == 0) {
					if (S[i][j] != '6') {
						S[i][j] = '#';
						for (int k = 0; k < 4; k++) {
							int nx = i + dx[k], ny = j + dy[k];
							if (0 <= nx && nx < H && 0 <= ny && ny < W) {
								S[nx][ny] = '#';
							}
						}
					}
				}
				else {
					if (S[i][j] != '1') {
						S[i][j] = '#';
						for (int k = 0; k < 4; k++) {
							int nx = i + dx[k], ny = j + dy[k];
							if (0 <= nx && nx < H && 0 <= ny && ny < W) {
								S[nx][ny] = '#';
							}
						}
					}
				}
			}
		}
	}
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (i % 2 != 0 || j % 2 != 0) continue;
			char v[4];
			if (i % 4 == 0 && j % 4 == 0) v[0] = '2', v[1] = '5', v[2] = '3', v[3] = '4';
			if (i % 4 == 0 && j % 4 == 2) v[0] = '2', v[1] = '5', v[2] = '4', v[3] = '3';
			if (i % 4 == 2 && j % 4 == 0) v[0] = '5', v[1] = '2', v[2] = '3', v[3] = '4';
			if (i % 4 == 2 && j % 4 == 2) v[0] = '5', v[1] = '2', v[2] = '4', v[3] = '3';
			for (int k = 0; k < 4; k++) {
				int nx = i + dx[k], ny = j + dy[k];
				if (0 <= nx && nx < H && 0 <= ny && ny < W) {
					if (S[nx][ny] != v[k]) S[nx][ny] = '#';
				}
			}
		}
	}
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (S[i][j] != '#') S[i][j] = '.';
		}
	}
	queue<pair<int, int> > Q;
	bool V[100][100] = {};
	V[0][0] = true;
	Q.push({ 0, 0 });
	while (!Q.empty()) {
		pair<int, int> P = Q.front();
		Q.pop();
		for (int i = 0; i < 4; i++) {
			int nx = P.first + dx[i], ny = P.second + dy[i];
			if (0 <= nx && nx < H && 0 <= ny && ny < W) {
				if (S[nx][ny] == '.' && !V[nx][ny]) {
					Q.push({ nx, ny });
					V[nx][ny] = true;
				}
			}
		}
	}
	cout << (V[H - 1][W - 1] ? "YES" : "NO") << endl;
}

C++: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<functional>
#include<assert.h>
#include<numeric>
using namespace std;
#define REP(i,m,n) for(int i=(int)(m) ; i < (int) (n) ; ++i )
#define rep(i,n) REP(i,0,n)
using ll = long long;
constexpr int inf=1e9+7;
constexpr ll longinf=1LL<<60 ;
constexpr ll mod=1e9+7 ;


int dp[111][111];


struct UnionFind{
   vector<int> par;
   UnionFind(int n):par(n,-1){}
   int find(int x){
       if(par[x]<0)return x;
       return par[x]=find(par[x]);
   }
   bool unite(int x,int y){
       x=find(x);
       y=find(y);
       if(x==y)return false;
       if(par[x]>par[y]){
           par[y]+=par[x];
           par[x]=y;
       }
       else{
           par[x]+=par[y];
           par[y]=x;
       }
       return true;
   }

   bool same(int x,int y){
       return find(x)==find(y);
   }
   int size(int x){
       return -par[find(x)];
   }
};
int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int h,w;
    cin>>h>>w;
    string s[h];
    rep(i,h)cin>>s[i];
    rep(i,h)rep(j,w){
        if(i%2==0 && j%2 ==0){
            if((i-j)%4==0 && s[i][j]!='6')s[i][j]='#';
            if((i-j)%4!=0 && s[i][j]!='1')s[i][j]='#';
        }
        if(i%2==0 && j%2 != 0){
            if(j%4 == 1 && s[i][j]!='3')s[i][j]='#';
            if(j%4 == 3 && s[i][j]!='4')s[i][j]='#';
        }
        if(i%2==1 && j%2 == 0){
            if(i%4 == 1 && s[i][j]!='2')s[i][j]='#';
            if(i%4 == 3 && s[i][j]!='5')s[i][j]='#';
        }
    }
    UnionFind uf(h*w);
    rep(i,h)rep(j,w-1){
        if(s[i][j]!='#'&&s[i][j+1]!='#')uf.unite(i*w+j,i*w+j+1);
    }
    rep(i,h-1)rep(j,w){
        if(s[i][j]!='#'&&s[i+1][j]!='#')uf.unite(i*w+j,i*w+j+w);
    }
    if(uf.same(0,h*w-1))cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    return 0;
}