Создать веб-работника, когда вызывается функция | JavaScript

1

У меня есть игра Tic Tac Toe 3D, которую я хочу оптимизировать, потому что в этот момент он разбивает мой веб-браузер. Он использует алгоритм альфа-бета-обрезки MiniMax, и я разделил код на 3 разных файла:

TTT3D
| -js
| ---init.js #, где я определяю все переменные (как winCombos, человек, компьютер и т.д.),
| ---worker.js # алгоритм miniMax и в конце, я отправляю в качестве сообщения переменную choice
| ---ticAlpha.js # рабочий построен и пытается получить ответ
| -index.html

Вот код:

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Tic Tac Toe 3D</title>
    <link rel="stylesheet" type="text/css" href="css/main.css">
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
    <meta charset="utf-8">
</head>
<body>
    <section id="intro">
        <div class="container">
            <div class="row">
                <div class="col-md-8 col-md-offset-2" style="text-align: center;">
                    <h1>Hi there! Let play <b>Tic Tac Toe</b>! Choose your player!</h1>
                    <button value="X" id="X" onclick="startGame('X')">X</button>
                    <button value="O" id="O" onclick="startGame('O')">O</button>
                </div>
            </div>
        </div>
    </section>

    <section id="board" class="hidden">
        <div class="container">
            <div class="row bottom">
                <div class="col-md-3"></div>
                <div class="col-md-2 boxContent">
                    <ul>
                        <li>
                            <h2>X</h2>
                        </li>
                        <li style="float: right !important;">
                            <input type="text" name="xPlayerScore" id="xPlayerScore" value="-" readonly>
                        </li>
                    </ul>
                </div>

                <div class="col-md-2 boxContent">
                    <ul>
                        <li>
                            <h2>O</h2>
                        </li>
                        <li style="float: right !important;">
                            <input type="text" name="oPlayerScore" id="oPlayerScore" value="-" readonly>
                        </li>
                    </ul>
                </div>
                <button class="col-md-2" onclick="playAgain()" style="margin-left: 7px;">
                    <img src="images/again.png" width="16">
                Play Again
                </button>


                <div class="col-md-3"></div>
            </div>
        </div>

        <div class="canvas1">
            <div class="row">
                <div class="tile" boardcol="0" boardrow="0" boardlevel="0" onclick="makeMove(0)" id="0"></div>
                <div class="tile" boardcol="1" boardrow="0" boardlevel="0" onclick="makeMove(1)" id="1"></div>
                <div class="tile" boardcol="2" boardrow="0" boardlevel="0"onclick="makeMove(2)" id="2"></div>
            </div>
            <div class="row">
                <div class="tile" boardcol="0" boardrow="1" boardlevel="0"onclick="makeMove(3)" id="3"></div>
                <div class="tile" boardcol="1" boardrow="1" boardlevel="0"onclick="makeMove(4)" id="4"></div>
                <div class="tile" boardcol="2" boardrow="1" boardlevel="0"onclick="makeMove(5)" id="5"></div>
            </div>
            <div class="row">
                <div class="tile" boardcol="0" boardrow="2" boardlevel="0"onclick="makeMove(6)" id="6"></div>
                <div class="tile" boardcol="1" boardrow="2" boardlevel="0"onclick="makeMove(7)" id="7"></div>
                <div class="tile" boardcol="2" boardrow="2" boardlevel="0"onclick="makeMove(8)" id="8"></div>
            </div>
        </div>

        <div class="canvas2">
            <div class="row">
                <div class="tile" boardcol="0" boardrow="0" boardlevel="1"onclick="makeMove(9)" id="9"></div>
                <div class="tile" boardcol="1" boardrow="0" boardlevel="1"onclick="makeMove(10)" id="10"></div>
                <div class="tile" boardcol="2" boardrow="0" boardlevel="1"onclick="makeMove(11)" id="11"></div>
            </div>
            <div class="row">
                <div class="tile" boardcol="0" boardrow="1" boardlevel="1"onclick="makeMove(12)" id="12"></div>
                <div class="tile" boardcol="1" boardrow="1" boardlevel="1"onclick="makeMove(13)" id="13"></div>
                <div class="tile" boardcol="2" boardrow="1" boardlevel="1"onclick="makeMove(14)" id="14"></div>
            </div>
            <div class="row">
                <div class="tile" boardcol="0" boardrow="2" boardlevel="1"onclick="makeMove(15)" id="15"></div>
                <div class="tile" boardcol="1" boardrow="2" boardlevel="1"onclick="makeMove(16)" id="16"></div>
                <div class="tile" boardcol="2" boardrow="2" boardlevel="1"onclick="makeMove(17)" id="17"></div>
            </div>
        </div>

        <div class="canvas3">
            <div class="row">
                <div class="tile" boardcol="0" boardrow="0" boardlevel="2"onclick="makeMove(18)" id="18"></div>
                <div class="tile" boardcol="1" boardrow="0" boardlevel="2"onclick="makeMove(19)" id="19"></div>
                <div class="tile" boardcol="2" boardrow="0" boardlevel="2"onclick="makeMove(20)" id="20"></div>
            </div>
            <div class="row">
                <div class="tile" boardcol="0" boardrow="1" boardlevel="2"onclick="makeMove(21)" id="21"></div>
                <div class="tile" boardcol="1" boardrow="1" boardlevel="2"onclick="makeMove(22)" id="22"></div>
                <div class="tile" boardcol="2" boardrow="1" boardlevel="2"onclick="makeMove(23)" id="23"></div>
            </div>
            <div class="row">
                <div class="tile" boardcol="0" boardrow="2" boardlevel="2"onclick="makeMove(24)" id="24"></div>
                <div class="tile" boardcol="1" boardrow="2" boardlevel="2"onclick="makeMove(25)" id="25"></div>
                <div class="tile" boardcol="2" boardrow="2" boardlevel="2"onclick="makeMove(26)" id="26"></div>
            </div>
        </div>
    </section>



    <script src="https://code.jquery.com/jquery-3.1.1.js"
    integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="
    crossorigin="anonymous"></script>
    <script src="js/init.js"></script>
    <script src="js/ticAlpha.js"></script>
</body>
</html>

init.js

var winningCombos   = new Array();

winningCombos[0]    = [0, 1, 2];
winningCombos[1]    = [3, 4, 5];
winningCombos[2]    = [6, 7, 8];

// Per columns

winningCombos[3]    = [0, 3, 6];
winningCombos[4]    = [1, 4, 7];
winningCombos[5]    = [2, 5, 8];

// Diagonals

winningCombos[6]    = [0, 4, 8];
winningCombos[7]    = [2, 4, 6];


// Second board

//Per lines

winningCombos[8]    = [9, 10, 11];
winningCombos[9]    = [12, 13, 14];
winningCombos[10]   = [15, 16, 17];

// Per columns

winningCombos[11]   = [9, 12, 15];
winningCombos[12]   = [10, 13, 16];
winningCombos[13]   = [11, 14, 17];

// Diagonals

winningCombos[14]   = [9, 13, 17];
winningCombos[15]   = [11, 13, 15];


// Third board

// Per lines

winningCombos[16]   = [18, 19, 20];
winningCombos[17]   = [21, 22, 23];
winningCombos[18]   = [24, 25, 26];

// Per columns

winningCombos[19]   = [18, 21, 24];
winningCombos[20]   = [19, 22, 25];
winningCombos[21]   = [20, 23, 26];

// Diagonals

winningCombos[22]   = [18, 22, 26];
winningCombos[23]   = [20, 22, 24];


// 3D Winning

winningCombos[24]   = [0, 13, 26];
winningCombos[25]   = [20, 13, 6];

// Per lines

winningCombos[26]   = [0, 10, 20];
winningCombos[27]   = [3, 13, 23];
winningCombos[28]   = [6, 16, 26];

var free            = ' ';
var boardSize       = 27;
var board           = new Array();
var activePlayer    = 'Human';
var i;
var choice;
var human;
var humanTurn;
var computer;
var computerTurn;
var humanWin = 0;
var computerWin = 0;

$(document).ready(function() {
    $("button").click(function(){
        $("#intro").addClass("hidden");
        $("#board").removeClass("hidden");
    });
});

function startGame(player) {
    for (i = 0; i < boardSize; i += 1) {
        board[i] = free;
    }

    activePlayer = 'Human';

    if (player == "X") {
        human = "X";
        humanTurn = "<p>X</p>";
        computer = "O";
        computerTurn = "<p>O</p>";
    } else {
        human = "O";
        humanTurn = "<p>O</p>";
        computer = "X";
        computerTurn = "<p>X</p>";
    }
}

ticAlpha.js

function makeMove(pos) {
    if (board[pos] === free && !gameOver(board)) {
        board[pos] = human;
        document.getElementById(pos).innerHTML = humanTurn;

        if (!gameOver(board)) {
            activePlayer = 'Computer';
            makeComputerMove();
        }
    }
}

function makeComputerMove() {
    // miniMax(board, 0, -Infinity, +Infinity);

    var worker = new Worker('worker.js');
    worker.postMessage('its time');

    worker.onmessage = function(event) {
        var move = event.data;
    };

    board[move] = computer;
    document.getElementById(move).innerHTML = computerTurn;
    choice = [];
    activePlayer = 'Human';
}

function score(possibleGame) {
    var score = getWinner(possibleGame);

    if (score === 3) {
        return 0;
    } else if (score === 1) {
        return -1;
    } else if (score === 2) {
        return 1;
    }
}

function miniMax(node, depth, alpha, beta) {
    if (getWinner(node) !== 0) {
        return score(node);
    }

    depth += 1;
    // var scores   = new Array();
    // var moves    = new Array();
    var availableMoves = getAvailableMoves(node);
    var move, result, possibleGame;
    if (activePlayer === 'Computer'){
        for (var i = 0; i < availableMoves.length; i += 1) {
            move = availableMoves[i];
            possibleGame = generateNewGame(move, node);
            result = miniMax(possibleGame, depth, alpha, beta);
            node = undoMove(node, move);

            if (result > alpha) {
                alpha = result;
                if (depth === 1) {
                    choice = move;
                } else if (alpha >= beta) {
                    return alpha;
                }
            }
        }
        return alpha;
    } else if (activePlayer === 'Human') { 
        for (var i = 0; i < availableMoves.length; i += 1) {
            move = availableMoves[i];
            possibleGame = generateNewGame(move, node);
            result = miniMax(possibleGame, depth, alpha, beta);
            node = undoMove(node, move);

            if (result < beta) {
                beta = result;
                if (depth === 1) {
                    choice = move;
                } else if (alpha >= beta) {
                    return beta;
                }
            }
        }

        return beta;
    }
}

function undoMove(possibleGame, move) {
    possibleGame[move] = free;
    changePlayerTurn();
    return possibleGame;
}

function getAvailableMoves(tempBoard) {
    var availableMoves = new Array();
    for (var i = 0; i < boardSize; i += 1) {
        if (board[i] === free) {
            availableMoves.push(i);
        }
    }
    return availableMoves;
}

function generateNewGame(move, possibleGame) {
    var piece = changePlayerTurn();
    possibleGame[move] = piece;
    return possibleGame;
}

function changePlayerTurn() {
    var turn;
    if (activePlayer === 'Computer') {
        turn = computer;
        activePlayer = 'Human';
    } else {
        turn = human;
        activePlayer = 'Computer';
    }

    return turn;
}

function gameOver(tempBoard) {
    if (getWinner(tempBoard) === 0) {
        return 0;
    } else if (getWinner(tempBoard) === 1) {
        alert("You won!");
        humanWin += 1;
        if (human === "X") {
            document.getElementById("xPlayerScore").value = humanWin;
        } else {
            document.getElementById("oPlayerScore").value = humanWin;
        }
    } else if (getWinner(tempBoard) === 2) {
        alert("Computer won!");
        computerWin += 1;
        if (computer === "X") {
            document.getElementById("xPlayerScore").value = computerWin;
        } else {
            document.getElementById("oPlayerScore").value = computerWin;
        }
    } else if (getWinner(tempBoard) === 3) {
        alert("The game was a draw!");
    }
    return 1;
}

function getWinner(tempBoard) {
    for (i = 0; i < winningCombos.length; i += 1) {
        if (tempBoard[winningCombos[i][0]] === human &&
            tempBoard[winningCombos[i][1]] === human &&
            tempBoard[winningCombos[i][2]] === human) {
            return 1; // human won
        } else if (tempBoard[winningCombos[i][0]] === computer &&
            tempBoard[winningCombos[i][1]] === computer &&
            tempBoard[winningCombos[i][2]] === computer) {
            return 2; // computer won
        }
    }

    if (tempBoard.indexOf(free) >= 0) {
        return 0; // not finished yet
    }

    return 3; // the game was a draw
}

function gameOver(tempBoard) {
    if (getWinner(tempBoard) === 0) {
        return 0;
    } else if (getWinner(tempBoard) === 1) {
        alert("You won!");
        humanWin += 1;
        if (human === "X") {
            document.getElementById("xPlayerScore").value = humanWin;
        } else {
            document.getElementById("oPlayerScore").value = humanWin;
        }
    } else if (getWinner(tempBoard) === 2) {
        alert("Computer won!");
        computerWin += 1;
        if (computer === "X") {
            document.getElementById("xPlayerScore").value = computerWin;
        } else {
            document.getElementById("oPlayerScore").value = computerWin;
        }
    } else if (getWinner(tempBoard) === 3) {
        alert("The game was a draw!");
    }
    return 1;
}

function getWinner(tempBoard) {
    for (i = 0; i < winningCombos.length; i += 1) {
        if (tempBoard[winningCombos[i][0]] === human &&
            tempBoard[winningCombos[i][1]] === human &&
            tempBoard[winningCombos[i][2]] === human) {
            return 1; // human won
        } else if (tempBoard[winningCombos[i][0]] === computer &&
            tempBoard[winningCombos[i][1]] === computer &&
            tempBoard[winningCombos[i][2]] === computer) {
            return 2; // computer won
        }
    }

    if (tempBoard.indexOf(free) >= 0) {
        return 0; // not finished yet
    }

    return 3; // the game was a draw
}

function playAgain() {
    if (getWinner(board) != 0) {
        for (var j = 0; j < boardSize; j += 1) {
            document.getElementById(j).innerHTML = "";
        }
        resetBoard();
    }
}

function resetBoard() {
    for (i = 0; i < boardSize; i += 1) {
        board[i] = free;
    }
}

worker.js

function miniMax(node, depth, alpha, beta) {
    if (getWinner(node) !== 0) {
        return score(node);
    }

    depth += 1;
    // var scores   = new Array();
    // var moves    = new Array();
    var availableMoves = getAvailableMoves(node);
    var move, result, possibleGame;
    if (activePlayer === 'Computer'){
        for (var i = 0; i < availableMoves.length; i += 1) {
            move = availableMoves[i];
            possibleGame = generateNewGame(move, node);
            result = miniMax(possibleGame, depth, alpha, beta);
            node = undoMove(node, move);

            if (result > alpha) {
                alpha = result;
                if (depth === 1) {
                    choice = move;
                } else if (alpha >= beta) {
                    return alpha;
                }
            }
        }
        return alpha;
    } else if (activePlayer === 'Human') { 
        for (var i = 0; i < availableMoves.length; i += 1) {
            move = availableMoves[i];
            possibleGame = generateNewGame(move, node);
            result = miniMax(possibleGame, depth, alpha, beta);
            node = undoMove(node, move);

            if (result < beta) {
                beta = result;
                if (depth === 1) {
                    choice = move;
                } else if (alpha >= beta) {
                    return beta;
                }
            }
        }

        return beta;
    }
}

function undoMove(possibleGame, move) {
    possibleGame[move] = free;
    changePlayerTurn();
    return possibleGame;
}

function getAvailableMoves(tempBoard) {
    var availableMoves = new Array();
    for (var i = 0; i < boardSize; i += 1) {
        if (board[i] === free) {
            availableMoves.push(i);
        }
    }
    return availableMoves;
}

function generateNewGame(move, possibleGame) {
    var piece = changePlayerTurn();
    possibleGame[move] = piece;
    return possibleGame;
}

function changePlayerTurn() {
    var turn;
    if (activePlayer === 'Computer') {
        turn = computer;
        activePlayer = 'Human';
    } else {
        turn = human;
        activePlayer = 'Computer';
    }

    return turn;
}

function gameOver(tempBoard) {
    if (getWinner(tempBoard) === 0) {
        return 0;
    } else if (getWinner(tempBoard) === 1) {
        alert("You won!");
        humanWin += 1;
        if (human === "X") {
            document.getElementById("xPlayerScore").value = humanWin;
        } else {
            document.getElementById("oPlayerScore").value = humanWin;
        }
    } else if (getWinner(tempBoard) === 2) {
        alert("Computer won!");
        computerWin += 1;
        if (computer === "X") {
            document.getElementById("xPlayerScore").value = computerWin;
        } else {
            document.getElementById("oPlayerScore").value = computerWin;
        }
    } else if (getWinner(tempBoard) === 3) {
        alert("The game was a draw!");
    }
    return 1;
}

function getWinner(tempBoard) {
    for (i = 0; i < winningCombos.length; i += 1) {
        if (tempBoard[winningCombos[i][0]] === human &&
            tempBoard[winningCombos[i][1]] === human &&
            tempBoard[winningCombos[i][2]] === human) {
            return 1; // human won
        } else if (tempBoard[winningCombos[i][0]] === computer &&
            tempBoard[winningCombos[i][1]] === computer &&
            tempBoard[winningCombos[i][2]] === computer) {
            return 2; // computer won
        }
    }

    if (tempBoard.indexOf(free) >= 0) {
        return 0; // not finished yet
    }

    return 3; // the game was a draw
}

onmessage = function(e) {
    miniMax(board, 0, -Infinity, Infinity);
    postMessage(choice);
};

Проблема в том, что переменная move всегда не определена, и даже если я выполняю console.log() внутри функции worker.onmessage, она ничего не отображает.

Вероятнее всего, он неправильно понял концепцию использования веб-рабочего и должен использоваться, но я пытаюсь решить более 24 часов, и это похоже на прогресс 0. По достоинству оцените вашу помощь. Большое спасибо!

  • 0
    Не заставляйте своего работника каждый раз вызывать функцию. Сделайте работника открытым и общайтесь с ним на протяжении всей жизни ваших приложений. Кроме того, в чем ваша проблема? Вы получаете ошибку?
  • 0
    Проблема в том, что move переменной всегда не определено. (ReferenceError: перемещение не определено). Даже когда я выполняю console.log () внутри функции worker.onmessage , он ничего не отображает.
Показать ещё 2 комментария
Теги:
optimization
web-worker
artificial-intelligence

1 ответ

0

Ну, одна проблема заключается в том, что похоже, что вы ожидаете, что работник получит доступ ко всем переменным, которые доступны в основном потоке, и не будет. Вы должны поддерживать состояние платы как в основном потоке, так и в рабочем месте и синхронизировать их с помощью сообщений. Это еще одна причина, чтобы сделать работника впереди и сохранить один и тот же на протяжении всей жизни приложения.

Рассмотрите свой запрос на miniMax(board, 0, -Infinity, Infinity); в worker.js. Этот вызов, вероятно, вызывает ошибку в потоке, потому что board не определена, поэтому miniMax пытается получить к ней доступ в теле функции и бросает.

Кроме того, вы также вызываете postMessage(choice) у своего работника, но choice не определен нигде.

  • 0
    Я сделал worker в файле init.js и также отправил board из ticAlpha.js в worker.js с postMessage . В worker.js я определяю новую переменную var board = e.data; , И choice определен сейчас. Это все еще не хочет работать. Спасибо за помощь!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню