var g_startOffset = null; var g_selectedPiece = null; var moveNumber = 1; var g_allMoves = []; var g_playerWhite = true; var g_changingFen = false; var g_analyzing = false; var g_uiBoard; var g_cellSize = 45; function UINewGame() { moveNumber = 1; var pgnTextBox = document.getElementById("PgnTextBox"); // pgnTextBox.value = ""; EnsureAnalysisStopped(); // UI (terminate and destroy worker) ResetGame(); // shouldn't work if (InitializeBackgroundEngine()) { g_backgroundEngine.postMessage("go"); } g_allMoves = []; RedrawBoard(); //UI // if player is black play the first move if (!g_playerWhite) { SearchAndRedraw(); //UI } } function EnsureAnalysisStopped() { if (g_analyzing && g_backgroundEngine != null) { g_backgroundEngine.terminate(); g_backgroundEngine = null; } } function UIAnalyzeToggle() { if (InitializeBackgroundEngine()) { if (!g_analyzing) { g_backgroundEngine.postMessage("analyze"); } else { EnsureAnalysisStopped(); } g_analyzing = !g_analyzing; document.getElementById("AnalysisToggleLink").innerText = g_analyzing ? "Analysis: On" : "Analysis: Off"; } else { alert("Your browser must support web workers for analysis - (chrome4, ff4, safari)"); } } function UIChangeFEN() { if (!g_changingFen) { var fenTextBox = document.getElementById("FenTextBox"); var result = InitializeFromFen(fenTextBox.value); if (result.length != 0) { UpdatePVDisplay(result); return; } else { UpdatePVDisplay(''); } g_allMoves = []; EnsureAnalysisStopped(); InitializeBackgroundEngine(); g_playerWhite = !!g_toMove; g_backgroundEngine.postMessage("position " + GetFen()); RedrawBoard(); } } function UIChangeStartPlayer() { g_playerWhite = !g_playerWhite; RedrawBoard(); } function UpdatePgnTextBox(move) { var pgnTextBox = document.getElementById("PgnTextBox"); if (g_toMove != 0) { pgnTextBox.value += moveNumber + ". "; moveNumber++; } pgnTextBox.value += GetMoveSAN(move) + " "; } function UIChangeTimePerMove() { var timePerMove = document.getElementById("TimePerMove"); g_timeout = parseInt(timePerMove.value, 10); } function FinishMove(bestMove, value, timeTaken, ply) { if (bestMove != null) { UIPlayMove(bestMove, BuildPVMessage(bestMove, value, timeTaken, ply)); } else { alert("Checkmate!"); } } function UIPlayMove(move, pv) { UpdatePgnTextBox(move); g_allMoves[g_allMoves.length] = move; MakeMove(move); UpdatePVDisplay(pv); UpdateFromMove(move); } // buggy doesn't update the pgn properly function UIUndoMove() { if (g_allMoves.length == 0) { return; } if (g_backgroundEngine != null) { g_backgroundEngine.terminate(); g_backgroundEngine = null; } UnmakeMove(g_allMoves[g_allMoves.length - 1]); g_allMoves.pop(); if (g_playerWhite !== !!g_toMove && g_allMoves.length !== 0) { UnmakeMove(g_allMoves[g_allMoves.length - 1]); g_allMoves.pop(); } RedrawBoard(); } function UpdatePVDisplay(pv) { if (pv != null) { var outputDiv = document.getElementById("output"); if (outputDiv.firstChild != null) { outputDiv.removeChild(outputDiv.firstChild); } outputDiv.appendChild(document.createTextNode(pv)); } } function SearchAndRedraw() { if (g_analyzing) { EnsureAnalysisStopped(); InitializeBackgroundEngine(); g_backgroundEngine.postMessage("position " + GetFen()); g_backgroundEngine.postMessage("analyze"); return; } if (InitializeBackgroundEngine()) { g_backgroundEngine.postMessage("search " + g_timeout); } else { Search(FinishMove, 99, null); // unasynchronous version fall back } } var g_backgroundEngineValid = true; var g_backgroundEngine; function InitializeBackgroundEngine() { if (!g_backgroundEngineValid) { return false; } if (g_backgroundEngine == null) { g_backgroundEngineValid = true; try { g_backgroundEngine = new Worker("js/garbochess.js"); g_backgroundEngine.onmessage = function (e) { if (e.data.match("^pv") == "pv") { UpdatePVDisplay(e.data.substr(3, e.data.length - 3)); } else if (e.data.match("^message") == "message") { EnsureAnalysisStopped(); UpdatePVDisplay(e.data.substr(8, e.data.length - 8)); } else { UIPlayMove(GetMoveFromString(e.data), null); } } g_backgroundEngine.error = function (e) { alert("Error from background worker:" + e.message); } g_backgroundEngine.postMessage("position " + GetFen()); } catch (error) { g_backgroundEngineValid = false; } } return g_backgroundEngineValid; } function UpdateFromMove(move) { var fromX = (move & 0xF) - 4; var fromY = ((move >> 4) & 0xF) - 2; var toX = ((move >> 8) & 0xF) - 4; var toY = ((move >> 12) & 0xF) - 2; if (!g_playerWhite) { fromY = 7 - fromY; toY = 7 - toY; fromX = 7 - fromX; toX = 7 - toX; } if ((move & moveflagCastleKing) || (move & moveflagCastleQueen) || (move & moveflagEPC) || (move & moveflagPromotion)) { // more than one piece was moved // or one piece was modified // -> entire redraw RedrawPieces(); } else { // simply swap piece parents var fromSquare = g_uiBoard[fromY * 8 + fromX]; $(g_uiBoard[toY * 8 + toX]) .empty() .append($(fromSquare).children()); } } function RedrawPieces() { for (y = 0; y < 8; ++y) { for (x = 0; x < 8; ++x) { var td = g_uiBoard[y * 8 + x]; var pieceY = g_playerWhite ? y : 7 - y; var piece = g_board[((pieceY + 2) * 0x10) + (g_playerWhite ? x : 7 - x) + 4]; var pieceName = null; switch (piece & 0x7) { case piecePawn: pieceName = "pawn"; break; case pieceKnight: pieceName = "knight"; break; case pieceBishop: pieceName = "bishop"; break; case pieceRook: pieceName = "rook"; break; case pieceQueen: pieceName = "queen"; break; case pieceKing: pieceName = "king"; break; } if (pieceName != null) { pieceName += "_"; pieceName += (piece & 0x8) ? "white" : "black"; } if (pieceName != null) { var img = document.createElement("div"); $(img).addClass('sprite-' + pieceName); img.style.backgroundImage = "url('img/sprites.png')"; img.width = g_cellSize; img.height = g_cellSize; var divimg = document.createElement("div"); divimg.appendChild(img); $(divimg).draggable({ start: function (e, ui) { if (g_selectedPiece === null) { g_selectedPiece = this; var offset = $(this).closest('table').offset(); g_startOffset = { left: e.pageX - offset.left, top: e.pageY - offset.top }; } else { return g_selectedPiece == this; } }}); $(divimg).mousedown(function(e) { if (g_selectedPiece === null) { var offset = $(this).closest('table').offset(); g_startOffset = { left: e.pageX - offset.left, top: e.pageY - offset.top }; e.stopPropagation(); g_selectedPiece = this; g_selectedPiece.style.backgroundImage = "url('img/transpBlue50.png')"; } else if (g_selectedPiece === this) { g_selectedPiece.style.backgroundImage = null; g_selectedPiece = null; } }); $(td).empty().append(divimg); } else { $(td).empty(); } } } } function RedrawBoard() { var div = $("#board")[0]; var table = document.createElement("table"); table.cellPadding = "0px"; table.cellSpacing = "0px"; $(table).addClass('no-highlight'); var tbody = document.createElement("tbody"); g_uiBoard = []; var dropPiece = function (e, ui) { // retrive start -> end move var endX = e.pageX - $(table).offset().left; var endY = e.pageY - $(table).offset().top; endX = Math.floor(endX / g_cellSize); endY = Math.floor(endY / g_cellSize); var startX = Math.floor(g_startOffset.left / g_cellSize); var startY = Math.floor(g_startOffset.top / g_cellSize); // convert coordinates to white-space if (!g_playerWhite) { startY = 7 - startY; endY = 7 - endY; startX = 7 - startX; endX = 7 - endX; } // gather all possible valid moves var moves = GenerateValidMoves(); var move = null; // check if the move is valid for (var i = 0; i < moves.length; i++) { if ((moves[i] & 0xFF) == MakeSquare(startY, startX) && ((moves[i] >> 8) & 0xFF) == MakeSquare(endY, endX)) { move = moves[i]; } } // convert coordinates back to black-space if (!g_playerWhite) { startY = 7 - startY; endY = 7 - endY; startX = 7 - startX; endX = 7 - endX; } // put the html object back to its original position // whether the move is valid or not g_selectedPiece.style.left = 0; g_selectedPiece.style.top = 0; if (!(startX == endX && startY == endY) && move != null) { // if the move is valid // we add the move to the png texbox UpdatePgnTextBox(move); // we save the move in our worker if (InitializeBackgroundEngine()) { g_backgroundEngine.postMessage(FormatMove(move)); } // we add the move to the move list g_allMoves[g_allMoves.length] = move; // we apply the move MakeMove(move); UpdateFromMove(move); // update the fen text box var fen = GetFen(); document.getElementById("FenTextBox").value = fen; setTimeout("SearchAndRedraw()", 0); } // whether the move is valid or not, we remove highlight and clear selection g_selectedPiece.style.backgroundImage = null; g_selectedPiece = null; }; for (y = 0; y < 8; ++y) { var tr = document.createElement("tr"); for (x = 0; x < 8; ++x) { var td = document.createElement("td"); td.style.width = g_cellSize + "px"; td.style.height = g_cellSize + "px"; td.style.backgroundColor = ((y ^ x) & 1) ? "#D18947" : "#FFCE9E"; tr.appendChild(td); g_uiBoard[y * 8 + x] = td; } tbody.appendChild(tr); } table.appendChild(tbody); $('body').droppable({ drop: dropPiece }); $(table).mousedown(function(e) { if (g_selectedPiece !== null) { dropPiece(e); } }); RedrawPieces(); $(div).empty(); div.appendChild(table); g_changingFen = true; document.getElementById("FenTextBox").value = GetFen(); g_changingFen = false; }