3
\$\begingroup\$

I am currently creating a chess game in JavaScript, some aspects are yet to be done such as the computer player and turns, but before I get into writing these features I would like to know how to restructure or edit the code so it is more flexible to changes, and is more manageable. Right now it seems that to implement some of these features, I would have to keep on copy-pasting similar sections of code.

    const canvas = document.getElementById('canvas');
      const c = canvas.getContext('2d');
      const difficultySlider = document.getElementsByClassName('slider');
      const chessPieceSWidth = 800/6;
      const chessPieceSHeight = 267/2;
      const chessPiecesImgSrc = "chessPieces.png";
      const whiteKing = {image: {sx: 0 * chessPieceSWidth, sy: 0 * chessPieceSHeight}};
      const whiteQueen = {image: {sx: 1 * chessPieceSWidth, sy: 0 * chessPieceSHeight}};
      const whiteBishop = {image: {sx: 2 * chessPieceSWidth, sy: 0 * chessPieceSHeight}};
      const whiteHorse = {image: {sx: 3 * chessPieceSWidth, sy: 0 * chessPieceSHeight}};
      const whiteCastle = {image: {sx: 4 * chessPieceSWidth, sy: 0 * chessPieceSHeight}};
      const whitePawn = {image: {sx: 5 * chessPieceSWidth, sy: 0 * chessPieceSHeight}};
      const blackKing = {image: {sx: 0 * chessPieceSWidth, sy: 1 * chessPieceSHeight}};
      const blackQueen = {image: {sx: 1 * chessPieceSWidth, sy: 1 * chessPieceSHeight}};
      const blackBishop = {image: {sx: 2 * chessPieceSWidth, sy: 1 * chessPieceSHeight}};
      const blackHorse = {image: {sx: 3 * chessPieceSWidth, sy: 1 * chessPieceSHeight}};
      const blackCastle = {image: {sx: 4 * chessPieceSWidth, sy: 1 * chessPieceSHeight}};
      const blackPawn = {image: {sx: 5 * chessPieceSWidth, sy: 1 * chessPieceSHeight}};
      const whitePieces = [whiteCastle, whiteHorse, whiteBishop, whiteQueen, whiteKing, whitePawn];
      const blackPieces = [blackCastle, blackHorse, blackBishop, blackQueen, blackKing, blackPawn];

      let standardBoard = [
        [blackCastle, blackHorse, blackBishop, blackQueen, blackKing, blackBishop, blackHorse, blackCastle],
        [blackPawn, blackPawn, blackPawn, blackPawn, blackPawn, blackPawn, blackPawn, blackPawn],
        ["vacant", "vacant", "vacant", "vacant", "vacant", "vacant", "vacant", "vacant"],
        ["vacant", "vacant", "vacant", "vacant", "vacant", "vacant", "vacant", "vacant"],
        ["vacant", "vacant", "vacant", "vacant", "vacant", "vacant", "vacant", "vacant"],
        ["vacant", "vacant", "vacant", "vacant", "vacant", "vacant", "vacant", "vacant"],
        [whitePawn, whitePawn, whitePawn, whitePawn, whitePawn, whitePawn, whitePawn, whitePawn],
        [whiteCastle, whiteHorse, whiteBishop, whiteQueen, whiteKing, whiteBishop, whiteHorse, whiteCastle]
      ];
      let hasClicked = false;
      let canMove = false;
      let isHighlightPossibleMoves = false;
      let canAdvancePiece = false;
      let highlightPos = undefined;
      let pieceMoves = undefined;
      let advancePosition = undefined;
      let isCastling = false;

      if(Math.round(Math.random()) == 0){
        humanPlayer = whitePieces;
        board = copyBoardArray(standardBoard);
      } else {
        humanPlayer = blackPieces;
        board = reverseArray(copyBoardArray(standardBoard));
      }

      function reverseArray(array){
        return array.reverse();
      }

      function switchSides(){
        if(humanPlayer == whitePieces){
          humanPlayer = blackPieces;
        } else {
          humanPlayer = whitePieces;
        }
        board = reverseArray(board);
      }

      function reload(){
        location.reload();
      }

      document.addEventListener('click', function(event){
        if(!hasClicked){
          if(event.clientX < 480 && event.clientY < 480 && board[Math.floor(event.clientY / 60)][Math.floor(event.clientX / 60)] != "vacant"){
            if(humanPlayer.indexOf(board[Math.floor(event.clientY / 60)][Math.floor(event.clientX / 60)]) != -1){
              canMove = true;
              isHighlightPossibleMoves = true;
              hasClicked = true;
              highlightPos = {x: Math.floor(event.clientX / 60), y: Math.floor(event.clientY / 60)};
              pieceMoves = processMoves({x: Math.floor(event.clientX / 60), y: Math.floor(event.clientY / 60)}, board);
            } else {
              hasClicked = true;
              highlightPos = {x: Math.floor(event.clientX / 60), y: Math.floor(event.clientY / 60)};
              canMove = false;
            }
          }
        } else {
          if(canMove){
            advancePosition = {x: Math.floor(event.clientX / 60), y: Math.floor(event.clientY / 60)};
            for(i = 0; i < pieceMoves.moves.length; i++){
              if(advancePosition.x == pieceMoves.moves[i].x && advancePosition.y == pieceMoves.moves[i].y){
                if(board[highlightPos.y][highlightPos.x] == blackKing || board[highlightPos.y][highlightPos.x] == whiteKing){
                  if(pieceMoves.moves[i].x - 2 == highlightPos.x || pieceMoves.moves[i].x + 2 == highlightPos.x){
                    isCastling = true;
                  } else {
                    isCastling = false;
                  }
                }
                if(isCastling){
                  board = chess.returnCastledBoard({x: highlightPos.x, y: highlightPos.y}, pieceMoves.moves[i]);
                  chess = new Chess(board);
                  isCastling = false;
                } else {
                  board[highlightPos.y][highlightPos.x].hasClicked = true;
                  board = chess.updateBoard(highlightPos, advancePosition);
                  chess = new Chess(board);
                  break;
                }
              }
            }
          }
          hasClicked = false;
          canMove = false;
          highlightPos = undefined;
          pieceMoves = undefined;
          advancePosition = undefined;
        }
      });

      function getPieceType(position, board){
        if(blackPieces.indexOf(board[position.y][position.x]) != -1 && board[position.y][position.x] != "vacant"){
          return blackPieces;
        } else if(whitePieces.indexOf(board[position.y][position.x]) != -1 && board[position.y][position.x] != "vacant"){
          return whitePieces;
        }
      }

      function isCheck(player, board){
        if(player == blackPieces){
          checkKing = blackKing;
          opponent = whitePieces;
        } else {
          checkKing = whiteKing;
          opponent = blackPieces;
        }
        for(rows = 0; rows < 8; rows++){
          for(columns = 0; columns < 8; columns++){
            if(board[rows][columns] == checkKing){
              kingPos = {x: columns, y: rows};
              break;
            }
          }
        }
        opponentMoves = [];
        threatningPieces = [];
        check = false;
        for(rows = 0; rows < 8; rows++){
          for(columns = 0; columns < 8; columns++){
            if(opponent.indexOf(board[rows][columns]) != -1){
              opponentMoves.push(move({x: columns, y: rows}, board));
            }
          }
        }
        for(len = 0; len < opponentMoves.length; len++){
          for(subLen = 0; subLen < opponentMoves[len].moves.length; subLen++){
            if(opponentMoves[len].moves[subLen].x == kingPos.x && opponentMoves[len].moves[subLen].y == kingPos.y){
              check = true;
              threatningPieces.push(opponentMoves[len].playerPos);
            }
          }
        }
        if(check){
          threatningPieces.push(kingPos);
        }
        return {state: check, threatningPieces: threatningPieces};
      }

      function castleMove(position, board){
        moves = [];
        let pieceType = getPieceType(position, board);

        for(i = position.x + 1; i < 8; i++){
          if(board[position.y][i] != "vacant" && pieceType.indexOf(board[position.y][i]) != -1){
            break;
          }
          if(board[position.y][i] != "vacant" && pieceType.indexOf(board[position.y][i]) == -1){
            moves.push({x: i, y: position.y});
            break;
          }
          moves.push({x: i, y: position.y});
        }

        for(i = position.x - 1; i >= 0; i--){
          if(board[position.y][i] != "vacant" && pieceType.indexOf(board[position.y][i]) != -1){
            break;
          }
          if(board[position.y][i] != "vacant" && pieceType.indexOf(board[position.y][i]) == -1){
            moves.push({x: i, y: position.y});
            break;
          }
          moves.push({x: i, y: position.y});
        }

        for(i = position.y + 1; i < 8; i++){
          if(board[i][position.x] != "vacant" && pieceType.indexOf(board[i][position.x]) != -1){
            break;
          }
          if(board[i][position.x] != "vacant" && pieceType.indexOf(board[i][position.x]) == -1){
            moves.push({x: position.x, y: i});
            break;
          }
          moves.push({x: position.x, y: i});
        }

        for(i = position.y - 1; i >= 0; i--){
          if(board[i][position.x] != "vacant" && pieceType.indexOf(board[i][position.x]) != -1){
            break;
          }
          if(board[i][position.x] != "vacant" && pieceType.indexOf(board[i][position.x]) == -1){
            moves.push({x: position.x, y: i});
            break;
          }
          moves.push({x: position.x, y: i});
        }

        return moves;
      }

      function horseMove(position, board){
        moves = [];

        let pieceType = getPieceType(position, board);

        if(position.x + 1 < 8 && position.y + 2 < 8){
          if(board[position.y + 2][position.x + 1] == "vacant" || pieceType.indexOf(board[position.y + 2][position.x + 1]) == -1){
            moves.push({x: position.x + 1, y: position.y + 2});
          }
        }

        if(position.x - 1 >= 0 && position.y + 2 < 8){
          if(board[position.y + 2][position.x - 1] == "vacant" || pieceType.indexOf(board[position.y + 2][position.x - 1]) == -1){
            moves.push({x: position.x - 1, y: position.y + 2});
          }
        }

        if(position.x + 1 < 8 && position.y - 2 >= 0){
          if(board[position.y - 2][position.x + 1] == "vacant" || pieceType.indexOf(board[position.y - 2][position.x + 1]) == -1){
            moves.push({x: position.x + 1, y: position.y - 2});
          }
        }

        if(position.x - 1 >= 0 && position.y - 2 >= 0){
          if(board[position.y - 2][position.x - 1] == "vacant" || pieceType.indexOf(board[position.y - 2][position.x - 1]) == -1){
            moves.push({x: position.x - 1, y: position.y - 2});
          }
        }

        if(position.x + 2 < 8 && position.y + 1 < 8){
          if(board[position.y + 1][position.x + 2] == "vacant" || pieceType.indexOf(board[position.y + 1][position.x + 2]) == -1){
            moves.push({x: position.x + 2, y: position.y + 1});
          }
        }

        if(position.x - 2 >= 0 && position.y + 1 < 8){
          if(board[position.y + 1][position.x - 2] == "vacant" || pieceType.indexOf(board[position.y + 1][position.x - 2]) == -1){
            moves.push({x: position.x - 2, y: position.y + 1});
          }
        }

        if(position.x + 2 < 8 && position.y - 1 >= 0){
          if(board[position.y - 1][position.x + 2] == "vacant" || pieceType.indexOf(board[position.y - 1][position.x + 2]) == -1){
            moves.push({x: position.x + 2, y: position.y - 1});
          }
        }

        if(position.x - 2 >= 0 && position.y - 1 >= 0){
          if(board[position.y - 1][position.x - 2] == "vacant" || pieceType.indexOf(board[position.y - 1][position.x - 2]) == -1){
            moves.push({x: position.x - 2, y: position.y - 1});
          }
        }

        return moves;
      }

      function bishopMove(position, board){
        moves = [];

        let pieceType = getPieceType(position, board);

        x = position.x + 1;
        y = position.y + 1;

        while(x < 8 && y < 8){
          if(board[y][x] != "vacant" && pieceType.indexOf(board[y][x]) != -1){
            break;
          }
          if(board[y][x] != "vacant" && pieceType.indexOf(board[y][x]) == -1){
            moves.push({x: x, y: y});
            break;
          }
          moves.push({x: x, y: y});
          x += 1;
          y += 1;
        }

        x = position.x - 1;
        y = position.y - 1;

        while(x >= 0 && y >= 0){
          if(board[y][x] != "vacant" && pieceType.indexOf(board[y][x]) != -1){
            break;
          }
          if(board[y][x] != "vacant" && pieceType.indexOf(board[y][x]) == -1){
            moves.push({x: x, y: y});
            break;
          }
          moves.push({x: x, y: y});
          x -= 1;
          y -= 1;
        }

        x = position.x - 1;
        y = position.y + 1;

        while(x >= 0 && y < 8){
          if(board[y][x] != "vacant" && pieceType.indexOf(board[y][x]) != -1){
            break;
          }
          if(board[y][x] != "vacant" && pieceType.indexOf(board[y][x]) == -1){
            moves.push({x: x, y: y});
            break;
          }
          moves.push({x: x, y: y});
          x -= 1;
          y += 1;
        }

        x = position.x + 1;
        y = position.y - 1;

        while(x < 8 && y >= 0){
          if(board[y][x] != "vacant" && pieceType.indexOf(board[y][x]) != -1){
            break;
          }
          if(board[y][x] != "vacant" && pieceType.indexOf() == -1){
            moves.push({x: x, y: y});
            break;
          }
          moves.push({x: x, y: y});
          x += 1;
          y -= 1;
        }

        return moves;
      }

      function kingMove(position, board){
        moves = [];

        let pieceType = getPieceType(position, board);

        if(position.x + 1 < 8){
          if(board[position.y][position.x + 1] == "vacant" || pieceType.indexOf(board[position.y][position.x + 1]) == -1){
            moves.push({x: position.x + 1, y: position.y});
          }
        }

        if(position.x - 1 >= 0){
          if(board[position.y][position.x - 1] == "vacant" || pieceType.indexOf(board[position.y][position.x - 1]) == -1){
            moves.push({x: position.x - 1, y: position.y});
          }
        }

        if(position.y + 1 < 8){
          if(board[position.y + 1][position.x] == "vacant" || pieceType.indexOf(board[position.y + 1][position.x]) == -1){
            moves.push({x: position.x, y: position.y + 1});
          }
        }

        if(position.y - 1 >= 0){
          if(this.board[position.y - 1][position.x] == "vacant" || pieceType.indexOf(this.board[position.y - 1][position.x]) == -1){
            moves.push({x: position.x, y: position.y - 1});
          }
        }

        if(position.y - 1 >= 0 && position.x - 1 >= 0){
          if(board[position.y - 1][position.x - 1] == "vacant" || pieceType.indexOf(board[position.y - 1][position.x - 1]) == -1){
            moves.push({x: position.x - 1, y: position.y - 1});
          }
        }

        if(position.y + 1 < 8 && position.x + 1 < 8){
          if(board[position.y + 1][position.x + 1] == "vacant" || pieceType.indexOf(board[position.y + 1][position.x + 1]) == -1){
            moves.push({x: position.x + 1, y: position.y + 1});
          }
        }

        if(position.y + 1 < 8 && position.x - 1 >= 0){
          if(board[position.y + 1][position.x - 1] == "vacant" || pieceType.indexOf(board[position.y + 1][position.x - 1]) == -1){
            moves.push({x: position.x - 1, y: position.y + 1});
          }
        }

        if(position.y - 1 >= 0 && position.x + 1 < 8){
          if(board[position.y - 1][position.x + 1] == "vacant" || pieceType.indexOf(board[position.y - 1][position.x + 1]) == -1){
            moves.push({x: position.x + 1, y: position.y - 1});
          }
        }

        return moves;
      }

      function pawnMove(position, board){
        moves = [];

        let pieceType = getPieceType(position, board);

        if(humanPlayer == whitePieces){
          standardPawn = whitePawn;
        } else {
          standardPawn = blackPawn;
        }

        if(this.board[position.y][position.x] == standardPawn){
          if(position.y == 6){
            if(board[position.y - 1][position.x] == "vacant"){
              moves.push({x: position.x, y: position.y - 1});
            }
            if(board[position.y - 2][position.x] == "vacant" && board[position.y - 1][position.x] == "vacant"){
              moves.push({x: position.x, y: position.y - 2});
            }
          } else if(position.y - 1 >= 0){
            if(board[position.y - 1][position.x] == "vacant"){
              moves.push({x: position.x, y: position.y - 1});
            }
          }
          if(position.x + 1 < 8 && position.y - 1 >= 0){
            if(getPieceType({x: position.x + 1, y: position.y - 1}, this.board) != pieceType && board[position.y - 1][position.x + 1] != "vacant"){
              moves.push({x: position.x + 1, y: position.y - 1});
            }
          }
          if(position.x - 1 >= 0 && position.y - 1 >= 0){
            if(getPieceType({x: position.x - 1, y: position.y - 1}, this.board) != pieceType && board[position.y - 1][position.x - 1] != "vacant"){
              moves.push({x: position.x - 1, y: position.y - 1});
            }
          }
        } else {
          if(position.y == 1){

            if(board[position.y + 1][position.x] == "vacant"){
              moves.push({x: position.x, y: position.y + 1});
            }
            if(board[position.y + 2][position.x] == "vacant" && board[position.y + 1][position.x] == "vacant"){
              moves.push({x: position.x, y: position.y + 2});
            }
          } else if(position.y + 1 < 8){
            if(board[position.y + 1][position.x] == "vacant"){
              moves.push({x: position.x, y: position.y + 1});
            }
          }
          if(position.x + 1 < 8 && position.y + 1 < 8){
            if(getPieceType({x: position.x + 1, y: position.y + 1}, this.board) != pieceType && board[position.y + 1][position.x + 1] != "vacant"){
              moves.push({x: position.x + 1, y: position.y + 1});
            }
          }
          if(position.x - 1 >= 0 && position.y + 1 < 8){
            if(getPieceType({x: position.x - 1, y: position.y + 1}, this.board) != pieceType && board[position.y + 1][position.x - 1] != "vacant"){
              moves.push({x: position.x - 1, y: position.y + 1});
            }
          }
        }

        return moves;
      }

      function move(position, board){
        let boardPos = board[position.y][position.x];

        if(boardPos == blackCastle || boardPos == whiteCastle){
          return {playerPos: {x: position.x, y: position.y}, moves: castleMove(position, board)};
        } else if(boardPos == blackHorse || boardPos == whiteHorse){
          return {playerPos: {x: position.x, y: position.y}, moves: horseMove(position, board)};
        } else if(boardPos == blackBishop || boardPos == whiteBishop){
          return {playerPos: {x: position.x, y: position.y}, moves: bishopMove(position, board)};
        } else if(boardPos == blackQueen || boardPos == whiteQueen){
          possibleMoves = castleMove(position, board);
          for(i = 0; i < bishopMove(position, board).length; i++){
            possibleMoves.push(bishopMove(position, board)[i]);
          }
          return {playerPos: {x: position.x, y: position.y}, moves: possibleMoves};
        } else if(boardPos == whiteKing || boardPos == blackKing){
          return {boardPos: {x: position.x, y: position.y}, moves: kingMove(position, board)}
        } else if(boardPos == whitePawn || boardPos == blackPawn){
          return {playerPos: {x: position.x, y: position.y}, moves: pawnMove(position, board)};
        }
      }

      function processMoves(position, board){
        let pieceType = getPieceType(position, board);
        let posMoves = move(position, board).moves;
        for(index = posMoves.length - 1; index >= 0; index--){
          bCopy = copyBoardArray(board);
          cCopy = new Chess(bCopy);
          bCopy = cCopy.updateBoard(position, posMoves[index]);
          if(isCheck(pieceType, bCopy).state){
            posMoves.splice(index, 1);
          }
          if(board[position.y][position.x] == blackKing || board[position.y][position.x] == whiteKing){
            castleMoves = castlingMoves(position, board);
            for(indI = 0; indI < castleMoves.length; indI++){
              posMoves.push(castleMoves[indI]);
            }
          }
        }

        return {playerPos: {x: position.x, y: position.y}, moves: posMoves};
      }

      function castlingMoves(position, board){
        let pieceType = getPieceType(position, board);
        let castleMoves = [];
        if(board[position.y][position.x].hasClicked === undefined){
          if(getPieceType({x: 0, y: position.y}, board) == pieceType && board[position.y][0].hasClicked === undefined){
            for(key = position.x - 1; key >= 1; key--){
              if(board[position.y][key] == "vacant"){
                isPieceBlocking = false;
              } else {
                isPieceBlocking = true;
                break;
              }
            }
            if(!isPieceBlocking){
              for(key = position.x; key > position.x - 3; key--){
                bdCopy = copyBoardArray(board);
                chessCpy = new Chess(bdCopy);
                bdCopy = chessCpy.updateBoard(position, {x: key, y: position.y});
                if(isCheck(pieceType, bdCopy).state){
                  isIllegal = true;
                  break;
                } else {
                  isIllegal = false;
                }
              }
            }
            if(!isPieceBlocking && !isIllegal){
              castleMoves.push({x: position.x - 2, y: position.y});
            }
          }
          if(getPieceType({x: 7, y: position.y}, board) == pieceType && board[position.y][7].hasClicked === undefined){
            for(key = position.x + 1; key < 7; key++){
              if(board[position.y][key] == "vacant"){
                isPieceBlocking = false;
              } else {
                isPieceBlocking = true;
                break;
              }
            }
            if(!isPieceBlocking){
              for(key = position.x; key < position.x + 3; key++){
                bdCopy = copyBoardArray(board);
                chessCpy = new Chess(bdCopy);
                bdCopy = chessCpy.updateBoard(position, {x: key, y: position.y});
                if(isCheck(pieceType, bdCopy).state){
                  isIllegal = true;
                  break;
                } else {
                  isIllegal = false;
                }
              }
            }
            if(!isPieceBlocking && !isIllegal){
              castleMoves.push({x: position.x + 2, y: position.y});
            }
          }
        }
        return castleMoves;
      }

      function Chess(board){
        this.board = board;

        this.updateBoard = function(playerPastPos, playerNextPos){
          let boardDeepClone = copyBoardArray(this.board);
          let player = this.board[playerPastPos.y][playerPastPos.x];
          boardDeepClone[playerPastPos.y][playerPastPos.x] = "vacant";
          boardDeepClone[playerNextPos.y][playerNextPos.x] = player;
          return boardDeepClone;
        }

        this.returnCastledBoard = function(kingPos, movePos){
          let king = this.board[kingPos.y][kingPos.x];
          if(movePos.x > kingPos.x){
            targetCastle = this.board[movePos.y][7];
            boardDeepClone = copyBoardArray(this.board);
            boardDeepClone[kingPos.y][kingPos.x] = "vacant";
            boardDeepClone[kingPos.y][kingPos.x + 2] = king;
            boardDeepClone[kingPos.y][7] = "vacant";
            boardDeepClone[kingPos.y][kingPos.x + 1] = targetCastle;
          } else {
            targetCastle = this.board[movePos.y][0];
            boardDeepClone = copyBoardArray(this.board);
            boardDeepClone[kingPos.y][kingPos.x] = "vacant";
            boardDeepClone[kingPos.y][kingPos.x - 2] = king;
            boardDeepClone[kingPos.y][0] = "vacant";
            boardDeepClone[kingPos.y][kingPos.x - 1] = targetCastle;
          }
          return boardDeepClone;
        }
      }

      function copyBoardArray(board){
        let boardCopy = [];
        for(i = 0; i < 8; i++){
          boardCopy.push([0]);
          for(j = 0; j < 8; j++){
            boardCopy[i][j] = board[i][j];
          }
        }
        return boardCopy;
      }

      function rect(x, y, width, height, color){
        c.beginPath();
        c.rect(x, y, width, height);
        c.fillStyle = color;
        c.fill();
        c.closePath();
      }

      let chess = new Chess(board);

      function render(){
        for(i = 0; i < 8; i++){
          for(j = 0; j < 8; j++){
            if(i % 2 == 0){
              if(j % 2 == 0){
                rect(j * 60, i * 60, 60, 60, "peru");
              } else {
                rect(j * 60, i * 60, 60, 60, "seashell");
              }
              c.stroke();
            } else {
              if(j % 2 == 0){
                rect(j * 60, i * 60, 60, 60, "seashell");
              } else {
                rect(j * 60, i * 60, 60, 60, "peru");
              }
            }
            c.stroke();
          }
        }
        if(isCheck(humanPlayer, board).state){
          for(ind = 0; ind < isCheck(humanPlayer, board).threatningPieces.length; ind++){
            rect(isCheck(humanPlayer, board).threatningPieces[ind].x * 60, isCheck(humanPlayer, board).threatningPieces[ind].y * 60, 60, 60, "red");
            c.stroke();
          }
        }
        if(highlightPos != undefined){
          rect(highlightPos.x * 60, highlightPos.y * 60, 60, 60, "yellow");
          c.stroke();
        }
        for(i = 0; i < 8; i++){
          for(j = 0; j < 8; j++){
            if(board[i][j] != "vacant"){
              let image = new Image();
              image.src = "chessPieces.png";
              c.drawImage(image, board[i][j].image.sx, board[i][j].image.sy, chessPieceSWidth, chessPieceSHeight, j * 60, i * 60, 60, 60);
            }
          }
        }
        if(pieceMoves != undefined){
          c.globalAlpha = 0.6;
          for(i = 0; i < pieceMoves.moves.length; i++){
            c.beginPath();
            c.arc(pieceMoves.moves[i].x * 60 + 30, pieceMoves.moves[i].y * 60 + 30, 12, 12, 0, Math.PI * 2);
            c.fillStyle = "grey";
            c.fill();
            c.closePath();
          }
          c.globalAlpha = 1;
        }
      }

      setInterval(render, 10);
````
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Methods

If you write more methods, your code instantly becomes easier to read. It's also easier to maintain, including making changes.

This is one example of what could be a method. It's not clear at a glance what this code does and you may want to allow the user to pick their own colour in the future.

if(Math.round(Math.random()) == 0){
    humanPlayer = whitePieces;
    board = copyBoardArray(standardBoard);
} else {
    humanPlayer = blackPieces;
    board = reverseArray(copyBoardArray(standardBoard));
}

Creating a chess piece could be a method. You may change the features of a Chess piece in the future, you can also reduce repeating yourself with a method:

function createChessPiece(var x, var y) {
    return {image: {sx: x * chessPieceSWidth, sy: y * chessPieceSHeight}};
}

All of your logic should be moved to separate methods as well.

Avoid magic numbers

"Magic numbers" and "magic strings" are literals not assigned to a variable. For example, what is "480" here? It could be a const declared at the top:

event.clientX < 480 && event.clientY < 480

Naming

Make sure your names make sense. "isCheck" does not make sense or mean anything. It looks like check is a class variable but should be declared inside this method. check, checkKing are also bad names as it's not descriptive.

Chess is not a good function name. You cannot tell what the method will do by reading the name.

Edit: Examples of naming You may find it's hard to give certain methods names. This is actually a good thing and shows why simply creating & renaming methods can be a very good tool to for refactoring.

For example, it's really hard to name isCheck, it's doing multiple things which aren't obvious by looking at the method.

I suggest splitting the method into 2 or 3 methods. isState & isThreatning may not be good names either. Perhaps getThreatningPieces and renaming state to be more specific.

Currently you are returning 2 flags and invoking the method when you need either threatningPieces or state. It should also be noted you're invoking the method more than you need to:

if(isCheck(humanPlayer, board).state){
    for(ind = 0; ind < isCheck(humanPlayer, board).threatningPieces.length;

In the above code, you can create a variable to store the value of the method, so it only gets invoked once.

Your isCheck method is changing some local variables creating spaghetti code. Which brings me to my next point:

Declare variables as locally as possible

Don't declare all your variables at the top. There's no need for that. It's hard to tell where checkKing is getting changed or used. It makes debugging difficult.

\$\endgroup\$
2
  • \$\begingroup\$ Is it ok if you can rewrite a small segment of the code as an example. \$\endgroup\$
    – Crupeng
    Dec 21, 2019 at 14:36
  • \$\begingroup\$ @SwatiRawatChandra I updated my answer \$\endgroup\$
    – dustytrash
    Dec 21, 2019 at 15:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.