For a maze that connects two points by only one path it is relatively easy to find it: start at the end point and build a complete graph of the maze: it will be a tree. At each vertex, take all the open paths exept the one where you just came from. Link the new vertices to the previous one.
Select the wanted start point, and follow the links until you reach the end point at the root of the tree.
The shortest possible hint stores only information if a walk through the maze has really to make a decision between alternating paths. If a vertex has only a direction you came from, and one to go to, nothing needs to be stored.
If there is a choice, the smallest amount of information needed is the number of alternatives and the index of the one to take. These are stored in the hint number as a series of multipliers and remainders. The rest is writing and reading them in the right order.
Edit: As it turns out, it is advantageous to do the backlinking in the opposite order. That way, you have the walkthrough backwards, but in the right order to record the hint number with the start point as the lowest multiplier and remainder, last.
function HintMaker(map) {
const info = [];
const dirs = 'LURD';
// start at the start vertex and go in all directions
function explore (x = 1, y = 1, from) {
const b = [...dirs];
// exclude where you came from
delete b[b.indexOf(from)];
// loop all other directions
b.forEach((d, i) => {
// the direction you go is the opposite of where you came from
const to = dirs[i + 2 & 3];
const dx = i & 1 ? 0 : i - 1;
const dy = i & 1 ? i - 2 : 0;
// which directions are open?
const open = map[y - (i == 1)][x + dx] != '|_'[i & 1];
if (open) {
// identify a new position
const xx = x + 2 * dx;
const yy = y + dy;
info[xx * 100 + yy] = {
link: x * 100 + y, // where from
to, // direction
alternates: explore(xx, yy, to) // possible further directions
}
// otherwide exclude from the list of directions
} else {
delete b[i];
}
});
return b.filter(d=>d);
}
// note possible directions at start
const atstart = explore();
let hint = 0n;
function write (a, f) {
// the hint needs to encode only cases where there are actually alternatives
if (a.length < 2) return;
// store the number of alternatives and the index of the one taken
hint = hint * BigInt(a.length) + BigInt(a.indexOf(f));
}
// start at the end vertex;
// the info has stored how you got there from the start vertex as a linked list,
// this is always the direct (shortest) path
let vertex = info[9950];
let from;
while (vertex = info[vertex.link]) {
write(vertex.alternates, from)
// the direction you go is the opposite of where you came from
from = dirs[dirs.indexOf(vertex.to) + 2 & 3]
}
// add the decision at start vertex
write(atstart, from)
return hint;
}
function SolveWithHint(hint, step) {
const dirs = 'LURD';
let from;
while(true) {
const b = [...dirs];
// exclude where you came from
delete b[dirs.indexOf(from)];
// only consider open directions
const alternates = b.filter(d => step[d]);
let dir = alternates[0];
// are there actually alternatives?
const len = BigInt(alternates.length);
if (alternates.length > 1) {
// look in the hint
dir = alternates[hint % len]
// throw away what you have read
hint = hint / len | 0n;
}
step(dir);
// the direction you go is the opposite of where you came from
from = dirs[dirs.indexOf(dir) + 2 & 3];
}
}
Try it online!
A more pleasing grafical representation
of the maze and the path.
For your test maze, the result is
Hint = 3749002908424008331902107714953749973951195
Step = 240