diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..75d93e8 Binary files /dev/null and b/.DS_Store differ diff --git a/public/css/chess.css b/public/css/chess.css index 6705394..54e9a6c 100644 --- a/public/css/chess.css +++ b/public/css/chess.css @@ -1,106 +1,63 @@ #game-ct { - width: 400px; - height: 400px; + width: 400px; /* Retaining the board size */ + height: 400px; /* Retaining the board size */ margin: 20px auto; border: 2px solid #333; display: grid; grid-template-columns: repeat(8, 1fr); padding: 0; - } - #game-ct > li { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); /* Add a slight shadow to the board */ +} + +#game-ct > li { list-style-type: none; padding: 0; - } - #game-ct > li > ul { +} + +#game-ct > li > ul { height: 100%; padding: 0; margin: 0; display: contents; - } - #game-ct li > ul > li { - width: 100%; - height: 50px; - list-style-type: none; - } - #game-ct li:nth-child(odd) li:nth-child(even), - #game-ct li:nth-child(even) li:nth-child(odd) { - background-color: #b58863; - } - #game-ct li:nth-child(even) li:nth-child(even), - #game-ct li:nth-child(odd) li:nth-child(odd) { - background-color: #f0d9b5; - } - - - -.piece { - background-image: url('/images/chess_sprite_transparent.png'); - background-repeat: no-repeat; - background-size: 600% 200%; } - -.white.king { - background-position: -9px 0; -} - -.black.king { - background-position: -9px -50px; -} - - -.white.queen { - background-position: -55px 0; -} - -.black.queen { - background-position: -55px -50px; -} - -.white.bishop { - background-position: -103px 0; -} - -.black.bishop { - background-position: -103px -50px; -} - -.white.knight { - background-position: -152px 0; -} - -.black.knight { - background-position: -152px -50px; -} - -.white.rook { - background-position: -198px 0; -} - -.black.rook { - background-position: -198px -50px; +#game-ct li > ul > li { + width: 100%; + height: 50px; /* Keeping the square size at 50px */ + list-style-type: none; } -.white.pawn { - background-position: -247px 0; +/* Checkerboard pattern */ +#game-ct li:nth-child(odd) li:nth-child(even), +#game-ct li:nth-child(even) li:nth-child(odd) { + background-color: #769656; /* Green color for dark squares */ } -.black.pawn { - background-position: -247px -50px; +#game-ct li:nth-child(even) li:nth-child(even), +#game-ct li:nth-child(odd) li:nth-child(odd) { + background-color: #eeeed2; /* Light beige color for light squares */ } +/* Piece styling */ .piece { + background-image: url('../images/chess_sprite_transparent.png'); /* Custom chess piece image */ + background-repeat: no-repeat; + background-size: 600% 200%; /* Adjusting sprite positions */ width: 100%; height: 100%; + transition: all 0.3s ease; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* Add shadow for a more 3D feel */ } +/* Highlight the selected piece with a green shadow */ .piece.selected { - box-shadow: 0 0 10px 3px rgba(0, 255, 0, 0.7); - transform: scale(1.1); + box-shadow: 0 0 10px 3px rgba(0, 255, 0, 0.7); /* Green glow for selection */ + transform: scale(1.1); /* Slightly larger size for selected piece */ transition: all 0.3s ease; z-index: 10; } +/* Highlight square of the selected piece with a green border */ .piece.selected::after { content: ''; position: absolute; @@ -110,7 +67,33 @@ bottom: -5px; border: 2px solid #00ff00; border-radius: 5px; - pointer-events: none; + pointer-events: none; /* This ensures clicks pass through the border */ } +/* Positions for chess pieces using sprite sheet */ +.white.king { background-position: -9px 0; } +.black.king { background-position: -9px -50px; } + +.white.queen { background-position: -55px 0; } +.black.queen { background-position: -55px -50px; } + +.white.bishop { background-position: -103px 0; } +.black.bishop { background-position: -103px -50px; } + +.white.knight { background-position: -152px 0; } +.black.knight { background-position: -152px -50px; } +.white.rook { background-position: -198px 0; } +.black.rook { background-position: -198px -50px; } + +.white.pawn { background-position: -247px 0; } +.black.pawn { background-position: -247px -50px; } + +.highlight { + background-color: rgba(255, 255, 0, 0.5); /* Yellow translucent background */ + border-radius: 50%; /* Make it circular */ + width: 100%; + height: 100%; + position: relative; + z-index: 1; +} diff --git a/public/javascript/chess/board.js b/public/javascript/chess/board.js index 3e54332..7461444 100644 --- a/public/javascript/chess/board.js +++ b/public/javascript/chess/board.js @@ -1,18 +1,21 @@ -var Board = function(config){ +var Board = function(config) { this.root_id = config.root_id; this.$el = document.getElementById(this.root_id); + this.currentTurn = 'white'; + this.selectedPiece = null; // Initialize selectedPiece this.generateBoardDom(); this.addListeners(); + this.initiateGame(); // Start the game } -Board.prototype.addListeners = function(){ +Board.prototype.addListeners = function() { this.$el.addEventListener('click', this.boardClicked.bind(this)); } -Board.prototype.generateBoardDom = function(config){ +Board.prototype.generateBoardDom = function() { let boardHTML = ''; - + this.$el.innerHTML = boardHTML; } -Board.prototype.getClickedBlock = function(clickEvent){ - // Get the clicked block - const clickedCell = clickEvent.target.closest('li'); +Board.prototype.getClickedBlock = function(clickEvent) { + const clickedCell = clickEvent.target.closest('li[data-row]'); if (clickedCell) { - // Extract row and column from data attributes const row = clickedCell.getAttribute('data-row'); const parentLi = clickedCell.closest('li[data-col]'); const col = parentLi ? parentLi.getAttribute('data-col') : null; if (row !== null && col !== null) { - return { - row: row, - col: col - }; + return { row: row, col: col }; } else { console.warn('Unable to determine block coordinates'); } @@ -48,31 +46,74 @@ Board.prototype.getClickedBlock = function(clickEvent){ console.warn('Clicked element is not within a board square'); } } - -Board.prototype.clearSelection = function(){ - // Remove 'selected' class from all pieces - const allPieces = document.querySelectorAll('.piece'); - allPieces.forEach(piece => { +Board.prototype.clearSelection = function() { + // Deselect all currently selected pieces + const selectedPieces = document.querySelectorAll('.selected'); + selectedPieces.forEach(piece => { piece.classList.remove('selected'); }); + + this.selectedPiece = null; // Reset the selected piece }; -Board.prototype.boardClicked = function(event){ - this.clearSelection(); +Board.prototype.boardClicked = function(event) { const clickedCell = this.getClickedBlock(event); - const selectedPiece = this.getPieceAt(clickedCell) - if(selectedPiece){ - //Add 'selected' class to the clicked piece - this.selectPiece(event.target, selectedPiece); - }else{ - //update position of the selected piece to new position - if(this.selectedPiece){ - this.selectedPiece.moveTo(clickedCell); - } - } + if (!clickedCell) return; // Exit if click was not on a valid cell + + const piece = this.getPieceAt(clickedCell); + + if (this.selectedPiece) { // If a piece is already selected + if (piece) { + // If the player clicks on a piece of the same color, allow reselection + if (piece.color === this.selectedPiece.color) { + console.log(`Reselecting your own piece.`); + this.selectPiece(event.target, piece); // Reselect the new piece + return; + } else { + // If clicked on an opponent's piece, validate move before capturing + const targetPosition = { row: clickedCell.row, col: clickedCell.col }; + const isValidMove = this.selectedPiece.isValidMove(targetPosition); + + if (!isValidMove) { + console.log('Invalid move, try again.'); + return; // Do not switch turns or move the piece if invalid move + } + + // Valid move, so capture the opponent's piece + this.selectedPiece.moveTo(clickedCell); + this.clearSelection(); + this.switchTurn(); // Switch turn after a valid move + } + } else { + // Empty cell clicked, validate move and proceed + const targetPosition = { row: clickedCell.row, col: clickedCell.col }; + const isValidMove = this.selectedPiece.isValidMove(targetPosition); + + if (!isValidMove) { + console.log('Invalid move, try again.'); + return; // Do not switch turns or move the piece if invalid move + } + + // Move the selected piece to the new position + this.selectedPiece.moveTo(clickedCell); + this.clearSelection(); + this.switchTurn(); // Switch turn after a valid move + } + } else { + if (piece) { + // Select the piece if it's the player's turn + if (piece.color === this.currentTurn) { + this.selectPiece(event.target, piece); + } else { + console.log(`It's ${this.currentTurn}'s turn! You cannot select an opponent's piece.`); + } + } + } } -Board.prototype.getPieceAt = function(cell){ + + +Board.prototype.getPieceAt = function(cell) { if (!cell || !cell.row || !cell.col) { return false; } @@ -81,103 +122,100 @@ Board.prototype.getPieceAt = function(cell){ // Check white pieces for (let pieceType in this.whitePieces) { - if (Array.isArray(this.whitePieces[pieceType])) { - // For arrays (pawns, bishops, knights, rooks) - for (let piece of this.whitePieces[pieceType]) { - if (piece.position === position) { - return piece; - } - } - } else { - // For single pieces (king, queen) - if (this.whitePieces[pieceType].position === position) { - return this.whitePieces[pieceType]; + const pieceArray = Array.isArray(this.whitePieces[pieceType]) ? this.whitePieces[pieceType] : [this.whitePieces[pieceType]]; + for (let piece of pieceArray) { + if (piece.position === position) { + return piece; } } } // Check black pieces for (let pieceType in this.blackPieces) { - if (Array.isArray(this.blackPieces[pieceType])) { - // For arrays (pawns, bishops, knights, rooks) - for (let piece of this.blackPieces[pieceType]) { - if (piece.position === position) { - return piece; - } - } - } else { - // For single pieces (king, queen) - if (this.blackPieces[pieceType].position === position) { - return this.blackPieces[pieceType]; + const pieceArray = Array.isArray(this.blackPieces[pieceType]) ? this.blackPieces[pieceType] : [this.blackPieces[pieceType]]; + for (let piece of pieceArray) { + if (piece.position === position) { + return piece; } } } return false; } +Board.prototype.switchTurn = function() { + this.currentTurn = this.currentTurn === 'white' ? 'black' : 'white'; + console.log(`It's now ${this.currentTurn}'s turn!`); +} + Board.prototype.selectPiece = function(clickedElement, selectedPiece) { + // First clear any existing selection + this.clearSelection(); + + // Highlight the new selected piece only if (clickedElement.classList.contains('piece')) { - // If the clicked element is a piece, add the 'selected' class clickedElement.classList.add('selected'); } else { - // If the clicked element is not a piece, check its parent const parentElement = clickedElement.closest('.piece'); if (parentElement) { parentElement.classList.add('selected'); } } + selectedPiece.selected = true; - this.selectedPiece = selectedPiece; + this.selectedPiece = selectedPiece; // Set the selected piece } Board.prototype.initiateGame = function() { // Create white pieces this.whitePieces = { - king: new King({ color: 'white', position: 'E1' }), - queen: new Queen({ color: 'white', position: 'D1' }), + king: new King({ color: 'white', position: 'D1', board: this }), + queen: new Queen({ color: 'white', position: 'E1', board: this }), bishops: [ - new Bishop({ color: 'white', position: 'C1' }), - new Bishop({ color: 'white', position: 'F1' }) + new Bishop({ color: 'white', position: 'C1', board: this }), + new Bishop({ color: 'white', position: 'F1', board: this }) ], knights: [ - new Knight({ color: 'white', position: 'B1' }), - new Knight({ color: 'white', position: 'G1' }) + new Knight({ color: 'white', position: 'B1', board: this }), + new Knight({ color: 'white', position: 'G1', board: this }) ], rooks: [ - new Rook({ color: 'white', position: 'A1' }), - new Rook({ color: 'white', position: 'H1' }) + new Rook({ color: 'white', position: 'A1', board: this }), + new Rook({ color: 'white', position: 'H1', board: this }) ], pawns: [] }; // Create white pawns for (let i = 0; i < 8; i++) { - this.whitePieces.pawns.push(new Pawn({ color: 'white', position: String.fromCharCode(65 + i) + '2' })); + this.whitePieces.pawns.push(new Pawn({ color: 'white', position: String.fromCharCode(65 + i) + '2', board: this })); } // Create black pieces this.blackPieces = { - king: new King({ color: 'black', position: 'E8' }), - queen: new Queen({ color: 'black', position: 'D8' }), + king: new King({ color: 'black', position: 'D8', board: this }), + queen: new Queen({ color: 'black', position: 'E8', board: this }), bishops: [ - new Bishop({ color: 'black', position: 'C8' }), - new Bishop({ color: 'black', position: 'F8' }) + new Bishop({ color: 'black', position: 'C8', board: this }), + new Bishop({ color: 'black', position: 'F8', board: this }) ], knights: [ - new Knight({ color: 'black', position: 'B8' }), - new Knight({ color: 'black', position: 'G8' }) + new Knight({ color: 'black', position: 'B8', board: this }), + new Knight({ color: 'black', position: 'G8', board: this }) ], rooks: [ - new Rook({ color: 'black', position: 'A8' }), - new Rook({ color: 'black', position: 'H8' }) + new Rook({ color: 'black', position: 'A8', board: this }), + new Rook({ color: 'black', position: 'H8', board: this }) ], pawns: [] }; // Create black pawns for (let i = 0; i < 8; i++) { - this.blackPieces.pawns.push(new Pawn({ color: 'black', position: String.fromCharCode(65 + i) + '7' })); + this.blackPieces.pawns.push(new Pawn({ color: 'black', position: String.fromCharCode(65 + i) + '7', board: this })); } + + // Render all pieces after initiating the game + this.renderAllPieces(); }; Board.prototype.renderAllPieces = function() { diff --git a/public/javascript/chess/piece.js b/public/javascript/chess/piece.js index 05aceb0..acb9a2d 100644 --- a/public/javascript/chess/piece.js +++ b/public/javascript/chess/piece.js @@ -1,6 +1,8 @@ var Piece = function(config){ this.position = config.position; this.color = config.color; + this.board = config.board; + this.currentTurn = config.currentTurn; if(this.position){ this.render(); } @@ -42,6 +44,31 @@ Piece.prototype.render = function(){ } } -Piece.prototype.kill = function(targetPiece){ - console.log("Method not implemeted by: " + typeof(this)); -} \ No newline at end of file +Piece.prototype.kill = function(targetPiece) { + if (targetPiece) { + const targetPosition = targetPiece.position; + const targetElement = document.querySelector(`[data-col="${targetPosition[0]}"] [data-row="${targetPosition[1]}"]`); + targetElement.innerHTML = ''; // Remove the target piece from the board + + // Remove the target piece from the appropriate pieces object + if (targetPiece.color === 'white') { + for (let pieceType in this.board.whitePieces) { + const pieceArray = Array.isArray(this.board.whitePieces[pieceType]) ? this.board.whitePieces[pieceType] : [this.board.whitePieces[pieceType]]; + const index = pieceArray.indexOf(targetPiece); + if (index !== -1) { + pieceArray.splice(index, 1); + break; + } + } + } else { + for (let pieceType in this.board.blackPieces) { + const pieceArray = Array.isArray(this.board.blackPieces[pieceType]) ? this.board.blackPieces[pieceType] : [this.board.blackPieces[pieceType]]; + const index = pieceArray.indexOf(targetPiece); + if (index !== -1) { + pieceArray.splice(index, 1); + break; + } + } + } + } +}; \ No newline at end of file diff --git a/public/javascript/chess/pieces/bishop.js b/public/javascript/chess/pieces/bishop.js index 75d7392..f8b17cc 100644 --- a/public/javascript/chess/pieces/bishop.js +++ b/public/javascript/chess/pieces/bishop.js @@ -1,11 +1,68 @@ -var Bishop = function(config){ +var Bishop = function(config) { this.type = 'bishop'; - this.constructor(config); + Piece.call(this, config); + this.color = config.color; + this.position = config.position; + this.board = config.board; }; +// Properly inherit from the Piece class +Bishop.prototype = Object.create(Piece.prototype); +Bishop.prototype.constructor = Bishop; +// Move the Bishop to the target position +Bishop.prototype.moveTo = function(targetPosition) { + if (this.board.currentTurn !== this.color) { + console.log("Invalid move: Not your turn"); + return; + } + + // Check if the move is valid + if (this.isValidMove(targetPosition)) { + // Check if there's a piece at the target position + const targetPiece = this.board.getPieceAt(targetPosition); + if (targetPiece && targetPiece.color !== this.color) { + this.kill(targetPiece); // Kill the target piece if it's an opponent's + } + + this.position = targetPosition.col + targetPosition.row; + this.render(); // Re-render the bishop in the new position + console.log(this.color + " Bishop moved to " + this.position); + } else { + console.log("Invalid move for " + this.color + " bishop"); + } +}; + +// Validate the Bishop's move +Bishop.prototype.isValidMove = function(targetPosition) { + // Convert current position to row and column + let currentCol = this.position.charCodeAt(0) - 'a'.charCodeAt(0); + let currentRow = parseInt(this.position.charAt(1)) - 1; + let targetCol = targetPosition.col.charCodeAt(0) - 'a'.charCodeAt(0); + let targetRow = parseInt(targetPosition.row) - 1; -Bishop.prototype = new Piece({}); -Bishop.prototype.move = function(newPosition){ + // Check if the move is diagonal + if (Math.abs(targetCol - currentCol) === Math.abs(targetRow - currentRow)) { + // Check if the path is clear + let rowStep = targetRow > currentRow ? 1 : -1; + let colStep = targetCol > currentCol ? 1 : -1; + + for (let i = 1; i < Math.abs(targetCol - currentCol); i++) { + let checkCol = String.fromCharCode(currentCol + i * colStep + 'a'.charCodeAt(0)); + let checkRow = (currentRow + i * rowStep + 1).toString(); + if (this.board.getPieceAt({col: checkCol, row: checkRow})) { + console.warn("Path is not clear for " + this.color + " bishop"); + return false; + } + } + + // Check if the target square is empty or contains an opponent's piece + const targetPiece = this.board.getPieceAt(targetPosition); + if (!targetPiece || targetPiece.color !== this.color) { + return true; + } + } -} \ No newline at end of file + console.warn("Invalid move for " + this.color + " bishop"); + return false; +}; \ No newline at end of file diff --git a/public/javascript/chess/pieces/king.js b/public/javascript/chess/pieces/king.js index 41aed5f..c7af5ee 100644 --- a/public/javascript/chess/pieces/king.js +++ b/public/javascript/chess/pieces/king.js @@ -1,11 +1,58 @@ -var King = function(config){ - this.type = 'king'; +var King = function (config) { + this.type = "king"; this.constructor(config); }; +King.prototype = new Piece({}); +King.prototype.kill = function (targetPiece) { + const targetPosition = targetPiece.position; + const targetElement = document.querySelector( + `[data-col="${targetPosition[0]}"] [data-row="${targetPosition[1]}"]` + ); + targetElement.innerHTML = ""; // Remove the target piece from the board -King.prototype = new Piece({}); -King.prototype.move = function(newPosition){ + console.log("King killed " + targetPiece.type); +}; +King.prototype.isValidMove = function (targetPosition) { + // Convert current position to row and column + let currentCol = this.position.charAt(0); + let currentRow = parseInt(this.position.charAt(1)); + + // Calculate the target position row and column + let targetCol = targetPosition.col; + let targetRow = targetPosition.row; + + // Calculate the difference in rows and columns + let rowDifference = Math.abs(targetRow - currentRow); + let colDifference = Math.abs( + targetCol.charCodeAt(0) - currentCol.charCodeAt(0) + ); -} \ No newline at end of file + // King can move one square in any direction (horizontal, vertical, or diagonal) + if (rowDifference <= 1 && colDifference <= 1) { + return true; // Valid king move + } + + // If none of the conditions are met, the move is invalid + console.warn("Invalid move for king"); + return false; +}; + +King.prototype.moveTo = function (targetPosition) { + if (this.board.currentTurn !== this.color) { + console.log("Invalid move: Not your turn"); + return; + } + if ( + this.isValidMove(targetPosition) && + this.board.getPieceAt(targetPosition) !== null && + this.board.getPieceAt(targetPosition).color !== this.color + ) + if (this.isValidMove(targetPosition)) { + this.position = targetPosition.col + targetPosition.row; + this.render(); + } else { + console.log("Invalid move for king"); + } +}; diff --git a/public/javascript/chess/pieces/knight.js b/public/javascript/chess/pieces/knight.js index 3957e36..3b8027b 100644 --- a/public/javascript/chess/pieces/knight.js +++ b/public/javascript/chess/pieces/knight.js @@ -3,9 +3,40 @@ var Knight = function(config){ this.constructor(config); }; +Knight.prototype = new Piece({}); +Knight.prototype.isValidMove = function(targetPosition) { + + var currentRow = parseInt(this.position[1], 10); + var targetRow = parseInt(targetPosition.row, 10); + var currentCol = this.position[0].toUpperCase().charCodeAt(0) - 65; + var targetCol = targetPosition.col.toUpperCase().charCodeAt(0) - 65; + + var rowDiff = Math.abs(targetRow - currentRow); + var colDiff = Math.abs(targetCol - currentCol); + + if ((rowDiff === 2 && colDiff === 1) || (rowDiff === 1 && colDiff === 2)) { + return true; + } + else { + console.log("Invalid move: Knight must move in an L-shape"); + return false; + } +}; + +Knight.prototype.moveTo = function(targetPosition) { + var isValidMove = this.isValidMove(targetPosition); + if (!isValidMove) { + console.log("Invalid move for knight"); + return; + } + + const targetPiece = this.board.getPieceAt(targetPosition); + if (targetPiece) { + this.kill(targetPiece); + } + this.position = targetPosition.col + targetPosition.row; + this.render(); +}; -Knight.prototype = new Piece({}); -Knight.prototype.move = function(newPosition){ -} \ No newline at end of file diff --git a/public/javascript/chess/pieces/pawn.js b/public/javascript/chess/pieces/pawn.js index b8b2460..d408dd9 100644 --- a/public/javascript/chess/pieces/pawn.js +++ b/public/javascript/chess/pieces/pawn.js @@ -1,14 +1,51 @@ -var Pawn = function(config){ +var Pawn = function(config) { this.type = 'pawn'; - this.constructor(config); + Piece.call(this, config); + this.color = config.color; + this.position = config.position; + this.board = config.board; }; +// Properly inherit from the Piece class +Pawn.prototype = Object.create(Piece.prototype); +Pawn.prototype.constructor = Pawn; +// Move the Pawn to the target position +Pawn.prototype.moveTo = function(targetPosition) { + if (this.board.currentTurn !== this.color) { + console.log("Invalid move: Not your turn"); + return; + } + + // Check if the move is valid + if (this.isValidMove(targetPosition)) { + const targetPiece = this.board.getPieceAt(targetPosition); + + // Check if it is a capture move + if (this.isDiagonalCapture(targetPosition) && targetPiece && targetPiece.color !== this.color) { + this.kill(targetPiece); // Capture the target piece + } else if (this.isStraightMove(targetPosition) && !targetPiece) { + // Normal straight move, no capture + } else { + console.log("Invalid move: Cannot move there"); + return; + } + + this.position = targetPosition.col + targetPosition.row; + this.render(); // Re-render the pawn in the new position + console.log("Pawn moved to " + this.position); + } else { + console.log("Invalid move for pawn"); + } +}; -Pawn.prototype = new Piece({}); +// Validate the Pawn's move +Pawn.prototype.isValidMove = function(targetPosition) { + return this.isStraightMove(targetPosition) || this.isDiagonalCapture(targetPosition); +}; -Pawn.prototype.isValidPosition = function(targetPosition){ - // Convert current position to row and column +// Check if the move is a valid straight move (forward) +Pawn.prototype.isStraightMove = function(targetPosition) { let currentCol = this.position.charAt(0); let currentRow = parseInt(this.position.charAt(1)); @@ -16,33 +53,32 @@ Pawn.prototype.isValidPosition = function(targetPosition){ let moveDistance = this.color === 'white' ? 1 : -1; let initialRow = this.color === 'white' ? 2 : 7; - // Check if the move is valid + // Straight movement (no column change) if (targetPosition.col === currentCol) { - // Moving straight + // Regular one-square move if (targetPosition.row === (currentRow + moveDistance).toString()) { - // Regular one-square move return true; - } else if (currentRow === initialRow && targetPosition.row === (currentRow + 2 * moveDistance).toString()) { - // Initial two-square move + } + // Initial two-square move + else if (currentRow === initialRow && targetPosition.row === (currentRow + 2 * moveDistance).toString()) { return true; } - } else if (Math.abs(targetPosition.col.charCodeAt(0) - currentCol.charCodeAt(0)) === 1 && - targetPosition.row === (currentRow + moveDistance).toString()) { - // Diagonal capture (assuming there's an enemy piece, which should be checked in the main game logic) - return true; } - // If none of the above conditions are met, the move is invalid - console.warn("Invalid move for pawn"); - return false; -} + return false; // Invalid straight move +}; -Pawn.prototype.moveTo = function(targetPosition){ - if(this.isValidPosition(targetPosition)){ - this.position = targetPosition.col + targetPosition.row; - this.render(); - }else{ - //NOOP +// Check if the move is a diagonal capture +Pawn.prototype.isDiagonalCapture = function(targetPosition) { + let currentCol = this.position.charAt(0); + let currentRow = parseInt(this.position.charAt(1)); + + // Check diagonal move + if (Math.abs(targetPosition.col.charCodeAt(0) - currentCol.charCodeAt(0)) === 1 && + targetPosition.row === (currentRow + (this.color === 'white' ? 1 : -1)).toString()) { + const targetPiece = this.board.getPieceAt(targetPosition); + return targetPiece && targetPiece.color !== this.color; // Only capture if there's an opponent's piece } - -} \ No newline at end of file + + return false; +}; diff --git a/public/javascript/chess/pieces/queen.js b/public/javascript/chess/pieces/queen.js index 7b114c2..8d465b6 100644 --- a/public/javascript/chess/pieces/queen.js +++ b/public/javascript/chess/pieces/queen.js @@ -3,9 +3,75 @@ var Queen = function(config){ this.constructor(config); }; +Queen.prototype = new Piece({}); +Queen.prototype.moveTo = function(targetPosition) { + var isValidMove = this.isValidMove(targetPosition); + if (!isValidMove) { + console.log("Invalid move for queen"); + return; + } + + const targetPiece = this.board.getPieceAt(targetPosition); + if (targetPiece) { + this.kill(targetPiece); + } -Queen.prototype = new Piece({}); -Queen.prototype.move = function(newPosition){ + console.log("move function starts here"); + var newPos = targetPosition.col + targetPosition.row; + this.position = newPos; + this.render(); + console.log("move function successfully ends here"); +}; + +Queen.prototype.isValidMove = function(targetPosition) { + var currentRow = parseInt(this.position[1], 10); + var targetRow = parseInt(targetPosition.row, 10); + var currentCol = this.position[0].toUpperCase().charCodeAt(0) - 65; + var targetCol = targetPosition.col.toUpperCase().charCodeAt(0) - 65; + + console.log("currentRow: ", currentRow, "targetRow: ", targetRow); + console.log("currentCol: ", currentCol, "targetCol: ", targetCol); + + var rowDiff = Math.abs(targetRow - currentRow); + var colDiff = Math.abs(targetCol - currentCol); + + // The queen can move any number of squares vertically, horizontally, or diagonally. + if ((rowDiff === colDiff) || (currentRow === targetRow) || (currentCol === targetCol)) { + // Check for obstacles + if (this.isPathBlocked(currentRow, currentCol, targetRow, targetCol)) { + console.log("Invalid move: There is an obstacle in the path."); + return false; + } + return true; + } else { + console.log("Invalid move: Queen must move vertically, horizontally, or diagonally."); + return false; + } +}; + +// Helper method to check if there's any obstacle in the path of the Queen +Queen.prototype.isPathBlocked = function(currentRow, currentCol, targetRow, targetCol) { + var rowStep = (targetRow > currentRow) ? 1 : (targetRow < currentRow) ? -1 : 0;//1-->forward, -1-->backward, 0--> no movement + var colStep = (targetCol > currentCol) ? 1 : (targetCol < currentCol) ? -1 : 0; + + var row = currentRow + rowStep; + var col = currentCol + colStep; + + while (row !== targetRow || col !== targetCol) { + var position = { + row: row.toString(), + col: String.fromCharCode(65 + col) + }; + + // Check if a piece exists at this position + if (this.board.getPieceAt(position)) { + return true; // There is an obstacle + } + + row += rowStep; + col += colStep; + } -} \ No newline at end of file + return false; // No obstacles +}; \ No newline at end of file diff --git a/public/javascript/chess/pieces/rook.js b/public/javascript/chess/pieces/rook.js index 045c127..049e491 100644 --- a/public/javascript/chess/pieces/rook.js +++ b/public/javascript/chess/pieces/rook.js @@ -1,11 +1,71 @@ -var Rook = function(config){ - this.type = 'rook'; +var Rook = function (config) { + this.type = "rook"; this.constructor(config); }; - - - Rook.prototype = new Piece({}); -Rook.prototype.move = function(newPosition){ - -} \ No newline at end of file +Rook.prototype.kill = function (targetPiece) { + const targetPosition = targetPiece.position; + const targetElement = document.querySelector( + `[data-col="${targetPosition[0]}"] [data-row="${targetPosition[1]}"]` + ); + targetElement.innerHTML = ""; + Piece.prototype.kill.call(this, targetPiece); + console.log("Rook killed " + targetPiece.type); +}; +Rook.prototype.isValidMove = function (targetPosition) { + let currentCol = this.position.charAt(0); + let currentRow = parseInt(this.position.charAt(1)); + let targetCol = targetPosition.col; + let targetRow = parseInt(targetPosition.row); + let colDifference = Math.abs(targetCol.charCodeAt(0) - currentCol.charCodeAt(0)); + let rowDifference = Math.abs(targetRow - currentRow); + if (colDifference !== 0 && rowDifference !== 0) { + console.warn("Invalid move for rook: Rook must move in a straight line."); + return false; + } + if (!this.isPathCheck(currentCol, currentRow, targetCol, targetRow)) { + console.warn("Path is not clear for rook."); + return false; + } + return true; +}; +Rook.prototype.isPathCheck = function (currentCol, currentRow, targetCol, targetRow) { + let colStep = 0; + let rowStep = 0; + if (currentCol === targetCol) { + rowStep = targetRow > currentRow ? 1 : -1; + } else { + colStep = targetCol.charCodeAt(0) > currentCol.charCodeAt(0) ? 1 : -1; + } + let col = currentCol.charCodeAt(0) + colStep; + let row = currentRow + rowStep; + while ((String.fromCharCode(col) !== targetCol) || (row !== targetRow)) { + let checkPosition = { + col: String.fromCharCode(col), + row: row.toString() + }; + if (this.board.getPieceAt(checkPosition)) { + return false; + } + col += colStep; + row += rowStep; + } + return true; +}; +Rook.prototype.moveTo = function (targetPosition) { + if (this.board.currentTurn !== this.color) { + console.log("Invalid move: Not your turn"); + return; + } + if (this.isValidMove(targetPosition)) { + let targetPiece = this.board.getPieceAt(targetPosition); + if (targetPiece && targetPiece.color !== this.color) { + this.kill(targetPiece); + } + this.position = targetPosition.col + targetPosition.row; + this.render(); + console.log(`Rook moved to ${this.position}`); + } else { + console.log("Invalid move for rook"); + } +}; \ No newline at end of file