Browse files

Partially implemented PGN display

  • Loading branch information...
1 parent 00918d0 commit abb9150e19df8d34c35517eb824ef8a3819f43c4 @gisikw committed Sep 19, 2011
Showing with 276 additions and 62 deletions.
  1. +1 −1 Rakefile
  2. +15 −0 jquery.jmate.css
  3. +118 −9 jquery.jmate.js
  4. +14 −7 jquery.jmate.min.js
  5. +0 −42 src/jquery.chess.js
  6. +89 −3 src/jquery.jmate.coffee
  7. +18 −0 src/jquery.jmate.sass
  8. +21 −0 test/index.haml
View
2 Rakefile
@@ -8,7 +8,7 @@ task :default => 'jmate:compile'
namespace :jmate do
desc 'Compile the files'
task :compile do
- `coffee -c -o jquery.jmate.js src/jquery.jmate.coffee`
+ `coffee -c -o . src/jquery.jmate.coffee`
`sass src/jquery.jmate.sass jquery.jmate.css`
`haml test/index.haml index.html`
File.open('jquery.jmate.min.js','w') do |f|
View
15 jquery.jmate.css
@@ -1,6 +1,21 @@
.jquery-chess-board {
position: relative;
border: 1px solid black; }
+ .jquery-chess-board .sidebar {
+ position: absolute;
+ border-left: 1px solid black;
+ border-right: 1px solid black; }
+ .jquery-chess-board .sidebar table {
+ display: block;
+ overflow: auto;
+ border-bottom: 1px solid black; }
+ .jquery-chess-board .sidebar .navigation span {
+ display: block;
+ float: left;
+ width: 50%;
+ height: 100%;
+ text-align: center;
+ line-height: 50px; }
.jquery-chess-board .promotion {
border: 1px solid #666666;
border-radius: 10px;
View
127 jquery.jmate.js
@@ -1,14 +1,11 @@
(function() {
- var $, d, pgnToCoords, pieceDict, symDict, toCart, toFAN, toFile, toIFile, toPiece, validSquare_;
+ var $, d, parsePGN, pieceDict, symDict, toCart, toFAN, toFile, toIFile, toPiece, validSquare_;
var __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i;
}
return -1;
};
- pgnToCoords = function(move) {
- return ["e2", "e4"];
- };
$ = jQuery;
pieceDict = {
P: 'pawn',
@@ -54,8 +51,32 @@
return pieceDict[c] || 'pawn';
}
};
+ parsePGN = function(text) {
+ var i, line, lines, m, moveCount, moveLines, moves, returnable, _i, _len, _ref;
+ returnable = [];
+ lines = text.split("\n");
+ moveLines = [];
+ for (_i = 0, _len = lines.length; _i < _len; _i++) {
+ line = lines[_i];
+ if ($.trim(line)[0] === '[') {
+ continue;
+ }
+ if ($.trim(line).length === 0) {
+ continue;
+ }
+ moveLines.push($.trim(line));
+ }
+ moves = moveLines.join(' ');
+ moveCount = parseInt(moves.match(/\d+\./g).pop());
+ for (i = 1, _ref = moveCount - 1; 1 <= _ref ? i <= _ref : i >= _ref; 1 <= _ref ? i++ : i--) {
+ m = moves.match(new RegExp("" + i + "\\..*" + (i + 1) + "\\.", 'g'))[0].replace("" + i + ".", '').replace("" + (i + 1) + ".", '').split(/\s+/);
+ returnable.push(m[0]);
+ returnable.push(m[1]);
+ }
+ return returnable;
+ };
$.fn.chessboard = function() {
- var activatePieces, allyAt_, b, board, candidateMoves, castle, coord, enPassant, enemyAt_, handler, i, movePiece, pieceAt, pieceMoves, placePiece, promotePawn, size, startTurn, threatens_, turn;
+ var activatePieces, allyAt_, b, board, candidateMoves, castle, coord, displayPGN, enPassant, enemyAt_, handler, i, movePiece, pgn, pgnIndex, pieceAt, pieceMoves, placePiece, promotePawn, sidebar, size, startTurn, threatens_, turn;
castle = {
black: {
long: true,
@@ -67,9 +88,12 @@
}
};
enPassant = null;
+ sidebar = null;
board = $("div").addClass("jquery-chess-board");
size = 50;
turn = 'white';
+ pgn = [];
+ pgnIndex = 0;
window.enPassant = function() {
return enPassant;
};
@@ -87,6 +111,25 @@
top: (8 - parseInt(coords[1])) * size
}).appendTo(board);
};
+ displayPGN = function() {
+ var i, _ref;
+ board.width("" + (12 * size) + "px");
+ sidebar = $('<div>');
+ sidebar.addClass('sidebar').css({
+ left: "" + (8 * size) + "px"
+ }).height(size * 8).width(size * 4).appendTo(board);
+ $('<table>').height(size * 7).appendTo(sidebar);
+ for (i = 0, _ref = pgn.length; i <= _ref; i += 2) {
+ sidebar.find('table').append("<tr><td>" + pgn[i] + "</td><td>" + pgn[i + 1] + "</td></tr>");
+ }
+ $("<div class='navigation'><span class='back'>Back</span><span class='next'>Next</span></div>").height(size).css({
+ left: "" + (8 * size) + "px",
+ top: "" + (7 * size) + "px"
+ }).appendTo(sidebar);
+ return sidebar.find('span.next').click(function() {
+ return handler.next();
+ });
+ };
promotePawn = function(fan) {
var col, dialog, i, piece, _i, _len, _ref;
col = fan[1] === '1' ? 'black' : 'white';
@@ -317,10 +360,10 @@
}
if (!threatCheck) {
opCol = col === 'white' ? 'black' : 'white';
- if (castle[col]['short'] && (!(pieceAt(toFAN(x + 1, y)) != null)) && (!(pieceAt(toFAN(x + 2, y)) != null)) && (!threatens_(toFAN(x, y), opCol)) && (!threatens_(toFAN(x + 1, y), opCol)) && (!threatens(toFAN(x + 2, y), opCol))) {
+ if (castle[col]['short'] && (!(pieceAt(toFAN(x + 1, y)) != null)) && (!(pieceAt(toFAN(x + 2, y)) != null)) && (!threatens_(toFAN(x, y), opCol)) && (!threatens_(toFAN(x + 1, y), opCol)) && (!threatens_(toFAN(x + 2, y), opCol))) {
returnable.push(toFAN(x + 2, y));
}
- if (castle[col]['long'] && (!(pieceAt(toFAN(x - 1, y)) != null)) && (!(pieceAt(toFAN(x - 2, y)) != null)) && (!pieceAt(toFAN(x - 3, y))) && (!threatens_(toFAN(x, y), opCol)) && (!threatens_(toFAN(x - 1, y), opCol)) && (!threatens(toFAN(x - 2, y), opCol))) {
+ if (castle[col]['long'] && (!(pieceAt(toFAN(x - 1, y)) != null)) && (!(pieceAt(toFAN(x - 2, y)) != null)) && (!pieceAt(toFAN(x - 3, y))) && (!threatens_(toFAN(x, y), opCol)) && (!threatens_(toFAN(x - 1, y), opCol)) && (!threatens_(toFAN(x - 2, y), opCol))) {
returnable.push(toFAN(x - 2, y));
}
}
@@ -482,12 +525,79 @@
_results.push(parseInt(c) ? i += parseInt(c) : (placePiece(toPiece(c, true), toFile((i % 8) + 1) + (8 - (Math.floor(i / 8)))), i++));
}
return _results;
+ },
+ setPGN: function(text) {
+ pgn = parsePGN(text);
+ return displayPGN();
+ },
+ next: function() {
+ this.movePGN(pgn[pgnIndex]);
+ return pgnIndex++;
+ },
+ movePGN: function(move) {
+ var castleRank, moved, pawn, piece, target, _i, _j, _k, _l, _len, _len2, _len3, _len4, _len5, _m, _ref, _ref2, _ref3, _ref4, _ref5, _ref6;
+ castleRank = turn === 'white' ? 1 : 8;
+ target = move.substring(move.length - 2);
+ if (move === 'O-O') {
+ movePiece("e" + castleRank, "g" + castleRank);
+ movePiece("h" + castleRank, "f" + castleRank);
+ } else if (move === 'O-O-O') {
+ movePiece("e" + castleRank, "c" + castleRank);
+ movePiece("a" + castleRank, "d" + castleRank);
+ } else if (move.length === 2) {
+ moved = false;
+ _ref = b(".pawn." + turn);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ pawn = _ref[_i];
+ if ($(pawn).data('pos') === move[0] + (parseInt(move[1]) + (turn === 'white' ? -1 : 1))) {
+ movePiece($(pawn).data('pos'), move);
+ moved = true;
+ }
+ }
+ if (!moved && move[1] === (turn === 'white' ? '4' : '5')) {
+ movePiece("" + move[0] + (turn === 'white' ? 2 : 7), move);
+ }
+ } else if (move.length === 3) {
+ _ref2 = b("." + pieceDict[move[0]] + "." + turn);
+ for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
+ piece = _ref2[_j];
+ if (__indexOf.call(candidateMoves($(piece).data('type'), $(piece).data('pos')), target) >= 0) {
+ movePiece($(piece).data('pos'), target);
+ }
+ }
+ } else if (__indexOf.call(move, 'x') >= 0 && move.length === 4) {
+ if (move[0].toUpperCase() === move[0]) {
+ _ref3 = b("." + pieceDict[move[0]] + "." + turn);
+ for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
+ piece = _ref3[_k];
+ if (__indexOf.call(candidateMoves($(piece).data('type'), $(piece).data('pos')), target) >= 0) {
+ movePiece($(piece).data('pos'), target);
+ }
+ }
+ } else {
+ _ref4 = b(".pawn." + turn);
+ for (_l = 0, _len4 = _ref4.length; _l < _len4; _l++) {
+ pawn = _ref4[_l];
+ if ($(pawn).data('pos')[0] === move[0]) {
+ movePiece($(pawn).data('pos'), target);
+ }
+ }
+ }
+ } else {
+ _ref5 = b("." + pieceDict[move[0]] + "." + turn);
+ for (_m = 0, _len5 = _ref5.length; _m < _len5; _m++) {
+ piece = _ref5[_m];
+ if ((_ref6 = move[1], __indexOf.call($(piece).data('pos'), _ref6) >= 0) && __indexOf.call(candidateMoves($(piece).data('type'), $(piece).data('pos')), target) >= 0) {
+ movePiece($(piece).data('pos'), target);
+ }
+ }
+ }
+ return turn = turn === "white" ? "black" : "white";
}
};
$(this).addClass('jquery-chess-wrapper').css({
background: 'transparent'
});
- board.height(size * 8).width(size * 8).appendTo(this);
for (i = 0; i <= 63; i++) {
coord = toFile((i % 8) + 1) + (8 - (Math.floor(i / 8)));
$('<div>').addClass("square " + ((i + Math.floor(i / 8)) % 2 === 0 ? 'light' : 'dark') + " " + coord).width(size).height(size).data('pos', coord).offset({
@@ -558,5 +668,4 @@
startTurn();
return handler;
};
- window.pgnToCoords = pgnToCoords;
}).call(this);
View
21 jquery.jmate.min.js
@@ -1,7 +1,12 @@
-(function(){var $,d,pgnToCoords,pieceDict,symDict,toCart,toFAN,toFile,toIFile,toPiece,validSquare_;var __indexOf=Array.prototype.indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(this[i]===item)return i;}
-return-1;};pgnToCoords=function(move){return["e2","e4"];};$=jQuery;pieceDict={P:'pawn',K:'king',N:'knight',B:'bishop',R:'rook',Q:'queen'};symDict={pawn:'P',knight:'N',bishop:'B',rook:'R',queen:'Q',king:'K'};validSquare_=function(x,y){return(0<x&&x<9)&&(0<y&&y<9);};toIFile=function(c){return'abcdefgh'.indexOf(c)+1;};toFile=function(i){return'abcdefgh'[i-1];};toFAN=function(x,y){return""+(toFile(x))+y;};toCart=function(fan){return[toIFile(fan[0]),parseInt(fan[1])];};d=function(message){return console.debug(message);};toPiece=function(c,col){if(col==null){col=false;}
-if(col){return""+(c.toUpperCase()===c?'white':'black')+" "+(pieceDict[c.toUpperCase()]||'pawn');}else{return pieceDict[c]||'pawn';}};$.fn.chessboard=function(){var activatePieces,allyAt_,b,board,candidateMoves,castle,coord,enPassant,enemyAt_,handler,i,movePiece,pieceAt,pieceMoves,placePiece,promotePawn,size,startTurn,threatens_,turn;castle={black:{long:true,short:true},white:{long:true,short:true}};enPassant=null;board=$("div").addClass("jquery-chess-board");size=50;turn='white';window.enPassant=function(){return enPassant;};b=function(selector){return board.find(selector);};startTurn=function(){b('.piece').draggable('option','disabled',true);return b(".piece."+turn).draggable('option','disabled',false);};placePiece=function(type,coords){b("."+coords).data('contents',type);return $('<div>').addClass("piece "+type).width(size).height(size).data('pos',coords).data('type',type).offset({left:(toIFile(coords[0])-1)*size,top:(8-parseInt(coords[1]))*size}).appendTo(board);};promotePawn=function(fan){var col,dialog,i,piece,_i,_len,_ref;col=fan[1]==='1'?'black':'white';dialog=$('<div>');dialog.addClass('promotion').height(size*3).width(size*5).offset({left:size*1.5,top:size*2.5}).appendTo(board);$('<p><strong>Promote to</strong></p>').css({'line-height':""+size+"px"}).appendTo(dialog);i=0;_ref=['queen','rook','bishop','knight'];for(_i=0,_len=_ref.length;_i<_len;_i++){piece=_ref[_i];$('<div>').addClass("promote piece "+piece+" "+col).data('square',fan).data('type',""+col+" "+piece).width(size).height(size).offset({left:(i+0.5)*size}).appendTo(dialog);i++;}
+(function(){var $,d,parsePGN,pieceDict,symDict,toCart,toFAN,toFile,toIFile,toPiece,validSquare_;var __indexOf=Array.prototype.indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(this[i]===item)return i;}
+return-1;};$=jQuery;pieceDict={P:'pawn',K:'king',N:'knight',B:'bishop',R:'rook',Q:'queen'};symDict={pawn:'P',knight:'N',bishop:'B',rook:'R',queen:'Q',king:'K'};validSquare_=function(x,y){return(0<x&&x<9)&&(0<y&&y<9);};toIFile=function(c){return'abcdefgh'.indexOf(c)+1;};toFile=function(i){return'abcdefgh'[i-1];};toFAN=function(x,y){return""+(toFile(x))+y;};toCart=function(fan){return[toIFile(fan[0]),parseInt(fan[1])];};d=function(message){return console.debug(message);};toPiece=function(c,col){if(col==null){col=false;}
+if(col){return""+(c.toUpperCase()===c?'white':'black')+" "+(pieceDict[c.toUpperCase()]||'pawn');}else{return pieceDict[c]||'pawn';}};parsePGN=function(text){var i,line,lines,m,moveCount,moveLines,moves,returnable,_i,_len,_ref;returnable=[];lines=text.split("\n");moveLines=[];for(_i=0,_len=lines.length;_i<_len;_i++){line=lines[_i];if($.trim(line)[0]==='['){continue;}
+if($.trim(line).length===0){continue;}
+moveLines.push($.trim(line));}
+moves=moveLines.join(' ');moveCount=parseInt(moves.match(/\d+\./g).pop());for(i=1,_ref=moveCount-1;1<=_ref?i<=_ref:i>=_ref;1<=_ref?i++:i--){m=moves.match(new RegExp(""+i+"\\..*"+(i+1)+"\\.",'g'))[0].replace(""+i+".",'').replace(""+(i+1)+".",'').split(/\s+/);returnable.push(m[0]);returnable.push(m[1]);}
+return returnable;};$.fn.chessboard=function(){var activatePieces,allyAt_,b,board,candidateMoves,castle,coord,displayPGN,enPassant,enemyAt_,handler,i,movePiece,pgn,pgnIndex,pieceAt,pieceMoves,placePiece,promotePawn,sidebar,size,startTurn,threatens_,turn;castle={black:{long:true,short:true},white:{long:true,short:true}};enPassant=null;sidebar=null;board=$("div").addClass("jquery-chess-board");size=50;turn='white';pgn=[];pgnIndex=0;window.enPassant=function(){return enPassant;};b=function(selector){return board.find(selector);};startTurn=function(){b('.piece').draggable('option','disabled',true);return b(".piece."+turn).draggable('option','disabled',false);};placePiece=function(type,coords){b("."+coords).data('contents',type);return $('<div>').addClass("piece "+type).width(size).height(size).data('pos',coords).data('type',type).offset({left:(toIFile(coords[0])-1)*size,top:(8-parseInt(coords[1]))*size}).appendTo(board);};displayPGN=function(){var i,_ref;board.width(""+(12*size)+"px");sidebar=$('<div>');sidebar.addClass('sidebar').css({left:""+(8*size)+"px"}).height(size*8).width(size*4).appendTo(board);$('<table>').height(size*7).appendTo(sidebar);for(i=0,_ref=pgn.length;i<=_ref;i+=2){sidebar.find('table').append("<tr><td>"+pgn[i]+"</td><td>"+pgn[i+1]+"</td></tr>");}
+$("<div class='navigation'><span class='back'>Back</span><span class='next'>Next</span></div>").height(size).css({left:""+(8*size)+"px",top:""+(7*size)+"px"}).appendTo(sidebar);return sidebar.find('span.next').click(function(){return handler.next();});};promotePawn=function(fan){var col,dialog,i,piece,_i,_len,_ref;col=fan[1]==='1'?'black':'white';dialog=$('<div>');dialog.addClass('promotion').height(size*3).width(size*5).offset({left:size*1.5,top:size*2.5}).appendTo(board);$('<p><strong>Promote to</strong></p>').css({'line-height':""+size+"px"}).appendTo(dialog);i=0;_ref=['queen','rook','bishop','knight'];for(_i=0,_len=_ref.length;_i<_len;_i++){piece=_ref[_i];$('<div>').addClass("promote piece "+piece+" "+col).data('square',fan).data('type',""+col+" "+piece).width(size).height(size).offset({left:(i+0.5)*size}).appendTo(dialog);i++;}
return b('.promote').click(function(){var square,type;square=$(this).data('square');type=$(this).data('type');pieceAt(square).remove();placePiece(type,square);dialog.remove();activatePieces();turn=turn==="white"?"black":"white";return startTurn();});};pieceAt=function(coords,ignore,add){var elem,type,_i,_len,_ref;if(coords===ignore){return null;}
if(coords===add){return true;}
type=b("."+coords).data('contents');if(!(type!=null)){return null;}
@@ -38,8 +43,8 @@ if(validSquare_(x,y-1)&&!allyAt_(toFAN(x,y-1),col,ignore,add)){returnable.push(t
if(validSquare_(x-1,y-1)&&!allyAt_(toFAN(x-1,y-1),col,ignore,add)){returnable.push(toFAN(x-1,y-1));}
if(validSquare_(x-1,y)&&!allyAt_(toFAN(x-1,y),col,ignore,add)){returnable.push(toFAN(x-1,y));}
if(validSquare_(x-1,y+1)&&!allyAt_(toFAN(x-1,y+1),col,ignore,add)){returnable.push(toFAN(x-1,y+1));}
-if(!threatCheck){opCol=col==='white'?'black':'white';if(castle[col]['short']&&(!(pieceAt(toFAN(x+1,y))!=null))&&(!(pieceAt(toFAN(x+2,y))!=null))&&(!threatens_(toFAN(x,y),opCol))&&(!threatens_(toFAN(x+1,y),opCol))&&(!threatens(toFAN(x+2,y),opCol))){returnable.push(toFAN(x+2,y));}
-if(castle[col]['long']&&(!(pieceAt(toFAN(x-1,y))!=null))&&(!(pieceAt(toFAN(x-2,y))!=null))&&(!pieceAt(toFAN(x-3,y)))&&(!threatens_(toFAN(x,y),opCol))&&(!threatens_(toFAN(x-1,y),opCol))&&(!threatens(toFAN(x-2,y),opCol))){returnable.push(toFAN(x-2,y));}}
+if(!threatCheck){opCol=col==='white'?'black':'white';if(castle[col]['short']&&(!(pieceAt(toFAN(x+1,y))!=null))&&(!(pieceAt(toFAN(x+2,y))!=null))&&(!threatens_(toFAN(x,y),opCol))&&(!threatens_(toFAN(x+1,y),opCol))&&(!threatens_(toFAN(x+2,y),opCol))){returnable.push(toFAN(x+2,y));}
+if(castle[col]['long']&&(!(pieceAt(toFAN(x-1,y))!=null))&&(!(pieceAt(toFAN(x-2,y))!=null))&&(!pieceAt(toFAN(x-3,y)))&&(!threatens_(toFAN(x,y),opCol))&&(!threatens_(toFAN(x-1,y),opCol))&&(!threatens_(toFAN(x-2,y),opCol))){returnable.push(toFAN(x-2,y));}}
return returnable;},pawn:function(x,y,col,threatCheck,ignore,add){var returnable,yMod;returnable=[];yMod=col==="white"?1:-1;if(!threatCheck){if(pieceAt(toFAN(x,y+yMod))==null){returnable.push(toFAN(x,y+yMod));if(y===(col==="white"?2:7)&&!pieceAt(toFAN(x+yMod*2),ignore,add)){returnable.push(toFAN(x,y+yMod*2));}}}
if(x<8&&(enemyAt_(toFAN(x+1,y+yMod),col,ignore,add)||threatCheck)||(enPassant===toFAN(x+1,y+yMod))){returnable.push(toFAN(x+1,y+yMod));}
if(x>1&&(enemyAt_(toFAN(x-1,y+yMod),col,ignore,add)||threatCheck)||(enPassant===toFAN(x-1,y+yMod))){returnable.push(toFAN(x-1,y+yMod));}
@@ -62,7 +67,9 @@ if(counter>0){returnable+=counter;}
if(rank>1){returnable+='/';}}
return returnable;},setFEN:function(fenString){var c,fen,i,_i,_len,_ref,_results;this.reset;fen=fenString.split(' ');castle['black']['short']=__indexOf.call(fen[2],'k')>=0;castle['white']['short']=__indexOf.call(fen[2],'K')>=0;castle['black']['long']=__indexOf.call(fen[2],'q')>=0;castle['white']['long']=__indexOf.call(fen[2],'Q')>=0;enPassant=fen[3]==='-'?null:fen[3];turn=fen[1]==='w'?'white':'black';i=0;_ref=fen[0].split('');_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){c=_ref[_i];if(c==='/'){continue;}
_results.push(parseInt(c)?i+=parseInt(c):(placePiece(toPiece(c,true),toFile((i%8)+1)+(8-(Math.floor(i/8)))),i++));}
-return _results;}};$(this).addClass('jquery-chess-wrapper').css({background:'transparent'});board.height(size*8).width(size*8).appendTo(this);for(i=0;i<=63;i++){coord=toFile((i%8)+1)+(8-(Math.floor(i/8)));$('<div>').addClass("square "+((i+Math.floor(i/8))%2===0?'light':'dark')+" "+coord).width(size).height(size).data('pos',coord).offset({top:Math.floor(i/8)*size,left:i%8*size}).appendTo(board);}
+return _results;},setPGN:function(text){pgn=parsePGN(text);return displayPGN();},next:function(){this.movePGN(pgn[pgnIndex]);return pgnIndex++;},movePGN:function(move){var castleRank,moved,pawn,piece,target,_i,_j,_k,_l,_len,_len2,_len3,_len4,_len5,_m,_ref,_ref2,_ref3,_ref4,_ref5,_ref6;castleRank=turn==='white'?1:8;target=move.substring(move.length-2);if(move==='O-O'){movePiece("e"+castleRank,"g"+castleRank);movePiece("h"+castleRank,"f"+castleRank);}else if(move==='O-O-O'){movePiece("e"+castleRank,"c"+castleRank);movePiece("a"+castleRank,"d"+castleRank);}else if(move.length===2){moved=false;_ref=b(".pawn."+turn);for(_i=0,_len=_ref.length;_i<_len;_i++){pawn=_ref[_i];if($(pawn).data('pos')===move[0]+(parseInt(move[1])+(turn==='white'?-1:1))){movePiece($(pawn).data('pos'),move);moved=true;}}
+if(!moved&&move[1]===(turn==='white'?'4':'5')){movePiece(""+move[0]+(turn==='white'?2:7),move);}}else if(move.length===3){_ref2=b("."+pieceDict[move[0]]+"."+turn);for(_j=0,_len2=_ref2.length;_j<_len2;_j++){piece=_ref2[_j];if(__indexOf.call(candidateMoves($(piece).data('type'),$(piece).data('pos')),target)>=0){movePiece($(piece).data('pos'),target);}}}else if(__indexOf.call(move,'x')>=0&&move.length===4){if(move[0].toUpperCase()===move[0]){_ref3=b("."+pieceDict[move[0]]+"."+turn);for(_k=0,_len3=_ref3.length;_k<_len3;_k++){piece=_ref3[_k];if(__indexOf.call(candidateMoves($(piece).data('type'),$(piece).data('pos')),target)>=0){movePiece($(piece).data('pos'),target);}}}else{_ref4=b(".pawn."+turn);for(_l=0,_len4=_ref4.length;_l<_len4;_l++){pawn=_ref4[_l];if($(pawn).data('pos')[0]===move[0]){movePiece($(pawn).data('pos'),target);}}}}else{_ref5=b("."+pieceDict[move[0]]+"."+turn);for(_m=0,_len5=_ref5.length;_m<_len5;_m++){piece=_ref5[_m];if((_ref6=move[1],__indexOf.call($(piece).data('pos'),_ref6)>=0)&&__indexOf.call(candidateMoves($(piece).data('type'),$(piece).data('pos')),target)>=0){movePiece($(piece).data('pos'),target);}}}
+return turn=turn==="white"?"black":"white";}};$(this).addClass('jquery-chess-wrapper').css({background:'transparent'});for(i=0;i<=63;i++){coord=toFile((i%8)+1)+(8-(Math.floor(i/8)));$('<div>').addClass("square "+((i+Math.floor(i/8))%2===0?'light':'dark')+" "+coord).width(size).height(size).data('pos',coord).offset({top:Math.floor(i/8)*size,left:i%8*size}).appendTo(board);}
b('.square').droppable({disabled:true,drop:function(ev,ui){var ep,opCol,promote,rank,typeArray,x,y,_ref,_ref2,_ref3,_ref4;ui.draggable.offset($(this).offset());ui.draggable.data('pos',$(this).data('pos'));typeArray=ui.draggable.data('type').split(' ');ep=null;promote=null;if(typeArray[1]==="pawn"){if((_ref=$(this).data('pos')[1])==='1'||_ref==='8'){promote=true;promotePawn($(this).data('pos'));}
if($(this).data('pos')===enPassant){pieceAt(""+enPassant[0]+(enPassant[1]==='6'?'5':'4')).remove();b("."+enPassant[0]+(enPassant[1]==='6'?'5':'4')).data('contents',null);}
if(Math.abs(parseInt(ui.draggable.data('oldPos')[1])-parseInt($(this).data('pos')[1]))===2){_ref2=toCart($(this).data('pos')),x=_ref2[0],y=_ref2[1];opCol=typeArray[0]==='white'?'black':'white';if((validSquare_(x+1,y)&&((_ref3=pieceAt(toFAN(x+1,y)))!=null?_ref3.data('type'):void 0)===(""+opCol+" pawn"))||(validSquare_(x-1,y)&&((_ref4=pieceAt(toFAN(x-1,y)))!=null?_ref4.data('type'):void 0)===(""+opCol+" pawn"))){ep=toFAN(x,y+(typeArray[0]==='white'?-1:1));}}}
@@ -71,4 +78,4 @@ if($(this).data('pos')[0]==='c'){movePiece('a'+rank,'d'+rank);}}}
if(typeArray[1]==='rook'){rank=typeArray[0]==='white'?1:8;if(castle[typeArray[0]]['short']&&ui.draggable.data('oldPos')===("h"+rank)){castle[typeArray[0]]['short']=false;}
if(castle[typeArray[0]]['long']&&ui.draggable.data('oldPos')===("a"+rank)){castle[typeArray[0]]['long']=false;}}
if($(this).data('contents')){pieceAt($(this).data('pos')).remove();}
-if(promote==null){turn=turn==="white"?"black":"white";return startTurn();}}});handler.setFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");activatePieces();startTurn();return handler;};window.pgnToCoords=pgnToCoords;}).call(this);
+if(promote==null){turn=turn==="white"?"black":"white";return startTurn();}}});handler.setFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");activatePieces();startTurn();return handler;};}).call(this);
View
42 src/jquery.chess.js
@@ -1,42 +0,0 @@
-function movePGN(string,color){
- console.debug(color + " moves "+string)
- // Castling
- var target = string.substring(string.length-2)
- if(string.length == 2){
- // Pawn move
- $(".pawn."+color).each(function(i,piece){
- if($(piece).data('pos')==(string[0]+(parseInt(string[1])+(color=="white" ? -1 : 1)))){
- movePiece($(piece).data('pos'),target)
- return
- }
- })
- if(target[1] == (color == "white" ? 4 : 5) && $("."+target[0]+(color=="white" ? 2 : 7)).data('contents')==(color+" pawn")){
- movePiece(target[0]+(color=="white" ? 2 : 7),target)
- return
- }
- } else if(string.length == 3){
- var pieceName = toPiece(string[0])
- $("."+pieceName+"."+color).each(function(i,piece){
- if($.inArray(target,candidateMoves($(this).data('type'),$(this).data('pos')))>-1){
- movePiece($(this).data('pos'),target)
- return
- }
- })
- } else if(string[string.length-3]=="x"){
- if(string.length == 4){
- var pieceName = toPiece(string[0])
- $("."+pieceName+"."+color).each(function(i,piece){
- if($.inArray(target,candidateMoves($(piece).data('type'),$(piece).data('pos')))>-1){
- if(pieceName != "pawn" || $(piece).data('pos')[0]==string[0]){
- movePiece($(piece).data('pos'),target)
- return
- }
- }
- })
- } else {
- console.debug("Not set up to handle non-ambiguous captures")
- }
- } else {
- console.debug("Not set up to handle non-ambiguous moves")
- }
-}
View
92 src/jquery.jmate.coffee
@@ -33,6 +33,25 @@ toPiece = (c,col = false) ->
else
pieceDict[c] || 'pawn'
+parsePGN = (text) ->
+ returnable = []
+ lines = text.split("\n")
+ moveLines = []
+ for line in lines
+ continue if $.trim(line)[0] is '['
+ continue if $.trim(line).length is 0
+ moveLines.push($.trim(line))
+ moves = moveLines.join(' ')
+ moveCount = parseInt(moves.match(/\d+\./g).pop())
+ for i in [1..moveCount-1]
+ m = moves.match(new RegExp("#{i}\\..*#{i+1}\\.",'g'))[0]
+ .replace("#{i}.",'')
+ .replace("#{i+1}.",'')
+ .split(/\s+/)
+ returnable.push(m[0])
+ returnable.push(m[1])
+ returnable
+
# Plugin
$.fn.chessboard = ->
# Instance Variables
@@ -44,9 +63,12 @@ $.fn.chessboard = ->
long: true
short: true
enPassant = null
+ sidebar = null
board = $("div").addClass "jquery-chess-board"
size = 50 # Probably should accept a size parameter
turn = 'white'
+ pgn = []
+ pgnIndex = 0
window.enPassant = ->
enPassant
@@ -70,6 +92,27 @@ $.fn.chessboard = ->
top: (8-parseInt(coords[1]))*size
.appendTo board
+ displayPGN = ->
+ board.width("#{12*size}px")
+ sidebar = $('<div>')
+ sidebar
+ .addClass('sidebar')
+ .css({left:"#{8*size}px"})
+ .height(size*8)
+ .width(size*4)
+ .appendTo(board)
+ $('<table>')
+ .height(size*7)
+ .appendTo(sidebar)
+ for i in [0..pgn.length] by 2
+ sidebar.find('table').append("<tr><td>#{pgn[i]}</td><td>#{pgn[i+1]}</td></tr>")
+ $("<div class='navigation'><span class='back'>Back</span><span class='next'>Next</span></div>")
+ .height(size)
+ .css({left:"#{8*size}px",top:"#{7*size}px"})
+ .appendTo(sidebar)
+ sidebar.find('span.next').click ->
+ handler.next()
+
promotePawn = (fan) ->
col = if fan[1] is '1' then 'black' else 'white'
dialog = $('<div>')
@@ -225,8 +268,8 @@ $.fn.chessboard = ->
returnable.push(toFAN(x-1,y+1)) if validSquare_(x-1,y+1) and not allyAt_(toFAN(x-1,y+1),col,ignore,add)
unless threatCheck
opCol = if col is 'white' then 'black' else 'white'
- returnable.push(toFAN(x+2,y)) if castle[col]['short'] and (!pieceAt(toFAN(x+1,y))?) and (!pieceAt(toFAN(x+2,y))?) and (!threatens_(toFAN(x,y),opCol)) and (!threatens_(toFAN(x+1,y),opCol)) and (!threatens(toFAN(x+2,y),opCol))
- returnable.push(toFAN(x-2,y)) if castle[col]['long'] and (!pieceAt(toFAN(x-1,y))?) and (!pieceAt(toFAN(x-2,y))?) and (!pieceAt(toFAN(x-3,y))) and (!threatens_(toFAN(x,y),opCol)) and (!threatens_(toFAN(x-1,y),opCol)) and (!threatens(toFAN(x-2,y),opCol))
+ returnable.push(toFAN(x+2,y)) if castle[col]['short'] and (!pieceAt(toFAN(x+1,y))?) and (!pieceAt(toFAN(x+2,y))?) and (!threatens_(toFAN(x,y),opCol)) and (!threatens_(toFAN(x+1,y),opCol)) and (!threatens_(toFAN(x+2,y),opCol))
+ returnable.push(toFAN(x-2,y)) if castle[col]['long'] and (!pieceAt(toFAN(x-1,y))?) and (!pieceAt(toFAN(x-2,y))?) and (!pieceAt(toFAN(x-3,y))) and (!threatens_(toFAN(x,y),opCol)) and (!threatens_(toFAN(x-1,y),opCol)) and (!threatens_(toFAN(x-2,y),opCol))
returnable
pawn: (x,y,col,threatCheck,ignore,add) ->
returnable = []
@@ -338,12 +381,55 @@ $.fn.chessboard = ->
placePiece(toPiece(c,true),toFile((i%8)+1) + (8-(Math.floor(i/8))))
i++
+ setPGN: (text) ->
+ pgn = parsePGN(text)
+ displayPGN()
+
+ next: ->
+ @movePGN(pgn[pgnIndex])
+ pgnIndex++
+
movePGN: (move) ->
castleRank = if turn is 'white' then 1 else 8
+ target = move.substring(move.length-2)
+ if move is 'O-O'
+ movePiece("e#{castleRank}","g#{castleRank}")
+ movePiece("h#{castleRank}","f#{castleRank}")
+ else if move is 'O-O-O'
+ movePiece("e#{castleRank}","c#{castleRank}")
+ movePiece("a#{castleRank}","d#{castleRank}")
+ else if move.length is 2
+ moved = false
+ for pawn in b(".pawn.#{turn}")
+ if $(pawn).data('pos') is move[0] + (parseInt(move[1]) + (if turn is 'white' then -1 else 1))
+ movePiece($(pawn).data('pos'),move)
+ moved = true
+ if !moved and move[1] is (if turn is 'white' then '4' else '5')
+ movePiece("#{move[0]}#{if turn is 'white' then 2 else 7}",move)
+ else if move.length is 3
+ for piece in b(".#{pieceDict[move[0]]}.#{turn}")
+ if target in candidateMoves($(piece).data('type'),$(piece).data('pos'))
+ movePiece($(piece).data('pos'),target)
+ else if 'x' in move and move.length is 4
+ if move[0].toUpperCase() is move[0]
+ for piece in b(".#{pieceDict[move[0]]}.#{turn}")
+ if target in candidateMoves($(piece).data('type'),$(piece).data('pos'))
+ movePiece($(piece).data('pos'),target)
+ else
+ for pawn in b(".pawn.#{turn}")
+ if $(pawn).data('pos')[0] is move[0]
+ movePiece($(pawn).data('pos'),target)
+ else
+ for piece in b(".#{pieceDict[move[0]]}.#{turn}")
+ if move[1] in $(piece).data('pos') and target in candidateMoves($(piece).data('type'),$(piece).data('pos'))
+ movePiece($(piece).data('pos'),target)
+
+ turn = if turn is "white" then "black" else "white"
+
# Main
$(@).addClass('jquery-chess-wrapper').css({background:'transparent'})
- board.height(size*8).width(size*8).appendTo(@)
+ #board.height(size*8).width(size*8).appendTo(@)
# Create Squares
for i in [0..63]
View
18 src/jquery.jmate.sass
@@ -2,6 +2,24 @@
position: relative
border: 1px solid black
+ .sidebar
+ position: absolute
+ border-left: 1px solid black
+ border-right: 1px solid black
+ table
+ display: block
+ overflow: auto
+ border-bottom: 1px solid black
+ .navigation
+ span
+ display: block
+ float: left
+ width: 50%
+ height: 100%
+ text-align: center
+ // The following line should be set in the JS
+ line-height: 50px
+
.promotion
border: 1px solid #666
border-radius: 10px
View
21 test/index.haml
@@ -6,10 +6,31 @@
%script{:src=>"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"}
%script{:src=>'jquery.jmate.js'}
%link{:href=>"jquery.jmate.css",:type=>"text/css",:rel=>"stylesheet"}
+ %script#pgn{:type=>"text/pgn"}
+ :plain
+ [Event "Earl tourn"]
+ [Site "?"]
+ [Date "1906.??.??"]
+ [Round "?"]
+ [White "Savrov"]
+ [Black "Alekhine, Alexander"]
+ [Result "0-1"]
+ [WhiteElo ""]
+ [BlackElo ""]
+ [ECO "C30"]
+
+ 1.e4 e5 2.f4 Bc5 3.Nf3 d6 4.c3 Bg4 5.Be2 Bxf3 6.Bxf3 Nc6 7.b4 Bb6 8.b5 Nce7
+ 9.d4 exd4 10.cxd4 Nf6 11.O-O O-O 12.Bb2 d5 13.e5 Nd7 14.Nc3 c6 15.Qd3 Ng6
+ 16.g3 f5 17.Kh1 Qe7 18.Nxd5 cxd5 19.Bxd5+ Kh8 20.Ba3 Qd8 21.Bxb7 Rb8 22.Bxf8 Ndxf8
+ 23.Bc6 Qxd4 24.Qxf5 Ne7 25.Qc2 Rc8 26.Rad1 Qb4 27.Rb1 Qa5 28.Rf3 Nxc6 29.Rc3 Rd8
+ 30.bxc6 Qd5+ 31.Qg2 Qd1+ 32.Qf1 Qd5+ 33.Qf3 Qxa2 34.Rd1 Rxd1+ 35.Qxd1 Ne6
+ 36.Qf3 Qb1+ 37.Kg2 g6 38.Qd3 Qg1+ 39.Kh3 h5 40.Qc4 Qd1 41.Rc1 Qg4+ 42.Kg2 h4
+ 43.Qf1 g5 44.Qd1 Nxf4+ 45.Kh1 0-1
%script
:plain
$(function(){
window.board = $('chess').chessboard()
+ window.board.setPGN($('#pgn').text())
})
%body
#chess{:style=>"width: 400px; height: 400px;"}

0 comments on commit abb9150

Please sign in to comment.