Инструкции по реализации функционала
Поскольку код для игры за левую ракетку и игру за правую уже был написан ранее, то интересным развитием игры будет натравливание ботов друг против друга. Для достижения этого эффекта необходимо внести следующие изменения в функцию runONNX
скрипта ai.js
:
Следующая часть кода отображает изменения функции runONNX
скрипта ai.js
.
// Предсказание нейронной сеткой
const runONNX = async (left = false) => {
use_bot.busy = true;
console.time("onnx");
var inp = Float32Array.from([
left ? (1 - ball.x / normalizationConstant + 30 / normalizationConstant) : (ball.x / normalizationConstant),
ball.y / normalizationConstant,
left ? (leftPaddle.y / normalizationConstant) : (rightPaddle.y / normalizationConstant)
]);
let input = new onnx.Tensor(inp, "float32", [1, 3]);
let output = (await onnxSess.run([input])).get("output").data;
const actionId = indexOfMax(output);
if (actionId === 2) {
// up
if (left) {
leftPaddle.dy = -leftPaddle.paddleSpeed;
} else {
keyPresses["up"] = 1;
keyPresses["down"] = 0;
keyPresses["nothing"] = 0;
rightPaddle.dy = -rightPaddle.paddleSpeed;
}
} else if (actionId === 1) {
// down
if (left) {
leftPaddle.dy = leftPaddle.paddleSpeed;
} else {
keyPresses["up"] = 0;
keyPresses["down"] = 1;
keyPresses["nothing"] = 0;
rightPaddle.dy = rightPaddle.paddleSpeed;
}
} else {
//nothing
if (left) {
leftPaddle.dy = 0;
} else {
keyPresses["up"] = 0;
keyPresses["down"] = 0;
keyPresses["nothing"] = 1;
rightPaddle.dy = 0;
}
}
console.timeEnd("onnx");
use_bot.busy = false;
return output;
};
Мы добавили аргумент функции left
со значением по умолчанию false
. Предполагается, что данная функция сможет делать прогнозы для дальнейших действий как для левой ракетки, так и для правой.
Остальные изменения затрагивают правильное формирование входных данных и запись требуемых значений для выбранной ракетки. Для уменьшения числа строк кода используется тернарный оператор – краткая запись оператора ветвления. Она имеет синтаксис:
(логическое выражение) ? значение_если_истина : значение_если_ложь
Последним действием необходимо прогонять модель через для состояний левой и правой ракеток. Поэтому немного перепишем функцию waitUntil:
Следующая часть кода отображает изменения функции waitUntil
скрипта ai.js
.
async function waitUntil(condition, func) {
let frame = 0;
return await new Promise((resolve) => {
condition.intervalId = setInterval(async () => {
if (!condition.state) {
resolve("a");
} else {
if (!condition.busy && !isPaused) {
await func(false);
await func(true);
if (frame === 0) {
botImages[0].style.display = "block";
botImages[1].style.display = "none";
const tmp = botImages[0];
botImages[0] = botImages[1];
botImages[1] = tmp;
}
frame = (frame + 1) % 10;
}
}
}, 50);
});
}
Итоговый результат выполнения шага можно скачать тут.