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<iostream>
#include<string>
#include<iomanip>
#include<cmath>
#include<vector>
#include<algorithm>
#include<utility>

using namespace std;

#define int long long
#define endl "\n"

constexpr long long INF = (long long)1e18;
constexpr long long MOD = 1'000'000'007; 

struct fast_io {
	fast_io(){
		std::cin.tie(nullptr);
		std::ios::sync_with_stdio(false);
	};
// } fio;
} ;

class union_find
{
	int  _setnum;
	vector<int> par, nume;
public:
	union_find(){
	}
	
	union_find(int x){
		par.resize(x);
		nume.resize(x);
		init();
	}
	
	~union_find(){
		//
		
	}
	
	void clear(){
		_setnum = 0;
		par.clear();
		nume.clear();
	}
	
	void init(){
		_setnum = par.size();
		for(int i = 0; i < par.size(); i++){
			par[i] = i;
			nume[i] = 1;
		}
	}
	
	void resize(int x){
		
		par.resize(x);
		nume.resize(x);
		init();
	}

	int find(int x){
		return par[x] == x ? x : par[x] = find(par[x]);
	}

	void unite(int x, int y){
		x = find(x);
		y = find(y);
	
		if(x == y)return;
		
		_setnum--;
		
		if(nume[x] > nume[y]) std::swap(x,y);
		
		par[x] = y;
		nume[y] += nume[x];
	}
	
	bool same(int x, int y){
		return find(x) == find(y);
	}
	
	int numel(int x){
		return nume[find(x)];
	}
	
	int size(){
		return par.size();
	}
	
	int setnum(){
		return _setnum;
	}
};

signed main(){
	cout<<fixed<<setprecision(10);
	
	int H, W;
	vector<string> s;
	vector<vector<int>> num;
	union_find uf;
	
	cin>>H>>W;
	
	uf.resize(H * W);
	s.resize(H);
	// num.resize(H + 100, vector<int>(W + 100));
	num.resize(200, vector<int>(200));
	
	for(int i = 0; i < H; i++){
		cin>>s[i];
	}
	
	for(int i = 0; i + 5 < num.size(); i += 4){//cout<<i<<endl;
		for(int j = 0; j + 5 < num[0].size(); j += 4){ 
			num[i][j] = 6;
			num[i][j+1] = 3;
			num[i][j+2] = 1;
			num[i][j+3] = 4;
			
			num[i+1][j] = 2;
			num[i+1][j+1] = 2;
			num[i+1][j+2] = 2;
			num[i+1][j+3] = 2;
			
			num[i+2][j] = 1;
			num[i+2][j+1] = 3;
			num[i+2][j+2] = 6;
			num[i+2][j+3] = 4;
			
			num[i+3][j] = 5;
			num[i+3][j+1] = 5;
			num[i+3][j+2] = 5;
			num[i+3][j+3] = 5;
		}
	}
	
	
	for(int i = 0; i < H; i++){
		for(int j = 0; j < W; j++){ //cout<<num[i][j];
			if(s[i][j] == '#') continue;
			if(num[i][j] != s[i][j] - '0') continue;
			
			if(i && s[i-1][j] != '#' && num[i-1][j] == s[i-1][j] - '0') {
				uf.unite(i * W + j, (i - 1) * W + j);
			}
			if(j  && s[i][j-1] != '#' && num[i][j-1] == s[i][j-1] - '0') {
				uf.unite(i * W + j, i * W + j - 1);
			}
		}//cout<<endl;
	}
	
	if(uf.same(0, (H-1) * W + W-1)) cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
	
	return 0;
}

C++: #include <string>
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
#include<functional>
#include<list>
#include<deque>
#include<bitset>
#include<set>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<cstring>
#include<sstream>
#include<complex>
#include<iomanip>
#include<numeric>
#include<cassert>
#define X first
#define Y second
#define pb push_back
#define rep(X,Y) for (int (X) = 0;(X) < (Y);++(X))
#define reps(X,S,Y) for (int (X) = S;(X) < (Y);++(X))
#define rrep(X,Y) for (int (X) = (Y)-1;(X) >=0;--(X))
#define rreps(X,S,Y) for (int (X) = (Y)-1;(X) >= (S);--(X))
#define repe(X,Y) for ((X) = 0;(X) < (Y);++(X))
#define peat(X,Y) for (;(X) < (Y);++(X))
#define all(X) (X).begin(),(X).end()
#define rall(X) (X).rbegin(),(X).rend()
#define eb emplace_back
#define UNIQUE(X) (X).erase(unique(all(X)),(X).end())
#define Endl endl
#define NL <<"\n"

using namespace std;
using ll=long long;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
template<class T> using vv=vector<vector<T>>;
template<class T> inline bool MX(T &l,const T &r){return l<r?l=r,1:0;}
template<class T> inline bool MN(T &l,const T &r){return l>r?l=r,1:0;}
//#undef NUIP
#ifdef NUIP
#include "benri.h"
#else
#define out(args...)
#endif
#ifdef __cpp_init_captures
template<typename T>vector<T> table(int n, T v){ return vector<T>(n, v);}
template <class... Args> auto table(int n, Args... args){auto val = table(args...); return vector<decltype(val)>(n, move(val));}
#endif
const ll MOD=1e9+7; //998244353

vector<string> ok
	{"6314",
	 "2!2!",
	 "1364",
	 "5!5!"};

int dst[112][112];
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1,0};

int main(){
  ios_base::sync_with_stdio(false); cin.tie(0);
  cout<<fixed<<setprecision(0);
	int h,w;
	cin>>h>>w;
	vector<string> mp(h);
	rep(i,h) cin>>mp[i];
	fill(dst[0],dst[112],MOD);
	dst[0][0]=0;
	queue<pii> que; que.emplace(0,0);
	while(que.size()){
		int x,y;
		tie(x,y)=que.front(); que.pop();
		rep(d,4){
			int nx=x+dx[d];
			int ny=y+dy[d];
			if(nx<0||ny<0||nx>=w||ny>=h||mp[ny][nx]!=ok[ny%4][nx%4]) continue;
			if(MN(dst[ny][nx],0)) que.emplace(nx,ny);
		}
	}
	// rep(i,h){rep(j,w) cout<<!!dst[i][j];cout NL;}
	cout<<(dst[h-1][w-1]?"NO":"YES") NL;
  return 0;
}