diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1ea4962 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "CodeGPT.apiKey": "CodeGPT Plus Beta" +} diff --git a/Chess Programme.code-workspace b/Chess Programme.code-workspace new file mode 100644 index 0000000..362d7c2 --- /dev/null +++ b/Chess Programme.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} \ No newline at end of file diff --git a/app.js b/app.js index d12ea73..4709adc 100644 --- a/app.js +++ b/app.js @@ -1,9 +1,27 @@ const gameBoard = document.getElementById("gameboard"); const playerDisplay = document.getElementById("player"); const infoDisplay = document.getElementById("info-display"); + const width = 8; + let playerTurn = "white"; // defining whose move it is playerDisplay.textContent = "white"; // showing whose move it is + +// fetching the visuals for each piece from fontawesome +const king = + '
'; +const queen = + '
'; +const rook = + '
'; +const knight = + '
'; +const bishop = + '
'; +const pawn = + '
'; + +// placing the pieces on the board const startPieces = [ rook, knight, @@ -71,16 +89,17 @@ const startPieces = [ rook, ]; -// CREATING THE INITIAL BOARD -function createBoard() { +// inject into the #gameboard +function createInitialBoard() { startPieces.forEach((startPiece, i) => { - // this function injects into the #gameboard const square = document.createElement("div"); // create a div for each startpiece. Call the div "square" square.classList.add("square"); // give each square a class called "square" square.innerHTML = startPiece; // make the pieces appear on the squares square.firstChild?.setAttribute("draggable", true); // Check whether a square should be draggable (it should be if it has a firstChild, i.e. if there is a piece on it). If it is, give it the attribute "draggable"; square.setAttribute("square-id", i); // give each square an attribute "square-id" of "i" const row = Math.floor((63 - i) / width) + 1; // define what row we're currently in + // TODO(Martin): Try also adding `const column = ...` line above, and then use `column` below, together with `row`, + // to decide if field should be light or dark. Instead of using `row` and then again `i`. It will be a bit nicer. if (row % 2 === 0) { // every other row add the class "bright" or "dark" to a square, depending on whether the index of that square can be divided by 2 (meaning: every other square) square.classList.add(i % 2 === 0 ? "bright" : "dark"); @@ -98,21 +117,26 @@ function createBoard() { gameBoard.append(square); // append each square to the game board }); } -createBoard(); +createInitialBoard(); // ENABLING DRAG & DROP FUNCTIONALITY const allSquares = document.querySelectorAll(".square"); // grab all squares (i.e. every HTML element with the class "square") and save them as const allSquares allSquares.forEach((square) => { - square.addEventListener("dragStart", dragStart); // listen out for a dragsStart even, and when it starts call the dragStart function - square.addEventListener("dragOver", dragOver); + square.addEventListener("dragstart", dragStart); // listen out for a dragstart event, and when it starts call the dragStart function + square.addEventListener("dragover", dragOver); square.addEventListener("drop", dragDrop); }); +// TODO(martin): I would rename `startPositionId` to `currentlyDraggedSquareId`. +// Although I don't quite get why you need both this variable and the one below, `draggedElement`, +// when you can easily obtain square id from the `draggedElement` by just doing +// `draggedElement.parentNode.getAttribute("square-id")`. let startPositionId; // global level. Starts with null. As soon as we drag a piece we get the square-id through the getAttribute function below, which then gets saved to StartPositionId. let draggedElement; function dragStart(e) { + // I don't understand what this "e" for event is for. Why do I need it? startPositionId = e.target.parentNode.getAttribute("square-id"); // the parentNode points to the square-id. This is equivalent to the startPosition of a piece. draggedElement = e.target; } @@ -123,15 +147,729 @@ function dragOver(e) { function dragDrop(e) { e.stopPropagation(); // this prevents any funky behaviour, e.g. dropping two pieces and call this function twice - const correctTurn = - draggedElement.firstChild.classList.contains("playerTurn"); // define a correct turn by saving all draggedElements with a class of "playerTurn" to const correctTurn - const taken = e.target.classList.contains("piece"); // this ensures that a piece can only be taken if there is already a piece on the target square + const isCorrectTurn = + draggedElement.firstChild.classList.contains(playerTurn); // define a correct turn by saving all draggedElements with a class of "playerTurn" to const isCorrectTurn + + const taken = e.target.firstChild !== null; // this ensures that a piece can only be taken if there is already a piece on the target square + const valid = checkIfValid(e.target, e); const opponentTurn = playerTurn === "white" ? "black" : "white"; const takenByOpponent = e.target.firstChild?.classList.contains(opponentTurn); // check whether the firstChild of the target square exists. If it does, check if the class contains opponentTurn - e.target.parentNode.append(draggedElement); // let the draggedElement appear in the target square. This only applies if there already is a piece in the target square. If there isn't, then e.target.append(draggedElement) applies. - e.target.remove(); - // e.target.append(draggedElement); - changePlayer(); // how can the programme call the revertIds function already here if it's written only further below in the script? + + if (isCorrectTurn) { + if (takenByOpponent && valid) { + e.target.append(draggedElement); // let the draggedElement appear in the target square. This only applies if there already is a piece in the target square. If there isn't, then e.target.append(draggedElement) applies. + e.target.removeChild(e.target.firstChild); // remove any existing elements in that square after appending the draggedElement + checkForVictory(); + changePlayer(); + return; + } + if (taken && !takenByOpponent) { + infoDisplay.textContent = "This move is invalid"; + setTimeout(() => (infoDisplay.textContent = ""), 2000); + return; + } + if (isCorrectTurn && !taken && valid) { + e.target.append(draggedElement); + checkForVictory(); + changePlayer(); + return; + } + } +} + +function checkIfValid(target, e) { + const targetId = + Number(e.target.getAttribute("square-id")) || + Number(e.target.parentNode.getAttribute("square-id")); // The Number function converts any type of value to numbers + const startId = Number(startPositionId); + const piece = draggedElement.id; + + // DEFINING THE MOVES OF THE VARIOUS PIECES + // The switch statement evaluates an expression, matching the expression's value against a series of case clauses, and executes statements after the first case clause with a matching value, until a break statement is encountered. + switch (piece) { + case "pawn": + const starterRow = [8, 9, 10, 11, 12, 13, 14, 15]; // for the pawns we need to define the starterRow because only if they're in the starterRow can they move two spaces forward + if ( + (starterRow.includes(startId) && startId + width * 2 === targetId) || + startId + width === targetId || + (startId + width - 1 === targetId && + document.querySelector(`[square-id="${startId + width - 1}"]`) + .firstChild) || // check that there is an opponent on this square, or this move is not allowed + (startId + width + 1 === targetId && + document.querySelector(`[square-id="${startId + width + 1}"]`) + .firstChild) // check that there is an opponent on this square, or this move is not allowed + ) { + return true; + } + break; + case "knight": + if ( + startId + width * 2 + 1 === targetId || + startId + width * 2 - 1 === targetId || + startId + width + 2 === targetId || + startId + width - 2 === targetId || + startId - width * 2 + 1 === targetId || + startId - width * 2 - 1 === targetId || + startId - width + 2 === targetId || + startId - width - 2 === targetId + ) { + return true; + } + break; + case "bishop": + if ( + startId + width + 1 === targetId || + (startId + width * 2 + 2 === targetId && + !document.querySelector(`[square-id="${startId + width + 1}"]`) + .firstchild) || // checking that there is no other piece in the way, preventing the bishop to reach the target square + (startId + width * 3 + 3 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild) || + (startId + width * 4 + 4 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 + 3}"]`) + .firstChild) || + (startId + width * 5 + 5 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 + 4}"]`) + .firstChild) || + (startId + width * 6 + 6 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 + 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5 + 5}"]`) + .firstChild) || + (startId + width * 7 + 7 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 + 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5 + 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 6 + 6}"]`) + .firstChild) || + startId + width - 1 === targetId || + (startId + width * 2 - 2 === targetId && + !document.querySelector(`[square-id="${startId + width - 1}"]`) + .firstchild) || + (startId + width * 3 - 3 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild) || + (startId + width * 4 - 4 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 - 3}"]`) + .firstChild) || + (startId + width * 5 - 5 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 - 4}"]`) + .firstChild) || + (startId + width * 6 - 6 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 - 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5 - 5}"]`) + .firstChild) || + (startId + width * 7 - 7 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 - 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5 - 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 6 - 6}"]`) + .firstChild) || + startId - width + 1 === targetId || + (startId - width * 2 + 2 === targetId && + !document.querySelector(`[square-id="${startId - width + 1}"]`) + .firstchild) || + (startId - width * 3 + 3 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild) || + (startId - width * 4 + 4 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 + 3}"]`) + .firstChild) || + (startId - width * 5 + 5 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 + 4}"]`) + .firstChild) || + (startId - width * 6 + 6 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 + 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5 + 5}"]`) + .firstChild) || + (startId - width * 7 + 7 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 + 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5 + 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 6 + 6}"]`) + .firstChild) || + startId - width - 1 === targetId || + (startId - width * 2 - 2 === targetId && + !document.querySelector(`[square-id="${startId - width - 1}"]`) + .firstchild) || + (startId - width * 3 - 3 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild) || + (startId - width * 4 - 4 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 - 3}"]`) + .firstChild) || + (startId - width * 5 - 5 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 - 4}"]`) + .firstChild) || + (startId - width * 6 - 6 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 - 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5 - 5}"]`) + .firstChild) || + (startId - width * 7 - 7 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 - 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5 - 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 6 - 6}"]`) + .firstChild) + ) { + return true; + } + break; + case "rook": + if ( + startId + width === targetId || + (startId + width * 2 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild) || + (startId + width * 3 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild) || + (startId + width * 4 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3}"]`) + .firstChild) || + (startId + width * 5 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4}"]`) + .firstChild) || + (startId + width * 6 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5}"]`) + .firstChild) || + (startId + width * 7 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 6}"]`) + .firstChild) || + startId - width === targetId || + (startId - width * 2 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild) || + (startId - width * 3 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild) || + (startId - width * 4 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3}"]`) + .firstChild) || + (startId - width * 5 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4}"]`) + .firstChild) || + (startId - width * 6 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5}"]`) + .firstChild) || + (startId - width * 7 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 6}"]`) + .firstChild) || + startId + 1 === targetId || + (startId + 2 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild) || + (startId + 3 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild) || + (startId + 4 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 3}"]`).firstChild) || + (startId + 5 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 4}"]`).firstChild) || + (startId + 6 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 4}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 5}"]`).firstChild) || + (startId + 7 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 4}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 5}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 6}"]`).firstChild) || + startId - 1 === targetId || + (startId - 2 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild) || + (startId - 3 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild) || + (startId - 4 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 3}"]`).firstChild) || + (startId - 5 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 4}"]`).firstChild) || + (startId - 6 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 4}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 5}"]`).firstChild) || + (startId - 7 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 4}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 5}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 6}"]`).firstChild) + ) { + return true; + } + break; + case "queen": + if ( + // bishop's moves + startId + width + 1 === targetId || + (startId + width * 2 + 2 === targetId && + !document.querySelector(`[square-id="${startId + width + 1}"]`) + .firstchild) || // checking that there is no other piece in the way, preventing the bishop to reach the target square + (startId + width * 3 + 3 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild) || + (startId + width * 4 + 4 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 + 3}"]`) + .firstChild) || + (startId + width * 5 + 5 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 + 4}"]`) + .firstChild) || + (startId + width * 6 + 6 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 + 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5 + 5}"]`) + .firstChild) || + (startId + width * 7 + 7 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 + 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5 + 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 6 + 6}"]`) + .firstChild) || + startId + width - 1 === targetId || + (startId + width * 2 - 2 === targetId && + !document.querySelector(`[square-id="${startId + width - 1}"]`) + .firstchild) || + (startId + width * 3 - 3 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild) || + (startId + width * 4 - 4 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 - 3}"]`) + .firstChild) || + (startId + width * 5 - 5 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 - 4}"]`) + .firstChild) || + (startId + width * 6 - 6 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 - 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5 - 5}"]`) + .firstChild) || + (startId + width * 7 - 7 === targetId && + !document.querySelector(`[square-id="${startId + width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4 - 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5 - 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 6 - 6}"]`) + .firstChild) || + startId - width + 1 === targetId || + (startId - width * 2 + 2 === targetId && + !document.querySelector(`[square-id="${startId - width + 1}"]`) + .firstchild) || + (startId - width * 3 + 3 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild) || + (startId - width * 4 + 4 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 + 3}"]`) + .firstChild) || + (startId - width * 5 + 5 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 + 4}"]`) + .firstChild) || + (startId - width * 6 + 6 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 + 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5 + 5}"]`) + .firstChild) || + (startId - width * 7 + 7 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 + 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 + 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 + 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5 + 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 6 + 6}"]`) + .firstChild) || + startId - width - 1 === targetId || + (startId - width * 2 - 2 === targetId && + !document.querySelector(`[square-id="${startId - width - 1}"]`) + .firstchild) || + (startId - width * 3 - 3 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild) || + (startId - width * 4 - 4 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 - 3}"]`) + .firstChild) || + (startId - width * 5 - 5 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 - 4}"]`) + .firstChild) || + (startId - width * 6 - 6 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 - 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5 - 5}"]`) + .firstChild) || + (startId - width * 7 - 7 === targetId && + !document.querySelector(`[square-id="${startId - width * 2 - 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3 - 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4 - 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5 - 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 6 - 6}"]`) + .firstChild) || + //rook's moves + startId + width === targetId || + (startId + width * 2 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild) || + (startId + width * 3 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild) || + (startId + width * 4 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3}"]`) + .firstChild) || + (startId + width * 5 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4}"]`) + .firstChild) || + (startId + width * 6 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5}"]`) + .firstChild) || + (startId + width * 7 === targetId && + !document.querySelector(`[square-id="${startId + width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId + width * 6}"]`) + .firstChild) || + startId - width === targetId || + (startId - width * 2 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild) || + (startId - width * 3 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild) || + (startId - width * 4 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3}"]`) + .firstChild) || + (startId - width * 5 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4}"]`) + .firstChild) || + (startId - width * 6 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5}"]`) + .firstChild) || + (startId - width * 7 === targetId && + !document.querySelector(`[square-id="${startId - width}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 2}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 3}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 4}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 5}"]`) + .firstChild && + !document.querySelector(`[square-id="${startId - width * 6}"]`) + .firstChild) || + startId + 1 === targetId || + (startId + 2 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild) || + (startId + 3 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild) || + (startId + 4 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 3}"]`).firstChild) || + (startId + 5 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 4}"]`).firstChild) || + (startId + 6 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 4}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 5}"]`).firstChild) || + (startId + 7 === targetId && + !document.querySelector(`[square-id="${startId + 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 4}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 5}"]`).firstChild && + !document.querySelector(`[square-id="${startId + 6}"]`).firstChild) || + startId - 1 === targetId || + (startId - 2 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild) || + (startId - 3 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild) || + (startId - 4 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 3}"]`).firstChild) || + (startId - 5 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 4}"]`).firstChild) || + (startId - 6 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 4}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 5}"]`).firstChild) || + (startId - 7 === targetId && + !document.querySelector(`[square-id="${startId - 1}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 2}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 3}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 4}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 5}"]`).firstChild && + !document.querySelector(`[square-id="${startId - 6}"]`).firstChild) + ) { + return true; + } + break; + case "king": + if ( + startId + 1 === targetId || + startId - 1 === targetId || + startId + width === targetId || + startId - width === targetId || + startId + width + 1 === targetId || + startId + width - 1 === targetId || + startId - width + 1 === targetId || + startId - width - 1 === targetId + ) { + return true; + } + } } // SWITCHING PLAYERS' TURNS @@ -148,10 +886,11 @@ function changePlayer() { } function reverseIds() { - // I'm confused as to when to use a parameter in a function and when not. Why wouldn't I use "i" here as a parameter? + // // I'm confused as to when to use a parameter in a function and when not. Why wouldn't I use "i" here as a parameter? const allSquares = document.querySelectorAll(".square"); // grab everything that has the class "square" allSquares.forEach((square, i) => // for each square, override the existing squareId with its reverse (width * width - 1) - i + // TODO(Martin): Oh wow what is the point of this, reversing all ids? I wonder why would we do that? Quite wild. square.setAttribute("square-id", width * width - 1 - i) ); // set the reversed squareId as the attribute } @@ -160,3 +899,85 @@ function revertIds() { const allSquares = document.querySelectorAll(".square"); allSquares.forEach((square, i) => square.setAttribute("square-id", i)); } + +function checkForVictory() { + const kings = Array.from(document.querySelectorAll("#king")); + if (!kings.some((king) => king.firstChild.classList.contains("white"))) { + // if there is no white king in my array of kings, black wins (and vv) + infoDisplay.innerHTML = "Black wins!"; + const allSquares = document.querySelectorAll(".square"); + allSquares.forEach((square) => + square.firstChild?.setAttribute("draggable", false) + ); // once game is over, the pieces should no longer be draggable + } + if (!kings.some((king) => king.firstChild.classList.contains("black"))) { + infoDisplay.innerHTML = "White wins!"; + const allSquares = document.querySelectorAll(".square"); + allSquares.forEach((square) => + square.firstChild?.setAttribute("draggable", false) + ); + } +} + +// TODO(Martin): Nice :)! This is actually quite complex code though, hard to reason about, and easy to make mistakes with. +// Not pleasant to write nor read. Not because you wrote it badly, but because of overall architecture, it is all too +// intertwined and mixed up. So I will recommend you a different, typical approach for these kind of programmes, +// that will make code much nicer and easier to work with, and it should be much more enjoyable. +// +// So, the main idea is that you want to separate "view" logic from "business"/"core" logic (let's call it "core" logic). +// +// View logic would be: I know what the chess board looks like, how do I show it on screen? +// +// Core logic would be: If player wants to do a move, how do I udpate the board to reflect that? +// How do I know if the move is valid? Whose turn is it? So really, all chess-related stuff and +// rules and so on, without worrying about how to actually show this to user: will it be shown in +// brwoser, or will you print the whole board into console with console.log and ascii characters. +// Core logic doesn't care about that, it cares about chess. +// +// Actually there is also "model" logic, which is about how we represent the actual board in Javascript, +// how do we "model" it. +// You could say that is part of "core" logic, but you can also look at it as a separate "model" logic. +// +// So this is called MVC (Model-View-Controller) architecture (controller == core logic), and is a popular pattern in +// programming, for certain tasks where it is a good fit. You can google this, although it will probably be a bit +// to abstractly explained, but still give it a look. +// +// So you really want to work in this way, because otherwise it will be too hard (already is). +// +// In our case, this would mean something like this: +// +// function displayBoard(board) { ... } // Does all the `document.` stuff to show the board in the browser. +// // Any board though, not just initial board! That is important. +// // This is our "View" logic. +// +// const initialBoard = [ // List of 8 lists where each of those inner lists has 8 elements. This is our "model" logic. +// [{ type: "rook", color: "white"}, { type: "knight", color: "white"}, ... ], +// [null, null, null, ...], +// [null, ...], +// ..., +// [{ type: "rook", color: "black"}, { type: "knight", color: "black"}, ...] +// ]; +// const initialGameState = { // This is another part of our "model" logic. +// currentPlayer: "white", +// board: initialBoard +// } +// +// And now comes the crux of things, our "core" logic (or Controller). +// It will consists of bunch of functions. +// +// function movePiece([startRow, startCol], [endRow, endCol], board) { ... } +// // This function will, given the current board, return a new board that will have the piece moved from start to end location. +// // We could also have one global `currentBoard` variable that this function would just update, that is alternative approach, +// // but this is even nicer, where you don't have global variable but are instead passing the board around and creating modifications of it. +// +// function isMoveValid([startRow, startCol], [endRow, endCol], board) { ... } +// +// function checkForVictory(board) { ... } +// +// function calculateCurrentScore(board) { ... } +// +// And so on and on. +// +// The whole point is, when doing complex stuff like chess rules and logic, you dont' have to dig through `docuemnt` and classes and DOM elements and stuff, you instead always focus on your simple list of lists and all is nice and simple. +// So you will want to rewrite your chess like this! +// I would suggest you forget drag and drop for start. Just try to get initial board to draw with this MVC approach, and then provide two input fields in your program, where user says initial field and end field, liek F1 and F2 and then they can press "move", and then try to get that move happening. Later we can upgrade that to be drag and drop instead of entering moves via text. diff --git a/index.html b/index.html index b8a5d84..ff26fe8 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@

It is 's turn.

- + diff --git a/pieces.js b/pieces.js index d9a7a81..fb02dd8 100644 --- a/pieces.js +++ b/pieces.js @@ -1,3 +1,5 @@ +// TODO(martin): How about you must move this logic into app.js, and you can then not have this second file? + const king = '
'; const queen = diff --git a/styles.css b/styles.css index ba0f691..ae154b9 100644 --- a/styles.css +++ b/styles.css @@ -8,6 +8,7 @@ .square { width: 80px; height: 80px; + position: relative; } .bright {