I have a first version of using a recursive function with Javascript which produces expected results. Below a working version :
// Call the recursive function and get final (a,b) results
var HitTemp = JSON.parse(JSON.stringify(HitCurrent));
var result= recursiveFunction(HitTemp, HitTemp.playerCurrent, maxNodes);
var a = HitTemp.coordPlayable[0];
var b = HitTemp.coordPlayable[1];
// Recursive function
function recursiveFunction(HitCurrent, colorCurrent, depth) {
// Indices
var i, j, k;
// Evaluation
var arrayTemp, eval, e;
// Set current color to HitCurrent
HitCurrent.playerCurrent = colorCurrent;
// Deep copy of arrayCurrent array
arrayTemp = JSON.parse(JSON.stringify(HitCurrent.arrayCurrent));
// If depth equal to 0
if (depth == 0)
return evaluation(HitCurrent);
// Starting evaluation
eval = -infinity;
// Browse all possible hits
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++) {
if (HitCurrent.arrayPlayable[i][j] == 'playable') {
for (k = 0; k < 8; k++) {
// Explore line started from (i,j) with direction "k"
exploreHitLine(HitCurrent, i, j, k, 'drawing');
}
// Recursive call
e = recursiveFunction(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
if (e > eval) {
HitCurrent.coordPlayable = [i,j];
eval = e;
}
}
// Restore arrayCurrent array
HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
}
return eval;
}
From this, I would like to use "inline" WebWorkers to dedicate the recursion to WebWorker and avoid hanging process in browsers.
I tried to follow this link and this other link
I don't know if I have to "postmessage
" the object HitCurrent
or the value eval
to the main thread : by using WebWorker, I make confusions between the return
instruction (which returns a value in the terminal case) and the objet HitCurrent
argument passed for next recursive call.
If someone could give some clues to reproduce this original algorithm by using inline webworker (or with classical way of using webworker).
Inline webworker example:
As your code, there is no function evaluation
, function exploreHitLine
.
Before use following code, you must insert them into code
.
{
let workerScript = URL.createObjectURL( new Blob( [ `
"use strict";
// Recursive function
function recursiveFunction( HitCurrent, colorCurrent, depth ) {
// Indices
var i, j, k;
// Evaluation
var arrayTemp, eval, e;
// Set current color to HitCurrent
HitCurrent.playerCurrent = colorCurrent;
// Deep copy of arrayCurrent array
arrayTemp = JSON.parse(JSON.stringify(HitCurrent.arrayCurrent));
// If depth equal to 0
if ( depth === 0 ) return evaluation(HitCurrent);
// Starting evaluation
eval = -infinity;
// Browse all possible hits
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
if (HitCurrent.arrayPlayable[i][j] === 'playable') {
for (k = 0; k < 8; k++) {
// Explore line started from (i,j) with direction "k"
exploreHitLine(HitCurrent, i, j, k, 'drawing');
}
// Recursive call
e = recursiveFunction(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
if (e > eval) {
HitCurrent.coordPlayable = [i,j];
eval = e;
}
}
// Restore arrayCurrent array
HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
}
}
return eval;
}
onmessage = function ( event ) {
let params = event.data;
postMessage( { result: recursiveFunction( ...params ) } );
}
` ], { type: "plain/text" } ) );
// Call the recursive function and get final (a,b) results
new Promise( resolve => {
let HitTemp = JSON.parse(JSON.stringify(HitCurrent));
let firstWorker = new Worker( workerScript );
firstWorker.onmessage = function ( event ) {
resolve( event.data ); //{ result: XXX }
}
firstWorker.postMessage( HitTemp, HitTemp.playerCurrent, maxNodes );
} ).then( ( { result } ) => {
let [ a, b ] = result.coordPlayable;
console.log( result );
} );
}
Additionally following is working inline WebWorker:
{
let workerScript = URL.createObjectURL( new Blob( [ `
"use strict";
onmessage = function ( event ) {
let sum = 0, count = event.data;
for ( let i = 0; i < count**count; i++ ) {
sum += i;
}
postMessage( { result: sum, count } );
}
` ], { type: "plain/text" } ) );
let firstWorker = new Worker( workerScript );
let firstAlive = setTimeout( () => {
firstWorker.terminate();
console.log( "terminated" );
}, 3000 );
firstWorker.onmessage = function ( event ) {
clearTimeout( firstAlive );
console.log( event.data );
}
firstWorker.postMessage( 10 );
let secondWorker = new Worker( workerScript );
let secondAlive = setTimeout( () => {
secondWorker.terminate();
console.log( "terminated" );
}, 3000 );
secondWorker.onmessage = function ( event ) {
clearTimeout( secondAlive );
console.log( event.data );
}
secondWorker.postMessage( 5 );
}
Update 1.
{
// Inline webworker version
let workerScript = URL.createObjectURL( new Blob( [ `
"use strict";
// Recursive function
function recursiveFunction( HitCurrent, colorCurrent, depth ) {
// Indices
var i, j, k;
// Evaluation
var arrayTemp, evaluated, e;
// Set current color to HitCurrent
HitCurrent.playerCurrent = colorCurrent;
// Deep copy of arrayCurrent array
arrayTemp = JSON.parse(JSON.stringify(HitCurrent.arrayCurrent));
// If depth equal to 0
if (depth == 0)
return evaluation(HitCurrent);
// Starting evaluation
evaluated = -infinity;
// Browse all possible hits
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
if (HitCurrent.arrayPlayable[i][j] == 'playable') {
for (k = 0; k < 8; k++) {
// Explore line started from (i,j) with direction "k"
exploreHitLine(HitCurrent, i, j, k, 'drawing');
}
// Recursive call
e = recursiveFunction(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
if ( e > evaluated ) {
HitCurrent.coordPlayable = [i,j];
evaluated = e;
}
if (e == -infinity) { HitCurrent.coordPlayable = [ i, j ]; }
// Restore arrayCurrent array
HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
}
}
}
return evaluated;
}
onmessage = function ( event ) {
let params = event.data;
//postMessage( { result: recursiveFunction( HitCurrent, HitCurrent.playerCurrent, maxNodes ) } );
postMessage( { result: recursiveFunction( ...params ) } );
};
` ], { type: "plain/text" } ) );
// Call the recursive function and get final (a,b) results
new Promise( resolve => {
let HitTemp = JSON.parse(JSON.stringify(HitCurrent));
let firstWorker = new Worker( workerScript );
firstWorker.onmessage = function ( event ) {
resolve( event.data ); //{ result: XXX }
}
firstWorker.postMessage( [ HitTemp, HitTemp.playerCurrent, maxNodes ] );
} ).then( ( { result } ) => {
let [ a, b ] = result.coordPlayable;
console.log( result );
} );
}
Explanation of my faults:
=>
from: eval
to: evaluated
Worker.postMessage( aMessage, Transferrable )
, in this case, you don't need to use the second parameter.=>
from: firstWorker.postMessage( HitTemp, HitTemp.playerCurrent, maxNodes );
to: firstWorker.postMessage( [ HitTemp, HitTemp.playerCurrent, maxNodes ] );
(https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage)