Question

I'm trying to design chess game in html using java script. I'm moving pieces on chess board using drag and drop. I'm still in starting stage. I just designed the board and placed pieces using "uni code" characters. I didn't write the functionality of each and every piece yet. I just differentiated the piece colors i.e. white pieces should not kill black pieces. The Main problem here When I drag a piece from one cell to another cell it moves but when I try to put it back in its original place it is not permitting the move. When debugged I came to know that there is an instance of the previously dragged element which according to My program shows an error "illegal move, Cannot Kill the Same Color piece". I tried using MozClearData also but it did not work. Please let me know how could I resolve this issue. My Html Code goes like this :

       <html> 
       <head> 
        <title>Chess Board</title> 
        <style type="text/css"> 
                table.chessboard { 
                border: 2px solid #000000; 
                 table-layout:fixed;
        } 
        table.chessboard td { 
             width:60px; 
             height:60px; 
         } 
        table.chessboard td.white { 
              background-color:#ffffff; 
        } 
       table.chessboard td.black { 
          background-color:#d3d3d3; 
       } 
     </style> 
   </head> 
   <body> 
       <table width="540" height="580" class="chessboard" align="center" 
       ondrop="drop(event)" ondragover="allowDrop(event)" style="font-size:2em"> 
       <tr id="0"> 
       <td id="A0" width="90" height="90" class="white" align="center"><a href="#" id="rook">              
        <span id="SA0" class="white" draggable="true" ondragstart="drag(event)">&#9814;</span>
       </a></td> 
        <td id="B0" width="90" height="90" class="black" align="center"><a href="#" id="knight">  
         <span id="SB0" class="white" draggable="true" ondragstart="drag(event)">&#9816;</span></a></td> 
        <td id="C0" width="90" height="90" class="white" align="center"><a href="#" id="bishop">              
         <span id="SC0" class="white" draggable="true" ondragstart="drag(event)">&#9815;</span></a></td> 
         <td id="D0" width="90" height="90" class="black" align="center"><a href="#" id="queen">                <span  id="SD0" class="white" draggable="true" ondragstart="drag(event)">&#9813;</span></a></td>
        <td id="E0" width="90" height="90" class="white" align="center"><a href="#" id="king">    <span id="SE0" class="white" draggable="true" ondragstart="drag(event)">&#9812;</span></a></td> 
        <td id="F0" width="90" height="90" class="black" align="center"><a href="#" id="bishop">  <span id="SF0" class="white" draggable="true" ondragstart="drag(event)">&#9815;</span></a></td> 
       <td id="G0" width="90" height="90" class="white" align="center"><a href="#" id="knight"> <span id="SG0" class="white" draggable="true" ondragstart="drag(event)">&#9816;</span></a></td> 
       <td id="H0" width="90" height="90" class="black" align="center"><a href="#" id="rook"><span id="SH0" class="white" draggable="true" ondragstart="drag(event)">&#9814;</span></a></td> 
    </tr> 
    <tr id="1"> 
         <td id="A1" width="90" height="90" class="black" align="center"><a href="#" id="pawn"> <span id="SA1" class="white" draggable="true" ondragstart="drag(event)">&#9817;</span></a></td> 
        <td id="B1" width="90" height="90" class="white" align="center"><a href="#" id="pawn"> <span id="SB1"  class="white" draggable="true" ondragstart="drag(event)">&#9817;</span></a></td> 
       <td id="C1" width="90" height="90" class="black" align="center"><a href="#" id="pawn"> <span class="white" id="SC1"  draggable="true" ondragstart="drag(event)">&#9817;</span></a></td> 
      <td id="D1" width="90" height="90" class="white" align="center"><a href="#" id="pawn"><span  class="white" id="SD1"  draggable="true" ondragstart="drag(event)">&#9817;</span></a></td> 
      <td id="E1" width="90" height="90" class="black" align="center"><a href="#" id="pawn"><span  id="SE1" class="white"  draggable="true" ondragstart="drag(event)">&#9817;</span></a></td> 
     <td id="F1" width="90" height="90" class="white" align="center"><a href="#" id="pawn"><span id="SF1" class="white"  draggable="true" ondragstart="drag(event)">&#9817;</span></a></td> 
     <td id="G1" width="90" height="90" class="black" align="center"><a href="#" id="pawn"><span id="SG1" class="white"  draggable="true" ondragstart="drag(event)">&#9817;</span></a></td> 
     <td id="H1" width="90" height="90" class="white" align="center"><a href="#" id="pawn"><span id="SH1" class="white"  draggable="true" ondragstart="drag(event)">&#9817;</span></a></td> 
   </tr> 
    <tr id="2"> 
      <td id="A2" width="90" height="90" class="white" align="center"><a href="#"><span id="SA2"  draggable="true" ondragstart="drag(event)"></span></a></td> 
       <td id="B2" width="90" height="90" class="black" align="center"><a href="#"><span id="SB2"   draggable="true" ondragstart="drag(event)"></span></a></td> 
      <td id="C2" width="90" height="90" class="white" align="center"><a href="#"><span id="SC2"   draggable="true" ondragstart="drag(event)"></span></a></td> 
      <td id="D2" width="90" height="90" class="black" align="center"><a href="#"><span id="SD2"   draggable="true" ondragstart="drag(event)"></span></a></td>
      <td id="E2" width="90" height="90" class="white" align="center"><a href="#"><span id="SE2"   draggable="true" ondragstart="drag(event)"></span></a></td> 
      <td id="F2" width="90" height="90" class="black" align="center"><a href="#"><span id="SF2"   draggable="true" ondragstart="drag(event)"></span></a></td> 
      <td id="G2" width="90" height="90" class="white" align="center"><a href="#"><span id="SG2"   draggable="true" ondragstart="drag(event)"></span></a></td> 
      <td id="H2" width="90" height="90" class="black" align="center"><a href="#"><span id="SH2"   draggable="true" ondragstart="drag(event)"></span></a></td> 


♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟
♜ ♞ ♝ ♚ ♛ ♝ ♞ ♜

And My JavaScript Code is as follows :

function getRowIndex(cell) {
     var index = cell.rowIndex;
     document.write("" + index);
 }

 function getCellIndex(cell) {
     var index = cell.cellIndex;
     document.write("" + index);
 }

 function allowDrop(ev) {
     ev.preventDefault();
 }
 var inisrc;

 function drag(ev) {
     inisrc = 0;
     ev.dataTransfer.effectAllowed = 'move';
     ev.dataTransfer.setData("Text", ev.target.getAttribute('id'));
     inisrc = ev.target.id;
     ev.dataTransfer.setDragImage(ev.target, 0, 0);
     var spanid = ev.target.getAttribute('id'); //span id
     // ev.target.getAttribute('id').remove();
     var tdid = spanid.substring(1, spanid.length); //td id
     var tind = document.getElementById(tdid).cellIndex; //td index ****** this is what we neeed
     var trid = tdid.substring(1, tdid.length); //table row id
     var rind = document.getElementById(trid).rowIndex; //row index ******* this is what we neeed
 }

 function getColor(code) {
     if (code >= 9812 && code <= 9817)
         return "white";
     else if (code >= 9818 && code <= 9823)
         return "black";
     else
         return null;
 }

 function drop(ev) {
     var srcColor = null,
         srcUnic = null,
         spanid = null,
         tgtPiece = null,
         tgtColor = null,
         tgtUnic = null,
         tdid = null;
     var src = ev.dataTransfer.getData("Text"); //src is span id of target
     // alert(src);
     var srcPiece = document.getElementById(src).innerHTML; //friend should not be eaten. here we are identifying the class (color) of the source piece
     // alert("srcp" +srcPiece);
     if (srcPiece != null) {
         srcUnic = srcPiece.charCodeAt(0); //extracts unicode of the particular chess piece
         srcColor = getColor(srcUnic); //gets color of the piece
     }
     tdid = ev.target.id; //td id of the target
     if (tdid.length < 3) {
         spanid = 'S' + tdid; //id of span by concatenating "S" to tdid
     }
     else {
         spanid = tdid;
     }
     if (document.getElementById(spanid) != null) {
         tgtPiece = document.getElementById(spanid).innerHTML; //gives code of target piece
         if ((tgtPiece != null) && (tgtPiece != "")) {
             tgtUnic = tgtPiece.charCodeAt(0); //extracts unicode of the particular chess piece
             alert(tgtUnic);
             tgtColor = getColor(tgtUnic); //gets color of the piece
             if (tgtColor != null) {
                 if (srcColor != tgtColor) {
                     ev.target.innerHTML = "";
                     ev.target.appendChild(document.getElementById(src)); //append src piece into target piece
                     alert(src);
                 }
                 else {
                     alert("illegal color move");
                 }
             }
             else {
                 alert("illegal move");
             }
         }
         else if (tgtPiece == "") {
             ev.target.innerHTML = "";
             ev.target.appendChild(document.getElementById(src)); //append src piece into target piece
             alert(src);
         }
     } //to avoid innerHTML nulll exception
 }

I Apologize for the long code. Any help will be highly appreciated

Was it helpful?

Solution 2

See this fiddle showing the main problem and some others fixed.

OK, the immediate problem - receiving an error when you dropped on a piece's starting position is that you were looking up the element by the td id name prefixed with S which happens to be the same as the span that you are dragging around:

if (tdid.length < 3) {
     spanid = 'S' + tdid; //id of span by concatenating "S" to tdid
} 

For example,

<td id="A0"...

contains span

<span id="SA0"

Note that S + A0 will always equal SA0 which is the ID of the span (piece) that you are dragging around.

There were a few other issues that I fixed:

  • All table cells, even ones that didn't have a piece had a draggable span. This caused some conflicts and errors when dragging around as it was removed after a drag which caused problems with the logic in the code when a piece was dragged back to where it had visited.
  • The item can be dropped on a td or another piece span, you need to handle both.
  • You lose the pointer icon after moving because it is no longer a link (a). So, I added the cursor:pointer css.

The main changes to the logic were in function drop(ev) {, specifically the code to handle drops to different locations and to get the inner span:

     tdid = ev.target.id; //td id of the target
     //if (tdid.length < 3) {
       //  spanid = 'S' + tdid; //id of span by concatenating "S" to tdid
     //}
     //else {
      //   spanid = tdid;
     //}
     var ttd = document.getElementById(tdid);
     var tgtPieceElem;
     if( ttd.nodeName.toLowerCase()=='span')//dropped onto another piece
     {
        tgtPieceElem = ttd;
     }
     else //dropped onto table-cell
     {
        var tgtPieces = ttd.getElementsByTagName('span');
        tgtPieceElem = (tgtPieces.length==1)?tgtPieces[0]:null;
     }
     if (tgtPieceElem) {
         tgtPiece = tgtPieceElem.innerHTML; //gives code of target  

and the final else to handle drop to an empty cell.

     else
     {
        ev.target.innerHTML = "";
        ev.target.appendChild(document.getElementById(src)); //append src piece into target piece
        alert(src);
     }

Besides this, I have the following recommendations: -

  • The links have duplicate ids for example, all pawn links have the id pawn. Ids should be unique on the page, use a class instead.
  • I am not sure if the links a was done because you wanted links or just to show that the elements could be clicked. If the latter, then I suggest removing the links and using the css cursor:pointer instead and css for colour styling. If you want the links, then currently the pieces are dragged without the links, so they lose them when dropped. You will need to insert the links into the new cell as well.
  • You probably want some class on the pieces so that you can recognize in drop that a valid piece is being dropped and exit the function if not. Currently you can drop an image or any other draggable element which causes an error in the code.
  • As others have mentioned, it is best to keep game logic separate from presentation. However, most of the errors were related to presentation, so you will need to do both (fix presentation errors and separate logic).

OTHER TIPS

I have actually just done this recently in JavaScript using jQuery draggable combined with click & drop events handler (so it works on mobile device too). Having read many open-source code, here are the arrangement I make to get everything work together beautifully.

Assign 2 dictionaries (array in JavaScript?) using chess unicode & FEN string, unicode can be used as both "Key" and "Value", like this:

PIECE = {
    P:'♙', R:'♖', N:'♘', B:'♗', Q:'♕', K:'♔',
    p:'♟', r:'♜', n:'♞', b:'♝', q:'♛', k:'♚',
};

// Reversed engineering to convert positional objects => fen string
// FEN_PIECE is used as a mirror array as in PIECE
FEN_PIECE = {
    '♙': 'P', '♖': 'R', '♘': 'N', '♗': 'B', '♕': 'Q', '♔': 'K',
    '♟': 'p', '♜': 'r', '♞': 'n', '♝': 'b', '♛': 'q', '♚': 'k',
};


// Empty position dictionary for board creation
// after chess movement, we capture on board pieces and insert into this
// so the dictionary keys: values pattern will be always the same
EMPTY_POSITION = {
    A8: "", B8: "", C8: "", D8: "", E8: "", F8: "", G8: "", H8: "",
    A7: "", B7: "", C7: "", D7: "", E7: "", F7: "", G7: "", H7: "",
    A6: "", B6: "", C6: "", D6: "", E6: "", F6: "", G6: "", H6: "",
    A5: "", B5: "", C5: "", D5: "", E5: "", F5: "", G5: "", H5: "",
    A4: "", B4: "", C4: "", D4: "", E4: "", F4: "", G4: "", H4: "",
    A3: "", B3: "", C3: "", D3: "", E3: "", F3: "", G3: "", H3: "",
    A2: "", B2: "", C2: "", D2: "", E2: "", F2: "", G2: "", H2: "",
    A1: "", B1: "", C1: "", D1: "", E1: "", F1: "", G1: "", H1: ""
};

and for the Chess board itself, loop through the rows & columns under with

<div class="piece" draggable="true"> will put chess piece here later </div>

using conversion between board position & FEN strings (I use FEN as the main game library, and convert to board position to draw the "pieces" dynamically).

and using PIECE[FEN string] & FEN_PIECE[piece] to retrieve the board position and pieces information.

then for the UI bits:

just set a few global variables when initializing the board:

var targetId
var sourceId
var clicked_id;
var clicked_piece;

and

on 'dragstart [draggable=true]': function(ev) {
  sourceId = ev.target.parentNode.id;
  piece = e.target.innerHTML;
}

since you have done this already so I will not go through again, and to get click & drop working, you just need to assign a class on element click:

on 'click .clicked': function(ev) {
  $(ev.target).toggleClass("clicked");
  try { your Chess move here... using sourceId, piece} 
  catch(err) { what not here... }
}

check if any "clicked" class already on the board other then itself, then it means a "drop" move.

to assign the board div id as A1 to H8, just do a simple loop:

var ROW = '12345678'.split("");
var COL = 'ABCDEFGH'.split("");
for (var r=1; r<=ROW.length; r++) {
  for (var c=1; c<=COL.length; c++) {
    //just assign your table tr td div to with id attribute here...
  }
}

So you do not really need to use colour to check the element, just back to basic div drag and click. I am not sure whether this helps you but I hope you get the idea or perhaps can think in another approach. There are too many libraries out there that you can study and see what the best will suit your situation, good luck!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top