Webworker для рекурсивной функции - PullRequest
0 голосов
/ 23 декабря 2018

У меня уже есть некоторые элементы для моего ответа, пришедшие из старого поста ( Попытка реализовать встроенный Web-работник для рекурсивной функции ).

Теперь я беру на себя этот небольшой код, подразумевающий этовопрос.В этом небольшом коде используются встроенные веб-работники, поскольку я использую рекурсивную функцию, которая вычисляет лучший хит для воспроизведения (это «компьютерный» хит).Если я не использую web-работника, и я беру слишком большую глубину, игра зависает в браузере.

источник кода доступен по [этой ссылке] [1]

Я быхотел бы получить рабочий код.В самом деле, я близок к решению, так как несколько ошибок было исправлено (например, тот факт, что веб-работник включает в себя различные функции, чтобы он выполнял свои вычисления без вызова внешних функций. Если я не включу все необходимые функции, веб-работник будетне сможет работать, так как у него есть своя область действия.

Поэтому я хотел бы получить помощь в отладке моей текущей версии.

Игра доступна по [этой ссылке] [2] Iменя интересует только режим "компьютер против игрока" (черные начинают играть). Здесь ниже вы можете найти часть, когда я вызываю рекурсивную функцию.

Как только вычисления выполнены с помощью этой рекурсивной функции, я бы хотелвернуть объект, представляющий текущую карту игры (позиции черных / белых кружков).

Чтобы вернуть объект или координаты, предложенные для попадания (здесь мы находимся в основной функции), я сделал следующий код:

// 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');
  }

и ниже рекурсивной функции (внутри встроенная веб-часть ):

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" вычисленного значения с помощью рекурсивной функции, но, похоже, ничего не возвращает.

Я не знаю, как получить объект HitTemp объект или, более точно, получить a и b предложенные координаты?

Не стесняйтесь спрашивать меня больше точности, если вы нене понимаю мою проблему в этом алгоритме.

1 Ответ

0 голосов
/ 26 декабря 2018

Есть две проблемы с кодом, который вы представили:

Проблема # 1: Предполагая, что postMessage передает ссылку, но вместо этого она сериализует / десериализует ее.

Когда выиспользуя postMessage из основного js в 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;
    }
//...

К сожалению, согласно документации , при вызове postMessage исходный объект сериализуется вызывающей стороной и затем десериализуется в WebWorker.Таким образом, WebWorker эффективно работает с копией.К счастью, этого легко избежать, разместив данные, которые вас больше всего интересуют, внутри postMessage назад из WebWorker.

Проблема №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');
}

Решение

Чтобы решитьВо-первых, вам нужно вернуть значения HitCurrent (которые содержат coordPlayable, которые вас, вероятно, больше всего интересуют) с postMessage обратно из WebWorker.Для второй проблемы просто переместите заключительный цикл for, используя переменные a и b внутри обратного вызова .then().Код результата выглядит следующим образом:

Основной код 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');
    }
} );

WebWorker:

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();
}

Я решил вернуть целое HitCurrent изнутри WebWorkerи передается как HitResult параметр, потому что на основании того факта, что другие параметры также изменяются рекурсивным методом (например, arrayPlayable и arrayCurrent), вы также сможете получить измененные значения после вычисления.

...