DEV Community

Artur
Artur

Posted on

How can I make the possible moves of the selected piece highlighted?

Hello! I want to add highlighting of possible moves for the selected piece. What do I need to do in javascript?

This is my javascript:

interaction.js:

let selectedPiece = null;
let selectedCell = null;
let selectedTeam = null;

/**
 * @param {HTMLElement} boardElement
 * @param {Array} boardState 
 * @param {Function} handleMove
 */
export function setupInteractions(boardElement, boardState, handleMove) {
  boardElement.addEventListener("click", (event) => {
    const cell = event.target.closest(".square");

    if (!cell) return;

    const row = parseInt(cell.getAttribute("data-row"));
    const col = parseInt(cell.getAttribute("data-col"));

    if (selectedPiece) {
      const successfulMove = handleMove(
        selectedPiece,
        selectedTeam,
        selectedCell,
        row,
        col
      );

      if (successfulMove) {
        clearSelection(boardElement);
        selectedPiece = null;
        selectedCell = null;
      } else {
        clearSelection(boardElement);
        selectedPiece = null;
        selectedCell = null;
      }
    } else if (boardState[row][col]) {
      selectedPiece = boardState[row][col];
      const pieceElement = cell.querySelector("span");
      selectedTeam = pieceElement?.classList.contains("white-piece")
        ? "white"
        : "black";
      selectedCell = { row, col };
      highlightCell(cell);
    }
    console.log("Selected team:", selectedTeam);
    console.log("Selected piece:", selectedPiece);
  });
}

/**
 * @param {HTMLElement} cell
 */
function highlightCell(cell) {
  clearSelection(cell.parentElement);
  cell.classList.add("selected");
}

/**
 * @param {HTMLElement} boardElement 
 */
function clearSelection(boardElement) {
  const selectedCells = boardElement.querySelectorAll(".selected");
  selectedCells.forEach((cell) => cell.classList.remove("selected"));
}
Enter fullscreen mode Exit fullscreen mode

main.js:

import { createBoard, createLabels, initialSetup } from "./board.js";
import { setupInteractions } from "./interactions.js";
import { isValidMove } from "./rules.js";

const board = document.querySelector(".board");
const letterTop = document.querySelector(".label-top");
const letterBotton = document.querySelector(".label-botton");
const letterRight = document.querySelector(".label-right");
const letterLeft = document.querySelector(".label-left");

let boardState = JSON.parse(JSON.stringify(initialSetup));

createBoard(board, boardState);
createLabels(letterTop, letterBotton, letterRight, letterLeft);

setupInteractions(board, boardState, handleMove);

/**
 * @param {string} selectedPiece
 * @param {HTMLElement} selectedTeam
 * @param {Object} selectedCell
 * @param {number} toRow
 * @param {number} toCol
 * @returns {boolean}
 */
function handleMove(selectedPiece, selectedTeam, selectedCell, toRow, toCol) {
  const { row: fromRow, col: fromCol } = selectedCell;

  if (
    isValidMove(
      selectedPiece.piece,
      selectedTeam,
      fromRow,
      fromCol,
      toRow,
      toCol,
      boardState
    )
  ) {
    boardState[toRow][toCol] = selectedPiece;
    boardState[fromRow][fromCol] = null;

    const fromCell = board.querySelector(
      `[data-row="${fromRow}"][data-col="${fromCol}"]`
    );
    const toCell = board.querySelector(
      `[data-row="${toRow}"][data-col="${toCol}"]`
    );

    if (fromCell && toCell) {
      const pieceElement = fromCell.querySelector("span");
      const targetPieceElement = toCell.querySelector("span");

      if (targetPieceElement) {
        targetPieceElement.remove();
      }

      if (pieceElement) {
        toCell.appendChild(pieceElement);
      }
    }

    return true;
  }

  return false;
}
Enter fullscreen mode Exit fullscreen mode

rules.js:

/**
 * @param {string} piece
 * @param {string} selectedTeam
 * @param {number} fromRow
 * @param {number} fromCol
 * @param {number} toRow
 * @param {number} toCol
 * @param {Array} boardState
 * @returns {boolean}
 */
export function isValidMove(
  piece,
  selectedTeam,
  fromRow,
  fromCol,
  toRow,
  toCol,
  boardState
) {
  const targetPiece = boardState[toRow]?.[toCol];
  const targetTeam = getTeam(targetPiece);

  console.log(`Selected piece: ${piece}, team: ${selectedTeam}`);
  console.log(`Target piece: ${targetPiece}, team: ${targetTeam}`);

  if (targetPiece && isSameTeam(selectedTeam, targetTeam)) {
    console.log("Cannot capture a piece of the same team!");
    return false;у
  }

  switch (piece) {
    case "♟":
      return isValidPawnMove(
        piece,
        selectedTeam,
        fromRow,
        fromCol,
        toRow,
        toCol,
        boardState
      );
    case "♜":
      return isValidRookMove(fromRow, fromCol, toRow, toCol, boardState);
    case "♝":
      return isValidBishopMove(fromRow, fromCol, toRow, toCol, boardState);
    case "♛":
      return isValidQueenMove(fromRow, fromCol, toRow, toCol, boardState);
    case "♚":
      return isValidKingMove(fromRow, fromCol, toRow, toCol);
    case "♞":
      return isValidKnightMove(fromRow, fromCol, toRow, toCol);
    default:
      return false;
  }
}

function isValidPawnMove(
  piece,
  selectedTeam,
  fromRow,
  fromCol,
  toRow,
  toCol,
  boardState
) {
  const direction = selectedTeam === "black" ? 1 : -1;
  const startRow = selectedTeam === "black" ? 1 : 6;

  if (
    toCol === fromCol &&
    (!boardState[toRow]?.[toCol] || boardState[toRow][toCol] === "")
  ) {
    if (toRow === fromRow + direction) {
      return true;
    }

    if (
      fromRow === startRow &&
      toRow === fromRow + 2 * direction &&
      (!boardState[fromRow + direction]?.[toCol] ||
        boardState[fromRow + direction][toCol] === "")
    ) {
      return true;
    }
  }

  if (
    Math.abs(toCol - fromCol) === 1 && 
    toRow === fromRow + direction && 
    boardState[toRow]?.[toCol] &&
    getTeam(boardState[toRow][toCol]) !== selectedTeam 
  ) {
    return true;
  }

  return false; 
}

function isValidRookMove(fromRow, fromCol, toRow, toCol, boardState) {
  if (fromRow !== toRow && fromCol !== toCol) return false; 

  return isPathClear(fromRow, fromCol, toRow, toCol, boardState);
}

function isValidBishopMove(fromRow, fromCol, toRow, toCol, boardState) {
  if (Math.abs(toRow - fromRow) !== Math.abs(toCol - fromCol)) return false;

  return isPathClear(fromRow, fromCol, toRow, toCol, boardState);
}

function isValidQueenMove(fromRow, fromCol, toRow, toCol, boardState) {
  return (
    isValidRookMove(fromRow, fromCol, toRow, toCol, boardState) ||
    isValidBishopMove(fromRow, fromCol, toRow, toCol, boardState)
  );
}

function isValidKingMove(fromRow, fromCol, toRow, toCol) {
  return (
    Math.abs(toRow - fromRow) <= 1 && Math.abs(toCol - fromCol) <= 1
  );
}

function isValidKnightMove(fromRow, fromCol, toRow, toCol) {
  const rowDiff = Math.abs(toRow - fromRow);
  const colDiff = Math.abs(toCol - fromCol);

  return (
    (rowDiff === 2 && colDiff === 1) || (rowDiff === 1 && colDiff === 2)
  );
}

function isPathClear(fromRow, fromCol, toRow, toCol, boardState) {
  const rowDirection = Math.sign(toRow - fromRow);
  const colDirection = Math.sign(toCol - fromCol);

  let currentRow = fromRow + rowDirection;
  let currentCol = fromCol + colDirection;

  while (currentRow !== toRow || currentCol !== toCol) {
    if (boardState[currentRow][currentCol]) {
      return false;
    }
    currentRow += rowDirection;
    currentCol += colDirection;
  }

  return true;
}

function isSameTeam(selectedTeam, targetTeam) {
  if (!selectedTeam || !targetTeam) return false;
  return selectedTeam === targetTeam;
}

function getTeam(cell) {
  if (!cell) return null;
  return cell.team || null;
}
Enter fullscreen mode Exit fullscreen mode

I tried with gpt chat but it didn't help(

Top comments (0)