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++: /**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author aajisaka
 */

#include<bits/stdc++.h>

using namespace std;

void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}
#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

#define SPEED ios_base::sync_with_stdio(false);cin.tie(nullptr)
#define rep(i,n) for(int i=0; i<(int)(n); i++)
#define all(v) v.begin(), v.end()
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; }

using ll = long long;
using P = pair<ll, ll>;

constexpr long double PI = 3.14159265358979323846264338327950288L;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

class B {
public:

    struct Dice {
      int i{}, j{}, k{}, x{}, y{};
      Dice(int i, int j, int k, int x, int y):
        i(i), j(j), k(k), x(x), y(y){}
    };

    void solve(istream& cin, ostream& cout) {
      SPEED;
      int h, w; cin >> h >> w;
      vector<vector<int>> mat(h, vector<int>(w));
      rep(i, h) {
        rep(j, w) {
          char c; cin >> c;
          if (c == '#') {
            mat[i][j] = 100;
          } else {
            mat[i][j] = c-'0';
          }
          debug(i, j, mat[i][j]);
        }
      }
      vector<vector<bool>> dp(h, vector<bool>(w));
      queue<Dice> que;
      que.emplace(1, 2, 3, 0, 0);
      dp[0][0] = true;

      while(!que.empty()) {
        auto d = que.front(); que.pop();
        debug(d.i, d.j, d.k, d.x, d.y);
        if (d.x > 0 && (!dp[d.x-1][d.y]) && mat[d.x-1][d.y] == 7-d.j) {
          dp[d.x-1][d.y] = true;
          que.emplace(d.j, 7-d.i, d.k, d.x-1, d.y);
        }
        if (d.x < h-1 && (!dp[d.x+1][d.y]) && mat[d.x+1][d.y] == d.j) {
          dp[d.x+1][d.y] = true;
          que.emplace(7-d.j, d.i, d.k, d.x+1, d.y);
        }
        if (d.y > 0 && (!dp[d.x][d.y-1]) && mat[d.x][d.y-1] == 7-d.k) {
          dp[d.x][d.y-1] = true;
          que.emplace(d.k, d.j, 7-d.i, d.x, d.y-1);
        }
        if (d.y < w-1 && (!dp[d.x][d.y+1]) && mat[d.x][d.y+1] == d.k) {
          debug(d.x, d.y);
          dp[d.x][d.y+1] = true;
          que.emplace(7-d.k, d.j, d.i, d.x, d.y+1);
        }
      }

      if (dp[h-1][w-1]) {
        cout << "YES" << endl;
      } else {
        cout << "NO" << endl;
      }

    }
};

signed main() {
  B solver;
  std::istream& in(std::cin);
  std::ostream& out(std::cout);
  solver.solve(in, out);
  return 0;
}

C++: #include <iostream>
#include <cmath>
#include <numeric>
#include <algorithm>
#include <deque>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <iomanip>
#include <map>
#include <stack>
#include <queue>
#include <functional>
#include <climits>
#include <bitset>
#include <random>
#include <tuple>
#include <initializer_list>
#include <fstream>
struct Dice {
	int top, front, right_face;
	int bottom_face() const { return 7 - top; }
	Dice right() const {
		return Dice{ 7 - right_face, front, top };
	}
	Dice left() const {
		return Dice{ right_face, front, 7 - top };
	}
	Dice up() const {
		return Dice{ front, 7 - top, right_face };
	}
	Dice down() const {
		return Dice{ 7 - front, top, right_face };
	}
};
struct Coordinate {
	int i, j;
	Coordinate right() const {
		return Coordinate{ i, j + 1 };
	}
	Coordinate left() const {
		return Coordinate{ i, j - 1 };
	}
	Coordinate up() const {
		return Coordinate{ i - 1, j };
	}
	Coordinate down() const {
		return Coordinate{ i + 1, j };
	}
};
std::vector<std::pair<Coordinate, Dice>> neighbors(const std::pair<Coordinate, Dice> pair) {
	return std::vector<std::pair<Coordinate, Dice>> {std::make_pair(pair.first.right(), pair.second.right()), std::make_pair(pair.first.left(), pair.second.left()), std::make_pair(pair.first.up(), pair.second.up()), std::make_pair(pair.first.down(), pair.second.down())};
}
int main() {
	int height, width; std::cin >> height >> width;
	std::vector<std::string> state(height); for (auto& line : state) std::cin >> line;
	std::vector<std::vector<std::vector<std::vector<std::vector<bool>>>>> memo(height, std::vector<std::vector<std::vector<std::vector<bool>>>>(width, std::vector<std::vector<std::vector<bool>>>(6, std::vector<std::vector<bool>>(6, std::vector<bool>(6, false)))));
	std::stack<std::pair<Coordinate, Dice>> stack;
	memo[0][0][0][1][2] = true;
	stack.emplace(Coordinate{ 0, 0 }, Dice{ 1, 2, 3 });
	while (!stack.empty()) {
		const auto top = stack.top(); stack.pop();
		for (const auto next : neighbors(top)) {
			if (0 > next.first.i || 0 > next.first.j || height <= next.first.i || width <= next.first.j) continue;
			if (memo[next.first.i][next.first.j][next.second.top - 1][next.second.front - 1][next.second.right_face - 1]) continue;
			if (state[next.first.i][next.first.j] - '0' == next.second.bottom_face()) {
				memo[next.first.i][next.first.j][next.second.top - 1][next.second.front - 1][next.second.right_face - 1] = true;
				stack.push(next);
			}
		}
	}
	bool can_reach = false;
	for (auto t = 0; t < 6; ++t) for (auto f = 0; f < 6; ++f) for (auto r = 0; r < 6; ++r) if (memo.back().back()[t][f][r]) can_reach = true;
	std::cout << (can_reach ? "YES" : "NO") << std::endl;
}