diff options
| author | Yann Granjon <[email protected]> | 2013-06-05 16:13:15 +0200 |
|---|---|---|
| committer | Yann Granjon <[email protected]> | 2013-06-05 16:13:15 +0200 |
| commit | 1ef133c52d12daf3fdad1d979e5a71cb39fa0d2e (patch) | |
| tree | 31e2cd5c6b0497f58762a63e3536dab76654324a /js/gui.js | |
| download | Chess3D-1ef133c52d12daf3fdad1d979e5a71cb39fa0d2e.tar.xz Chess3D-1ef133c52d12daf3fdad1d979e5a71cb39fa0d2e.zip | |
Initial Commit
Diffstat (limited to 'js/gui.js')
| -rw-r--r-- | js/gui.js | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/js/gui.js b/js/gui.js new file mode 100644 index 0000000..b32bc03 --- /dev/null +++ b/js/gui.js @@ -0,0 +1,545 @@ + +// ECMAScript 5 strict mode +/* jshint globalstrict: true*/ +/* jslint newcap: true */ +/* global THREE, $, document, window, console */ +/* global LOADING_BAR_SCALE,ROWS,COLS,PIECE_SIZE, BOARD_SIZE, FLOOR_SIZE, WIREFRAME, DEBUG, Cell, WHITE, BLACK, FEEDBACK, SHADOW */ +/* global SearchAndRedraw, UIPlayMove, camera, levels, g_allMoves:true, promotion:true, g_backgroundEngine:true, validMoves, InitializeBackgroundEngine, EnsureAnalysisStopped, newGame, redrawBoard, parsePGN, g_playerWhite:true */ + /*global Search,FormatSquare,GenerateMove,MakeMove,GetMoveSAN,MakeSquare,UnmakeMove, FormatMove, ResetGame, GetFen, GetMoveFromString, alert, InitializeFromFen, GenerateValidMoves */ + /*global g_inCheck,g_board,g_pieceList, g_toMove, g_timeout:true,g_maxply:true */ + /*global moveflagCastleKing, moveflagCastleQueen, moveflagEPC, moveflagPromotion, colorWhite*/ + /*global moveflagPromoteQueen,moveflagPromoteRook,moveflagPromoteBishop,moveflagPromoteKnight*/ + /*global piecePawn, pieceKnight, pieceBishop, pieceRook, pieceQueen, pieceKing */ +"use strict"; +(function () { + + // jQuery pgn textarea + var $pgn; + // list of moves in pgn format + var g_pgn = []; + // jQuery check feedback + var $info; + + function initInfo() { + // create the DOM element + // to display Chc + $info = $("<div>") + .css("position","absolute") + .position({ + of:$("body"), + my:"right top", + at:"right top" + }) + .attr("id","info") + .appendTo($("body")) + .css("left","auto") + .css("right","0"); + } + + + function initGUI() { + var $gui = $("<div>") + .css("position","absolute") + .position({ + of:$("body"), + my:"left top", + at:"left top" + }) + .width(150) + .attr("id","gui"); + + $("<p>") + .text("menu") + .appendTo($gui); + + var $menudiv = $("<div>").appendTo($gui); + + var $menu = $("<ul>").appendTo($menudiv); + + makeButton("NewGame",newGameDialog,$menu); + makeButton("Undo",undo,$menu); + makeButton("Load",loadDialog,$menu); + makeButton("Save",save,$menu); + + $("<label>") + .text("Promotion:") + .append( + $("<select>") + .width(140) + .append( + $("<option>") + .text("Queen")) + .append( + $("<option>") + .text("Rook")) + .append( + $("<option>") + .text("Bishop")) + .append( + $("<option>") + .text("Knight")) + .change( changePromo ) + .appendTo($menudiv) + ) + .appendTo($menudiv); + + + $pgn = $("<textarea>") + .attr("cols","16") + .attr("rows","10") + .attr("readonly","readonly") + .appendTo($menudiv); + + + $("body").append($gui); + + $gui.accordion({ + header: "p", + collapsible: true + }); + } + + + function makeButton(name,callback,parent) { + var $item = $("<li>").appendTo(parent); + return $("<button>") + .button({ + label:name + }) + .width(140) + .click(callback) + .appendTo($item); + } + + function newGameDialog() { + var id = "newgame"; + var dialogColor = WHITE; + var dialogLevel = 0; + + if ($("#"+id).length !== 0) { + return false; + } + + var $newGame = $("<div>") + .attr("id",id) + .attr("title","New Game") + .appendTo($("body")); + + // buttonset div + var $radio = $("<p>").appendTo($newGame); + // first button for white + $('<input type="radio" id="white" name="color" checked="checked">') + .click(function() { + dialogColor = WHITE; + }) + .appendTo($radio); + $('<label for="white">White</label>').appendTo($radio); + + // second button for black + $('<input type="radio" id="black" name="color"/>') + .click(function() { + dialogColor = BLACK; + }) + .appendTo($radio); + $('<label for="black">Black</label>').appendTo($radio); + // initialize the buttonset + $radio.buttonset(); + + // level selector + + var $label = $("<label>") + .text("AI Strength:"); + var $levelSelect = $('<select>') + .css("display","block") + .appendTo($label) + .change(function(event) { + dialogLevel = $(event.currentTarget).val(); + }); + $("<p>").append($label).appendTo($newGame); + + // add as much level configuration we have + for (var i = 0; i < levels.length; i++) { + $('<option>') + .val(i) + .text("level "+(i+1)) + .appendTo($levelSelect); + } + $newGame.dialog({ + close:function(event,ui) { + $newGame.remove(); + }, + buttons: { + "Start": function() { + newGame(dialogColor,dialogLevel); + $(this).remove(); + } + } + }); + } + /* + * GAME CONTROL + */ + function newGame(color,level) { + + // change AI parameters according to level + if (levels[level] !== undefined) { + g_timeout = levels[level].timeout; + g_maxply = levels[level].maxply; + } + + EnsureAnalysisStopped(); + ResetGame(); + if (InitializeBackgroundEngine()) { + g_backgroundEngine.postMessage("go"); + } + + g_allMoves = []; + clearPGN(); + + redrawBoard(); + + if (color === WHITE) { + g_playerWhite = true; + camera.position.x = 0; + camera.position.z = 100; // camera on white side + } else { + g_playerWhite = false; + SearchAndRedraw(); + camera.position.x = 0; + camera.position.z = -100; // camera on black side + } + } + + + function changeStartPlayer(event) { + g_playerWhite = $(event.currentTarget).val() === "white"; + redrawBoard(); + } + + function undo() { + 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(); + g_pgn.pop(); + g_pgn.pop(); + updatePGN(); + + if (g_playerWhite !== Boolean(g_toMove) && g_allMoves.length !== 0) { + UnmakeMove(g_allMoves[g_allMoves.length - 1]); + g_allMoves.pop(); + } + + redrawBoard(); + } + + + function loadDialog() { + var id = "loadGame"; + if ($("#"+id).length !== 0) { + return false; + } + + var $loadGame = $("<div>") + .attr("id",id) + .attr("title","Load Game") + .appendTo($("body")); + + $('<input>') + .attr("type","file") + .change(function(evt) { + load(evt); + $loadGame.remove(); + }) + .appendTo($loadGame); + + $loadGame + .dialog({ + minWidth:420, + close:function(event,ui) { + $loadGame.remove(); + } + }); + + } + + function load(evt) { + + //Retrieve the first (and only!) File from the FileList object + var file = evt.target.files[0]; + + if (file) { + var reader = new FileReader(); + reader.onload = function(e) { + var contents = e.target.result; + loadPGN(contents); + }; + reader.readAsText(file); + } else { + console.log("Failed to load file"); + } + + } + + function loadFEN(fen) { + g_allMoves = []; + InitializeFromFen(fen); + + EnsureAnalysisStopped(); + InitializeBackgroundEngine(); + + g_playerWhite = !!g_toMove; + g_backgroundEngine.postMessage("position " + GetFen()); + + redrawBoard(); + } + + function loadPGN (pgn) { + var parsedPGN = parsePGN(pgn); + var fen = parsedPGN.fen; + var moves = parsedPGN.sequence; + + g_allMoves = []; + clearPGN(); + if (fen !== null) { + loadFEN(fen); + if (parsedPGN.startColor === BLACK) { + g_pgn.push(".."); + } + } else { + ResetGame(); + } + + function Piece(flag,promo) { + this.flag = flag; + this.promo = promo; + } + + + moves.forEach(function(move) { + var i; + var formatedMove; + var vMoves = GenerateValidMoves(); + var pieces = { + "P": new Piece(piecePawn,null), + "N": new Piece(pieceKnight,moveflagPromoteKnight), + "B": new Piece(pieceBishop,moveflagPromoteBishop), + "R": new Piece(pieceRook,moveflagPromoteRook), + "Q": new Piece(pieceQueen,moveflagPromoteQueen), + "K": new Piece(pieceKing,null) + }; + + // get the piece flag + var piece = pieces[move.piece].flag; // [P,N,B,R,Q,K] + // ge the color flag + var color = (move.color === WHITE) ? 0x8 : 0x0; + + // get the from value + var startList = []; + + // get all square that has this kind of piece + var pieceIdx = (color|piece) << 4; + + while(g_pieceList[pieceIdx] !== 0) { + startList.push(new Cell(FormatSquare(g_pieceList[pieceIdx]))); + pieceIdx++; + } + + var from = move.from; + if (from !== undefined) { + // if we have a precision on the starting square like the columns + // or even the position directly + // We will filter the startList using it + for (i = startList.length - 1; i >= 0; i--) { + if( from.length === 1) { + // only the row is given + + if (from.match(/[a-h]/) && startList[i].position.charAt(0) !== from) { + // different starting row + startList.splice(i,1); + } else if (from.match(/[1-8]/) && startList[i].position.charAt(1) !== from) { + // different starting line + startList.splice(i,1); + } + } else if (from.length === 2) { + // the starting coordinate is given + // this is then just an extra check + if (startList[i].position !== from) { + // different starting coordinate + startList.splice(i,1); + } + } + } + } + + // here we should have a list of starting square + // only one should make a valid move + // paired with the provided destination + + var end = new Cell(move.to); + var endSquare = MakeSquare(end.y, end.x); + + var promotion = (move.promotion) ? pieces[move.promotion.substr(1)].promo : undefined; // remove the "=" + + + // take formatedMove and endSquare in a closure + function checkMove(start) { + var startSquare = MakeSquare(start.y, start.x); + if (promotion !== undefined) { + // we have a promotion so we need to generate a + // specific move and check against it + if(vMoves[i] === GenerateMove(startSquare, endSquare, moveflagPromotion | promotion)) { + formatedMove = vMoves[i]; + } + } else { + // just checking start and end square allows to cover + // all other special moves like "en passant" capture and + // castling + if ( (vMoves[i] & 0xFF) == startSquare && + ((vMoves[i] >> 8) & 0xFF) == endSquare ) { + formatedMove = vMoves[i]; + } + } + } + + // to get the move we will check withing all valide moves + // which one match the hints given by the pgn + + for (i = 0; i < vMoves.length; i++) { + startList.forEach(checkMove); + if (formatedMove) break; + } + + if(formatedMove) { + UIPlayMove(formatedMove,false); + } else { + console.log(move); + throw "Invalid PGN"; + } + }); + + if (g_toMove === colorWhite) { + g_playerWhite = true; + camera.position.x = 0; + camera.position.z = 100; + } else { + g_playerWhite = false; + camera.position.x = 0; + camera.position.z = -100; + } + + EnsureAnalysisStopped(); + if (InitializeBackgroundEngine()) { + g_backgroundEngine.postMessage("position " + GetFen()); + } + + redrawBoard(); + } + + function clearPGN () { + $pgn.val(""); + g_pgn = []; + } + + function addToPGN(move) { + g_pgn.push(GetMoveSAN(move)); + updatePGN(); + } + + function updatePGN() { + + $pgn.val(getPGN()); + $pgn.scrollTop($pgn[0].scrollHeight); + } + + function getPGN() { + var str = ""; + g_pgn.forEach(function(move,i) { + if(i%2 === 0) { + if (move === "..") { + str += ((i/2)+1)+"..."; + } else { + str += ((i/2)+1)+". "+move; + } + } else { + str += " "+move+"\r\n"; + } + }); + return str; + } + + + + function save() { + var filename = "chessSave.pgn"; + var a = document.createElement("a"); + + if (typeof a.download === "undefined") + { + var str = 'data:text/html,' + encodeURIComponent("<p><a download='" + filename + "' href=\"data:application/json," + + encodeURIComponent(getPGN()) + + "\">Download link</a></p>"); + window.open(str); + } else { + // auto download + var body = document.body; + a.textContent = filename; + a.href = "data:application/json," + encodeURIComponent(getPGN()); + a.download = filename; + body.appendChild(a); + var clickEvent = document.createEvent("MouseEvent"); + clickEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + a.dispatchEvent(clickEvent); + body.removeChild(a); + } + + } + + function changePromo(event) { + var choice = $(event.currentTarget).val(); + switch(choice) { + case "Queen": + promotion = moveflagPromoteQueen; + break; + case "Rook": + promotion = moveflagPromoteRook; + break; + case "Bishop": + promotion = moveflagPromoteBishop; + break; + case "Knight": + promotion = moveflagPromoteKnight; + break; + } + } + + function displayCheck() { + if (validMoves.length === 0) { + $info.text(( g_inCheck ? 'Checkmate' : 'Stalemate' )); + } else if (g_inCheck) { + $info.text('Check'); + } else { + $info.text(''); + } + if ($info.text() !== '') { + $info.show("highlight",{},500); + } else { + $info.hide(); + } + } + + window.initGUI = initGUI; + window.initInfo = initInfo; + window.clearPGN = clearPGN; + window.addToPGN = addToPGN; + window.displayCheck = displayCheck; + window.newGame = newGame; + +})();
\ No newline at end of file |
