For a maze:
+----+----+----+----+----+
| |BOMB|BOMB|BOMB| |
+----+----+----+----+----+
|EXIT| S1 | S2 | S3 |BOMB|
+----+----+----+----+----+
| |BOMB|BOMB|BOMB| |
+----+----+----+----+----+
You can map this to a matrix of the probabilities of what happens after each move:
// DEAD, ESC, S1, S2, S3
p = [
[ 1.00, 0.00, 0.00, 0.00, 0.00 ], // DEAD
[ 0.00, 1.00, 0.00, 0.00, 0.00 ], // ESCAPED
[ 0.50, 0.25, 0.00, 0.25, 0.00 ], // S1
[ 0.50, 0.00, 0.25, 0.00, 0.25 ], // S2
[ 0.75, 0.00, 0.00, 0.25, 0.00 ] // S3
];
So, reading along the middle row, if the frog starts in the S1
square then, after one hop, there is:
- a 0.5 probability it will be dead;
- 0.25 probability it will have escaped; and
- 0.25 probability it will be in S2.
And reading along the top two rows - there is a probability of 1 that if it has died/escaped then it will stay dead/escaped (respectively).
To work out the probabilities after n
hops then you just raise the probability matrix to the power n
.
// DEAD, ESC, S1, S2, S3
p = [
[ 1.00, 0.00, 0.00, 0.00, 0.00 ], // DEAD
[ 0.00, 1.00, 0.00, 0.00, 0.00 ], // ESCAPED
[ 0.50, 0.25, 0.00, 0.25, 0.00 ], // S1
[ 0.50, 0.00, 0.25, 0.00, 0.25 ], // S2
[ 0.75, 0.00, 0.00, 0.25, 0.00 ] // S3
];
function multiply( a, b )
{
if ( a[0].length !== b.length )
{
throw "Matrices must have same a.x/b.y dimensions!";
}
let r = [];
for ( let y = 0; y < a.length; y++ )
{
r[y] = [];
for ( let x = 0; x < b[0].length; x++ )
{
r[y][x] = 0;
for ( let i = 0; i < a[0].length; i++ )
{
r[y][x] += a[y][i] * b[i][x];
}
}
}
return r;
}
// Start at S1
r = [ [ 0, 0, 1, 0, 0 ] ];
// Output probabilities up to 10 decimal places.
dp = 10;
console.log(
"i"
+ " " + "DEAD".padEnd(" ",dp+2)
+ " " + "ESCAPED".padEnd(" ",dp+2)
+ " " + "S1".padEnd(" ",dp+2)
+ " " + "S2".padEnd(" ",dp+2)
+ " " + "S3".padEnd(" ",dp+2)
);
for ( let i = 1; i <= 50; i++ ){
r = multiply( r, p );
if ( i < 10 || i % 10 === 0 )
{
console.log(
i
+ " " + Number(r[0][0]).toFixed(dp)
+ " " + Number(r[0][1]).toFixed(dp)
+ " " + Number(r[0][2]).toFixed(dp)
+ " " + Number(r[0][3]).toFixed(dp)
+ " " + Number(r[0][4]).toFixed(dp)
);
}
}
This simple example shows that it quickly converges to a state where it is very unlikely for the frog to be still moving and there is a probability of 0.7321428571
that it is dead and 0.2678571429
that it is alive.
The challenge would be to take the input map and output the matrix and then to look at methods of optimising raising a matrix to a power to quickly find this convergence point (either through repeatedly squaring the matrix - p = multiply(p, p);
- or other methods).