递归函数的网络工作者
Webworker for a recursive function
我的答案已经有了一些要素,来自旧的 post ()。
现在我接手这个暗示这个问题的小代码。这段小代码使用内联 webworkers,因为我使用递归函数计算最佳播放(这是 "computer" 命中)。如果我不使用 webworker 并且深度太高,游戏就会在浏览器中挂起。
代码源可在 [this link][1]
我想要一个工作代码。事实上,我已经接近解决方案,因为已经修复了几个错误(例如,在 webworker 中包含不同的函数以使其在不调用外部函数的情况下进行计算。如果我不包含所有必要的函数,webworker 将无法工作,因为它有自己的范围。
所以我想获得帮助来调试我当前的版本。
游戏可在 [this link][2]
我只对 "computer vs player" 模式感兴趣(黑色开始播放)。在下面你可以找到我调用递归函数时的部分。
一旦用这个递归函数完成计算,我想取回代表当前游戏地图的对象(black/white 个圆圈的位置)。
为了取回建议命中的对象或坐标(我们在主函数中),我做了以下代码:
// 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 }
console.log('here5');
}
firstWorker.postMessage([HitTemp, HitTemp.playerCurrent, maxNodes]);
} ).then( ( { result } ) => {
//let [ a, b ] = result.coordPlayable;
let [ a, b ] = HitTemp.coordPlayable;
console.log('result3 : ', result);
console.log('here3 : ', a, b);
} );
// HERE I TRY TO USE a and b in exploreHitLine function
// who needs the variables a and b BUT I DON'T KNOW
// IF a AND b ARE KNOWN HERE FROM CODE ABOVE
for (k = 0; k < 8; k++) {
exploreHitLine(HitCurrent, a, b, k, 'drawing');
}
递归函数以下(内联 webworker 部分):
window.onload = function() {
// Inline webworker version
workerScript = URL.createObjectURL( new Blob( [ `
"use strict";
...
...
// All other variables and functions necessary for inline webworker
...
...
...
function negaMax(HitCurrent, colorCurrent, depth) {
// Indices
var i, j, k;
// Evaluation
var arrayTemp, evalFinal, 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
evalFinal = -infinity;
// Compute all playable hits and check if playable hits
if (computeHit(HitCurrent, 'playable')) {
// 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 = -negaMax(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
if (e > evalFinal) {
HitCurrent.coordPlayable = [i,j];
evalFinal = e;
}
if (e == -infinity) {
HitCurrent.coordPlayable = [i,j];
}
// Restore arrayCurrent array
HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
}
// Clean playable hits once double loop is done
cleanHits('playable', HitCurrent);
}
console.log('here2 :', evalFinal);
return evalFinal;
}
onmessage = function ( event ) {
let params = event.data;
//postMessage( { result: recursiveFunction( HitCurrent, HitCurrent.playerCurrent, maxNodes ) } );
postMessage( { result: negaMax( ...params ) } );
};
` ], { type: "plain/text" } ) );
main();
}
我希望通过递归函数取回计算值的坐标"a"和"b",但似乎return什么都没有。
我不知道如何接收对象HitTemp
对象或更直接地获取a
和b
建议坐标?
如果你不明白我在这个算法中的问题,请随时问我更多的精度。
您提供的代码有两个问题:
问题 #1:假设 postMessage
传递了一个引用,但它 serializes/deserializes 传递了它。
当您从主 js 中使用 postMessage
进入 WebWorker 时,您将传递 HitTemp 对象,稍后,在您假设的 WebWorker 中,如果您设置该对象的属性,则原始对象也会被修改。我的意思是以下代码:
firstWorker.postMessage([
HitTemp // <-- here you are sending the object to the WebWorker
, HitTemp.playerCurrent, maxNodes]);
workerScript = URL.createObjectURL( new Blob( [ `
// ...
if (e > evalFinal) {
HitCurrent.coordPlayable = [i,j]; // <-- here you access the object
evalFinal = e;
}
//...
不幸的是,根据documentation,当调用postMessage
时,原始对象被调用者序列化,然后在WebWorker中反序列化,所以实际上,WebWorker是在一个副本上操作。幸运的是,通过将您最感兴趣的数据发布到 WebWorker 返回的 postMessage
中,可以轻松避免这种情况。
问题 #2:在范围外使用 a
和 b
变量
我注意到您正在尝试访问 .then()
结果回调中定义的值,但不在该回调之外,如下所示:
//...
} ).then( ( { result } ) => {
let [ a, b ] = //here you define a and b
} );
// a and b are no longer in scope here
for (k = 0; k < 8; k++) {
exploreHitLine(HitCurrent, a, b, k, 'drawing');
}
解决方案
要解决第一个问题,您需要 return HitCurrent
的值(其中包含您可能最感兴趣的 coordPlayable
)和 postMessage
返回来自 WebWorker。对于第二个问题,只需使用 .then()
回调中的 a
和 b
变量移动最终的 for
循环。结果代码如下:
主要js代码:
new Promise( resolve => {
let HitTemp = JSON.parse(JSON.stringify(HitCurrent));
let firstWorker = new Worker( workerScript );
firstWorker.onmessage = function ( event ) {
resolve( event.data );
console.log('here5');
}
firstWorker.postMessage([HitTemp, HitTemp.playerCurrent, maxNodes]);
} ).then( ( { result } ) => {
var HitResult = result.HitResult;
let [ a, b ] = HitResult.coordPlayable; // <-- get values from result
console.log('result3 : ', result.eval);
console.log('here3 : ', a, b);
//move for loop inside the callback
for (k = 0; k < 8; k++) {
exploreHitLine(HitCurrent, a, b, k, 'drawing');
}
} );
网络工作者:
window.onload = function() {
// Inline webworker version
workerScript = URL.createObjectURL( new Blob( [ `
"use strict";
// ...
function negaMax(HitCurrent, colorCurrent, depth) {
// Indices
var i, j, k;
// Evaluation
var arrayTemp, evalFinal, 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
evalFinal = -infinity;
// Compute all playable hits and check if playable hits
if (computeHit(HitCurrent, 'playable')) {
// 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 = -negaMax(JSON.parse(JSON.stringify(HitCurrent)).eval, ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1); //since negaMax returns an object, don't forget to access the value in the recursive call
if (e > evalFinal) {
HitCurrent.coordPlayable = [i,j];
evalFinal = e;
}
if (e == -infinity) {
HitCurrent.coordPlayable = [i,j];
}
// Restore arrayCurrent array
HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
}
// Clean playable hits once double loop is done
cleanHits('playable', HitCurrent);
}
console.log('here2 :', evalFinal);
return {eval: evalFinal, HitResult: HitCurrent }; //<-- send the additional HitCurrent as a result here
}
onmessage = function ( event ) {
let params = event.data;
postMessage( { result: negaMax( ...params ) } );
};
` ], { type: "plain/text" } ) );
main();
}
我决定从WebWorker内部return整个HitCurrent
传递is as HitResult
参数,因为基于其他参数被递归方法修改为好吧(比如arrayPlayable
和arrayCurrent
),那么你也可以在计算后得到修改后的值。
我的答案已经有了一些要素,来自旧的 post (
现在我接手这个暗示这个问题的小代码。这段小代码使用内联 webworkers,因为我使用递归函数计算最佳播放(这是 "computer" 命中)。如果我不使用 webworker 并且深度太高,游戏就会在浏览器中挂起。
代码源可在 [this link][1]
我想要一个工作代码。事实上,我已经接近解决方案,因为已经修复了几个错误(例如,在 webworker 中包含不同的函数以使其在不调用外部函数的情况下进行计算。如果我不包含所有必要的函数,webworker 将无法工作,因为它有自己的范围。
所以我想获得帮助来调试我当前的版本。
游戏可在 [this link][2] 我只对 "computer vs player" 模式感兴趣(黑色开始播放)。在下面你可以找到我调用递归函数时的部分。
一旦用这个递归函数完成计算,我想取回代表当前游戏地图的对象(black/white 个圆圈的位置)。
为了取回建议命中的对象或坐标(我们在主函数中),我做了以下代码:
// 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 }
console.log('here5');
}
firstWorker.postMessage([HitTemp, HitTemp.playerCurrent, maxNodes]);
} ).then( ( { result } ) => {
//let [ a, b ] = result.coordPlayable;
let [ a, b ] = HitTemp.coordPlayable;
console.log('result3 : ', result);
console.log('here3 : ', a, b);
} );
// HERE I TRY TO USE a and b in exploreHitLine function
// who needs the variables a and b BUT I DON'T KNOW
// IF a AND b ARE KNOWN HERE FROM CODE ABOVE
for (k = 0; k < 8; k++) {
exploreHitLine(HitCurrent, a, b, k, 'drawing');
}
递归函数以下(内联 webworker 部分):
window.onload = function() {
// Inline webworker version
workerScript = URL.createObjectURL( new Blob( [ `
"use strict";
...
...
// All other variables and functions necessary for inline webworker
...
...
...
function negaMax(HitCurrent, colorCurrent, depth) {
// Indices
var i, j, k;
// Evaluation
var arrayTemp, evalFinal, 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
evalFinal = -infinity;
// Compute all playable hits and check if playable hits
if (computeHit(HitCurrent, 'playable')) {
// 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 = -negaMax(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
if (e > evalFinal) {
HitCurrent.coordPlayable = [i,j];
evalFinal = e;
}
if (e == -infinity) {
HitCurrent.coordPlayable = [i,j];
}
// Restore arrayCurrent array
HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
}
// Clean playable hits once double loop is done
cleanHits('playable', HitCurrent);
}
console.log('here2 :', evalFinal);
return evalFinal;
}
onmessage = function ( event ) {
let params = event.data;
//postMessage( { result: recursiveFunction( HitCurrent, HitCurrent.playerCurrent, maxNodes ) } );
postMessage( { result: negaMax( ...params ) } );
};
` ], { type: "plain/text" } ) );
main();
}
我希望通过递归函数取回计算值的坐标"a"和"b",但似乎return什么都没有。
我不知道如何接收对象HitTemp
对象或更直接地获取a
和b
建议坐标?
如果你不明白我在这个算法中的问题,请随时问我更多的精度。
您提供的代码有两个问题:
问题 #1:假设 postMessage
传递了一个引用,但它 serializes/deserializes 传递了它。
当您从主 js 中使用 postMessage
进入 WebWorker 时,您将传递 HitTemp 对象,稍后,在您假设的 WebWorker 中,如果您设置该对象的属性,则原始对象也会被修改。我的意思是以下代码:
firstWorker.postMessage([
HitTemp // <-- here you are sending the object to the WebWorker
, HitTemp.playerCurrent, maxNodes]);
workerScript = URL.createObjectURL( new Blob( [ `
// ...
if (e > evalFinal) {
HitCurrent.coordPlayable = [i,j]; // <-- here you access the object
evalFinal = e;
}
//...
不幸的是,根据documentation,当调用postMessage
时,原始对象被调用者序列化,然后在WebWorker中反序列化,所以实际上,WebWorker是在一个副本上操作。幸运的是,通过将您最感兴趣的数据发布到 WebWorker 返回的 postMessage
中,可以轻松避免这种情况。
问题 #2:在范围外使用 a
和 b
变量
我注意到您正在尝试访问 .then()
结果回调中定义的值,但不在该回调之外,如下所示:
//...
} ).then( ( { result } ) => {
let [ a, b ] = //here you define a and b
} );
// a and b are no longer in scope here
for (k = 0; k < 8; k++) {
exploreHitLine(HitCurrent, a, b, k, 'drawing');
}
解决方案
要解决第一个问题,您需要 return HitCurrent
的值(其中包含您可能最感兴趣的 coordPlayable
)和 postMessage
返回来自 WebWorker。对于第二个问题,只需使用 .then()
回调中的 a
和 b
变量移动最终的 for
循环。结果代码如下:
主要js代码:
new Promise( resolve => {
let HitTemp = JSON.parse(JSON.stringify(HitCurrent));
let firstWorker = new Worker( workerScript );
firstWorker.onmessage = function ( event ) {
resolve( event.data );
console.log('here5');
}
firstWorker.postMessage([HitTemp, HitTemp.playerCurrent, maxNodes]);
} ).then( ( { result } ) => {
var HitResult = result.HitResult;
let [ a, b ] = HitResult.coordPlayable; // <-- get values from result
console.log('result3 : ', result.eval);
console.log('here3 : ', a, b);
//move for loop inside the callback
for (k = 0; k < 8; k++) {
exploreHitLine(HitCurrent, a, b, k, 'drawing');
}
} );
网络工作者:
window.onload = function() {
// Inline webworker version
workerScript = URL.createObjectURL( new Blob( [ `
"use strict";
// ...
function negaMax(HitCurrent, colorCurrent, depth) {
// Indices
var i, j, k;
// Evaluation
var arrayTemp, evalFinal, 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
evalFinal = -infinity;
// Compute all playable hits and check if playable hits
if (computeHit(HitCurrent, 'playable')) {
// 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 = -negaMax(JSON.parse(JSON.stringify(HitCurrent)).eval, ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1); //since negaMax returns an object, don't forget to access the value in the recursive call
if (e > evalFinal) {
HitCurrent.coordPlayable = [i,j];
evalFinal = e;
}
if (e == -infinity) {
HitCurrent.coordPlayable = [i,j];
}
// Restore arrayCurrent array
HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
}
// Clean playable hits once double loop is done
cleanHits('playable', HitCurrent);
}
console.log('here2 :', evalFinal);
return {eval: evalFinal, HitResult: HitCurrent }; //<-- send the additional HitCurrent as a result here
}
onmessage = function ( event ) {
let params = event.data;
postMessage( { result: negaMax( ...params ) } );
};
` ], { type: "plain/text" } ) );
main();
}
我决定从WebWorker内部return整个HitCurrent
传递is as HitResult
参数,因为基于其他参数被递归方法修改为好吧(比如arrayPlayable
和arrayCurrent
),那么你也可以在计算后得到修改后的值。