play.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. var $side = 'w';
  2. var $piece = null;
  3. var $chess = new Chess();
  4. function selectPiece(el) { // add html class which highlights the square according to css
  5. el.addClass('selected');
  6. }
  7. function unselectPiece(el) { // remove highlighting
  8. el.removeClass('selected');
  9. }
  10. function isSelected(el) { // function checks if chess piece is selected
  11. if (el) {
  12. return el.hasClass('selected');
  13. } else {
  14. return false;
  15. }
  16. }
  17. function movePiece(from, to, promotion, rcvd) { // function moves the piece
  18. var move = $chess.move({
  19. 'from': from,
  20. 'to': to,
  21. promotion: promotion
  22. });
  23. if (move) {
  24. var tdFrom = $('td.' + from.toUpperCase());
  25. var tdTo = $('td.' + to.toUpperCase());
  26. //check if last moves are highlighted
  27. if($('td').hasClass('last-target')){
  28. //if so, remove highlight of last move
  29. //and highlight current move instead
  30. $('td').removeClass('last-target');
  31. $('td').removeClass('last-origin');
  32. tdFrom.addClass('last-origin');
  33. tdTo.addClass('last-target');
  34. } else{
  35. // otherwise highlight current move
  36. tdFrom.addClass('last-origin');
  37. tdTo.addClass('last-target');
  38. }
  39. var piece = tdFrom.find('a'); // find out what piece is being moved
  40. var moveSnd = $("#moveSnd")[0]; // sound file variable
  41. unselectPiece(piece.parent());
  42. tdTo.html(piece); // replace td attributes
  43. $piece = null;
  44. // en passant move
  45. if (move.flags == 'e'){
  46. var enpassant = move.to.charAt(0) + move.from.charAt(1);
  47. $('td.' + enpassant.toUpperCase()).html('');
  48. }
  49. //kingside castling
  50. if (move.flags == 'k'){
  51. if (move.to == 'g1'){
  52. var rook = $('td.H1').find('a');
  53. $('td.F1').html(rook);
  54. }
  55. else if (move.to == 'g8'){
  56. var rook = $('td.H8').find('a');
  57. $('td.F8').html(rook);
  58. }
  59. }
  60. //queenside castling
  61. if (move.flags == 'q'){
  62. if (move.to == 'c1'){
  63. var rook = $('td.A1').find('a');
  64. $('td.D1').html(rook);
  65. }
  66. else if (move.to == 'c8'){
  67. var rook = $('td.A8').find('a');
  68. $('td.D8').html(rook);
  69. }
  70. }
  71. //promotion
  72. if (move.flags == 'np' || move.flags == 'cp'){
  73. var square = $('td.' + move.to.toUpperCase()).find('a');
  74. var option = move.promotion;
  75. if (square.hasClass('white')){
  76. switch(true){
  77. case(option == 'q'):
  78. square.html('♕');
  79. break;
  80. case(option == 'r'):
  81. square.html('♖');
  82. break;
  83. case(option == 'n'):
  84. square.html('♘');
  85. break;
  86. case(option == 'b'):
  87. square.html('♗');
  88. break;
  89. }
  90. } else {
  91. switch(true){
  92. case(option == 'q'):
  93. square.html('♛');
  94. break;
  95. case(option == 'r'):
  96. square.html('♜');
  97. break;
  98. case(option == 'n'):
  99. square.html('♞');
  100. break;
  101. case(option == 'b'):
  102. square.html('♝');
  103. break;
  104. }
  105. }
  106. }
  107. if ($('#sounds').is(':checked')) { // if enable sounds checkbox is ticked, play sounds
  108. moveSnd.play();
  109. }
  110. if ($chess.turn() == 'b') { // if black's turn
  111. var f = $('.feedback-move');
  112. f.text('Black to move.'); // display black to move text
  113. f.parent().removeClass('whitefeedback');
  114. f.parent().addClass('blackfeedback');
  115. } else { // otherwise display white to move
  116. var f = $('.feedback-move');
  117. f.text('White to move.');
  118. f.parent().removeClass('blackfeedback');
  119. f.parent().addClass('whitefeedback');
  120. }
  121. if ($chess.in_check()) {
  122. $('.feedback-status').text(' Check.');
  123. } else{
  124. $('.feedback-status').text('');
  125. }
  126. if ($chess.game_over()) {
  127. $('.feedback-move').text('');
  128. var result = "";
  129. if ($chess.in_checkmate()) {
  130. result = $chess.turn() == 'b' ? 'Checkmate. White wins!' : 'Checkmate. Black wins!'
  131. } else if ($chess.in_draw()) {
  132. result = "Draw.";
  133. } else if ($chess.in_stalemate()) {
  134. result = "Stalemate.";
  135. } else if ($chess.in_threefold_repetition()) {
  136. result = "Draw. (Threefold Repetition)";
  137. } else if ($chess.insufficient_material()) {
  138. result = "Draw. (Insufficient Material)";
  139. }
  140. $('.feedback-status').text(result);
  141. }
  142. /* Add all moves to the table */
  143. var pgn = $chess.pgn({ max_width: 5, newline_char: ',' });
  144. var moves = pgn.split(',');
  145. var last_move = moves.pop().split('.');
  146. var move_number = last_move[0];
  147. var move_pgn = $.trim(last_move[1]);
  148. if (move_pgn.indexOf(' ') != -1) {
  149. var moves = move_pgn.split(' ');
  150. move_pgn = moves[1];
  151. }
  152. $('#moves tbody tr').append('<td><strong>' + move_number + '</strong>. ' + move_pgn + '</td>');
  153. if (rcvd === undefined) {
  154. $socket.emit('new-move', {
  155. 'token': $token,
  156. 'move': move
  157. });
  158. }
  159. }
  160. }
  161. /* socket.io */
  162. $(document).ready(function () {
  163. $socket.emit('join', {
  164. 'token': $token
  165. });
  166. $socket.on('joined', function (data) {
  167. if (data.color == 'white') {
  168. $side = 'w';
  169. $('.chess_board.black').remove();
  170. } else {
  171. $side = 'b';
  172. $('.chess_board.white').remove();
  173. $('.chess_board.black').show();
  174. }
  175. });
  176. $socket.on('move', function (data) {
  177. movePiece(from=data.move.from, to=data.move.to, promotion=data.move.promotion, rcvd=true);
  178. });
  179. $socket.on('opponent-disconnected', function (data) {
  180. alert("Your opponent has disconnected.");
  181. window.location = '/';
  182. });
  183. $socket.on('full', function (data) {
  184. alert("This game already has two players. You have to create a new one.");
  185. window.location = '/';
  186. });
  187. });
  188. /* gameplay */
  189. $(document).ready(function () {
  190. $('.chess_board a').click(function (e) {
  191. var piece = $(this);
  192. if ((piece.hasClass('white') && $side != 'w') ||
  193. (piece.hasClass('black') && $side != 'b')) {
  194. if ($piece) {
  195. movePiece(
  196. from=$piece.parent().data('id').toLowerCase(),
  197. to=$(this).parent().data('id').toLowerCase(),
  198. promotion=$('#promotion option:selected').val()
  199. )
  200. }
  201. } else {
  202. if ($chess.turn() != $side) {
  203. return false;
  204. }
  205. if ($piece && isSelected($(this).parent())) {
  206. unselectPiece($piece.parent());
  207. $piece = null;
  208. } else {
  209. if ($piece) {
  210. unselectPiece($piece.parent());
  211. $piece = null;
  212. }
  213. $piece = $(this);
  214. selectPiece($piece.parent());
  215. }
  216. }
  217. e.stopImmediatePropagation();
  218. e.preventDefault();
  219. });
  220. $('.chess_board td').click(function (e) {
  221. if ($piece) {
  222. movePiece(
  223. from=$piece.parent().data('id').toLowerCase(),
  224. to=$(this).data('id').toLowerCase(),
  225. promotion=$('#promotion option:selected').val()
  226. )
  227. }
  228. });
  229. });