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 <algorithm>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define rep(i, n) for(int i = 0; (i) < (n); (i)++)
#define FOR(i, m, n) for(int i = (m); (i) < (n); (i)++)
#define All(v) (v).begin(), (v).end()
#define MP make_pair
#define pb push_back
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int INF = 1 << 30;
const ll LINF = 1LL << 61;
const int MOD = 1e9 + 7;

int check(int i, int j) {
    if((i + j) % 4 == 0)
        return 6;
    else if((i + j) % 4 == 2)
        return 1;
    else if(j % 4 == 1)
        return 3;
    else if(j % 4 == 3)
        return 4;
    else if(i % 4 == 1)
        return 2;
    else if(i % 4 == 3)
        return 5;
}

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

int main() {
    int H, W;
    cin >> H >> W;
    vector<string> s(H);
    rep(i, H) cin >> s[i];
    vector<vector<bool>> ok(H, vector<bool>(W));
    rep(i, H) rep(j, W) {
        if(check(i, j) == s[i][j] - '0') {
            ok[i][j] = 1;
        }
    }
    vector<vector<bool>> reach(H, vector<bool>(W));
    queue<pii> que;
    que.push(MP(0, 0));
    reach[0][0] = 1;
    while(!que.empty()) {
        auto p = que.front();
        que.pop();
        int y = p.first;
        int x = p.second;
        rep(i, 4) {
            int ny = y + dy[i];
            int nx = x + dx[i];
            if(nx >= 0 && nx < W && ny >= 0 && ny < H) {
                if(!reach[ny][nx] && ok[ny][nx]) {
                    reach[ny][nx] = 1;
                    que.push(MP(ny, nx));
                }
            }
        }
    }
    if(reach[H - 1][W - 1]) {
        cout << "YES" << endl;
    } else {
        cout << "NO" << endl;
    }
    return 0;
}

C++: #define _USE_MATH_DEFINES
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <numeric>
#include <functional>
#include <cctype>
#include <list>
#include <limits>
#include <cassert>
#include <random>
#include <time.h>
#include <unordered_set>

using namespace std;
using Int = long long;

constexpr double EPS = 1e-10;
constexpr long long MOD = 1000000007;

long long mod_pow(long long x, long long n) {
    long long res = 1;
    for (int i = 0;i < 60; i++) {
        if (n >> i & 1) res = res * x % MOD;
        x = x * x % MOD;
    }
    return res;
}

long long my_mod_pow(long long x, long long n) {
	long long ret = 1;
	for (; n > 0; n >>= 1, x = x * x % MOD) {
		if (n & 1) {
			ret = ret * x % MOD;
		}
	}
	return ret;
}

template<typename T>
T gcd(T a, T b) {
    return b != 0 ? gcd(b, a % b) : a;
}

template<typename T>
T lcm(T a, T b) {
    return a * b / gcd(a, b);
}

void fastInput() {
    cin.tie(0);
    ios::sync_with_stdio(false);
}

int can_move[10][10] = {{6, 3, 1, 4},
                        {2, 0, 2, 0},
                        {1, 3, 6, 4},
                        {5, 0, 5, 0}
                        };

int main(void) {
    vector<vector<int>> field(105, vector<int>(105, -1));
    int H, W; cin >> H >> W;
    for (int i = 1; i <= H; i++) {
        for (int j = 1; j <= W; j++) {
            char c; cin >> c;
            if (c == '#') field[i][j] = -1;
            else field[i][j] = c - '0';
        }
    }

    vector<vector<int>> reachable_cell(105, vector<int>(105));
    reachable_cell[1][1] = 1;
    int dh[] = {1, 0, -1, 0};
    int dw[] = {0, 1, 0, -1};
    queue<pair<int, int>> q;
    q.push({1, 1});
    while (!q.empty()){
        auto crt = q.front();
        q.pop();
        int h = crt.first;
        int w = crt.second;

        for (int k = 0; k < 4; k++) {
            int next_h = h + dh[k];
            int next_w = w + dw[k];
            if (reachable_cell[next_h][next_w] == 1 || field[next_h][next_w] == -1) continue;
            if (can_move[(next_h-1)%4][(next_w-1)%4] == field[next_h][next_w]) {
                reachable_cell[next_h][next_w] = 1;
                q.push({next_h, next_w});
            }
        }
    }
    if (reachable_cell[H][W]) cout << "YES" << endl;
    else cout << "NO" << endl;   
}

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

//template
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define rrep(i,a,b) for(int i=(a);i>(b);i--)
#define ALL(v) (v).begin(),(v).end()
typedef long long int ll;
const int inf = 0x3fffffff; const ll INF = 0x1fffffffffffffff; const double eps=1e-12;
void tostr(ll x,string& res){while(x)res+=('0'+(x%10)),x/=10; reverse(ALL(res)); return;}
template<class T> inline bool chmax(T& a,T b){ if(a<b){a=b;return 1;}return 0; }
template<class T> inline bool chmin(T& a,T b){ if(a>b){a=b;return 1;}return 0; }
//end

struct dice{
    ll x, y, z;
};

dice roll(dice d, ll dir){
    ll x = d.x, y = d.y, z = d.z;
    if(dir == 0) d.x = y, d.y = 7 - x;
    if(dir == 1) d.x = z, d.z = 7 - x;
    if(dir == 2) d.x = 7 - y, d.y = x;
    if(dir == 3) d.x = 7 - z, d.z = x;
    return d;
}

typedef pair<int,int> pos;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};

int main(){
   int h,w; scanf("%d%d",&h,&w);
   string s[110]; rep(i,0,h)cin>>s[i];
   queue<pair<pos,dice>> que; que.push({{0,0},{6,2,3}});
   bool used[110][110]={}; used[0][0]=1;
   while(!que.empty()){
      auto p=que.front(); que.pop();
      pos xy=p.first; dice d=p.second;
      if(s[xy.first][xy.second]!=(d.x+'0'))continue;
      if(xy.first==h-1&&xy.second==w-1){puts("YES"); return 0;}
      rep(i,0,4){
         int nx=xy.first+dx[i],ny=xy.second+dy[i];
         if(nx<0||nx>=h||ny<0||ny>=w||used[nx][ny])continue;
         que.push({{nx,ny},roll(d,i)}); used[nx][ny]=1;
      }
   } puts("NO");
   return 0;
}