95 lines
3.4 KiB
JavaScript
95 lines
3.4 KiB
JavaScript
var globalDepth = 15;
|
|
|
|
var _hackEngine = null;
|
|
var _evalEngine = null;
|
|
var _movePoller = null;
|
|
|
|
const STOCKFISH_PATH = "/bundles/app/js/vendor/jschessengine/stockfish.asm.1abfa10c.js";
|
|
const CHAR_MAP = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8 };
|
|
|
|
function startEngines(playerColour) {
|
|
let baseFen = getBoardFen();
|
|
let evalSideToMove = "w";
|
|
let activeSide = "w";
|
|
|
|
// --- Hack engine ---
|
|
_hackEngine = new Worker(STOCKFISH_PATH);
|
|
_hackEngine.postMessage(`position fen ${baseFen} ${playerColour}`);
|
|
_hackEngine.postMessage("go wtime 300000 btime 300000 winc 2000 binc 2000");
|
|
_hackEngine.postMessage(`go depth ${globalDepth}`);
|
|
|
|
_hackEngine.onmessage = function(event) {
|
|
if (!event.data.startsWith("bestmove")) return;
|
|
|
|
const bestMove = event.data.split(" ")[1];
|
|
const display = document.getElementById("best-move");
|
|
if (display) display.textContent = `Best move: ${bestMove} (depth ${globalDepth})`;
|
|
|
|
document.querySelectorAll(".cheat-highlight").forEach(el => el.remove());
|
|
|
|
const m = bestMove.split("");
|
|
const from = `${CHAR_MAP[m[0]]}${m[1]}`;
|
|
const to = `${CHAR_MAP[m[2]]}${m[3]}`;
|
|
const board = document.querySelector("wc-chess-board");
|
|
if (!board) return;
|
|
|
|
[from, to].forEach(sq => {
|
|
const hl = document.createElement("div");
|
|
hl.className = `highlight cheat-highlight square-${sq}`;
|
|
hl.style = "background:red;opacity:0.5";
|
|
board.appendChild(hl);
|
|
});
|
|
};
|
|
|
|
// --- Eval engine ---
|
|
_evalEngine = new Worker(STOCKFISH_PATH);
|
|
let evalGeneration = 0;
|
|
|
|
function startEvalSearch() {
|
|
activeSide = evalSideToMove;
|
|
const gen = ++evalGeneration;
|
|
const side = activeSide;
|
|
_evalEngine.postMessage("stop");
|
|
_evalEngine.postMessage(`position fen ${baseFen} ${evalSideToMove}`);
|
|
_evalEngine.postMessage("go depth 10");
|
|
|
|
let pending = null;
|
|
_evalEngine.onmessage = function(event) {
|
|
if (gen !== evalGeneration) return; // discard stale results from old search
|
|
if (event.data.startsWith("info")) {
|
|
const scoreCP = event.data.match(/score cp (-?\d+)/);
|
|
const scoreMate = event.data.match(/score mate (-?\d+)/);
|
|
if (scoreMate) pending = { val: parseInt(scoreMate[1]), isMate: true };
|
|
else if (scoreCP) pending = { val: parseInt(scoreCP[1]), isMate: false };
|
|
} else if (event.data.startsWith("bestmove") && pending) {
|
|
// Only update the bar once the search is fully done — avoids wild swings
|
|
// from shallow-depth lines (e.g. seeing a capture but not the recapture)
|
|
updateEvalBar(pending.val, pending.isMate, side);
|
|
pending = null;
|
|
}
|
|
};
|
|
}
|
|
startEvalSearch();
|
|
|
|
// --- Move poller ---
|
|
_movePoller = setInterval(() => {
|
|
const newFen = getBoardFen();
|
|
if (newFen === baseFen) return;
|
|
baseFen = newFen;
|
|
|
|
evalSideToMove = evalSideToMove === "w" ? "b" : "w";
|
|
startEvalSearch();
|
|
|
|
_hackEngine.postMessage(`position fen ${baseFen} ${playerColour}`);
|
|
_hackEngine.postMessage("go wtime 300000 btime 300000 winc 2000 binc 2000");
|
|
_hackEngine.postMessage(`go depth ${globalDepth}`);
|
|
}, 500);
|
|
}
|
|
|
|
function stopEngines() {
|
|
if (_movePoller) { clearInterval(_movePoller); _movePoller = null; }
|
|
if (_evalEngine) { _evalEngine.terminate(); _evalEngine = null; }
|
|
if (_hackEngine) { _hackEngine.terminate(); _hackEngine = null; }
|
|
document.querySelectorAll(".cheat-highlight").forEach(el => el.remove());
|
|
}
|