diff --git a/26.9-backgammon/README.md b/26.9-backgammon/README.md new file mode 100644 index 0000000..c77b332 --- /dev/null +++ b/26.9-backgammon/README.md @@ -0,0 +1,18 @@ +# Backgammon Game + +A modern, fully interactive backgammon game optimized for mobile and desktop browsers. + +## Features +- 3D animated board and dice +- Dynamic player guidance +- Customizable themes and player names +- Save and load game states with local storage +- Sound effects for in-game actions + +## How to Play +1. Clone or download the repository. +2. Open `index.html` in your browser. +3. Roll the dice, move the pieces, and enjoy the game! + +## Contributing +Feel free to fork the project and make pull requests with improvements! diff --git a/26.9-backgammon/bg1.js b/26.9-backgammon/bg1.js new file mode 100644 index 0000000..14416c6 --- /dev/null +++ b/26.9-backgammon/bg1.js @@ -0,0 +1,92 @@ +// bg1.js - Enhancing UI with animations and 3D effects + +document.addEventListener("DOMContentLoaded", () => { + // 3D Rotating Board Animation + const board = document.getElementById("backgammon-board"); + + function addBoardRotation() { + board.style.transition = "transform 1s ease-in-out"; + board.style.transformStyle = "preserve-3d"; + board.style.transform = "rotateX(15deg) rotateY(15deg)"; + } + + function resetBoardRotation() { + board.style.transform = "rotateX(0deg) rotateY(0deg)"; + } + + board.addEventListener("mouseenter", addBoardRotation); + board.addEventListener("mouseleave", resetBoardRotation); + + // Highlight active player's side + let currentPlayer = "yellow"; + const leftBar = document.getElementById("left-bar"); + const rightBar = document.getElementById("right-bar"); + + function highlightActivePlayer() { + if (currentPlayer === "yellow") { + leftBar.style.boxShadow = "0px 0px 20px 10px rgba(255, 204, 0, 0.8)"; + rightBar.style.boxShadow = "none"; + } else { + rightBar.style.boxShadow = "0px 0px 20px 10px rgba(255, 255, 255, 0.8)"; + leftBar.style.boxShadow = "none"; + } + } + + // Animate dice roll + const dice1 = document.getElementById("dice1"); + const dice2 = document.getElementById("dice2"); + + function animateDiceRoll(diceElement) { + diceElement.style.transition = "transform 0.5s ease"; + diceElement.style.transform = "rotateX(360deg)"; + } + + dice1.addEventListener("click", () => animateDiceRoll(dice1)); + dice2.addEventListener("click", () => animateDiceRoll(dice2)); + + // Pieces Animation - Adding drag & drop for a more interactive interface + const pieces = document.querySelectorAll(".piece"); + + pieces.forEach(piece => { + piece.style.transition = "transform 0.3s ease, box-shadow 0.3s ease"; + piece.addEventListener("mouseenter", () => { + piece.style.transform = "scale(1.1)"; + piece.style.boxShadow = "0px 5px 10px rgba(0, 0, 0, 0.5)"; + }); + + piece.addEventListener("mouseleave", () => { + piece.style.transform = "scale(1)"; + piece.style.boxShadow = "none"; + }); + }); + + // Roll button 3D bounce effect + const rollBtn = document.getElementById("roll-btn"); + + rollBtn.style.transition = "transform 0.5s ease"; + rollBtn.addEventListener("mousedown", () => { + rollBtn.style.transform = "scale(0.9)"; + }); + + rollBtn.addEventListener("mouseup", () => { + rollBtn.style.transform = "scale(1)"; + }); + + // Board background color change on piece moves (color-changing theme) + function changeBoardColor() { + const colors = ["#2f2f2f", "#3e3e3e", "#4d4d4d"]; + const randomColor = colors[Math.floor(Math.random() * colors.length)]; + board.style.backgroundColor = randomColor; + } + + board.addEventListener("click", changeBoardColor); + + // Function to toggle active player + function togglePlayer() { + currentPlayer = currentPlayer === "yellow" ? "white" : "yellow"; + highlightActivePlayer(); + } + + // Initial highlight + highlightActivePlayer(); +}); diff --git a/26.9-backgammon/bg2.js b/26.9-backgammon/bg2.js new file mode 100644 index 0000000..d13163c --- /dev/null +++ b/26.9-backgammon/bg2.js @@ -0,0 +1,154 @@ +// bg2.js - Enhancing gameplay mechanics and dynamic interactions + +document.addEventListener("DOMContentLoaded", () => { + const board = document.getElementById("board"); + let currentPlayer = "yellow"; + let diceRolls = []; + + // Dice Roll Functionality + function rollDice() { + const dice1 = Math.floor(Math.random() * 6) + 1; + const dice2 = Math.floor(Math.random() * 6) + 1; + diceRolls = [dice1, dice2]; + + document.getElementById("dice1").textContent = dice1; + document.getElementById("dice2").textContent = dice2; + + animateDiceRolls(); + togglePlayer(); + showPlayerTooltip(); + } + + // Animate dice after rolling + function animateDiceRolls() { + const diceElements = [document.getElementById("dice1"), document.getElementById("dice2")]; + + diceElements.forEach(dice => { + dice.style.transform = "rotateX(360deg) rotateY(360deg)"; + setTimeout(() => { + dice.style.transform = "rotateX(0deg) rotateY(0deg)"; + }, 500); + }); + } + + // Move pieces based on dice roll + function movePiece(piece, diceValue) { + const currentPosition = Array.from(board.children).indexOf(piece.parentElement); + let newPosition = currentPosition + (currentPlayer === "yellow" ? diceValue : -diceValue); + + if (newPosition < 0 || newPosition >= board.children.length) { + newPosition = currentPosition; // Invalid move, stay in place + } + + const targetSpot = board.children[newPosition]; + if (targetSpot) { + piece.style.transition = "transform 0.3s ease"; + targetSpot.appendChild(piece); + } + } + + // Add drag & drop functionality for pieces + let draggedPiece = null; + + board.addEventListener("dragstart", (e) => { + if (e.target.classList.contains("piece")) { + draggedPiece = e.target; + setTimeout(() => (e.target.style.opacity = "0.5"), 0); + } + }); + + board.addEventListener("dragend", (e) => { + e.target.style.opacity = "1"; + }); + + board.addEventListener("dragover", (e) => { + e.preventDefault(); + }); + + board.addEventListener("drop", (e) => { + if (draggedPiece && e.target.classList.contains("triangle")) { + movePiece(draggedPiece, diceRolls[0]); // Move based on the first dice roll + diceRolls.shift(); // Remove the used dice roll + } + }); + + // Display a tooltip guiding the player + function showPlayerTooltip() { + const tooltip = document.createElement("div"); + tooltip.id = "player-tooltip"; + tooltip.style.position = "absolute"; + tooltip.style.bottom = "20px"; + tooltip.style.left = "50%"; + tooltip.style.transform = "translateX(-50%)"; + tooltip.style.padding = "10px"; + tooltip.style.backgroundColor = currentPlayer === "yellow" ? "#ffcc00" : "#ffffff"; + tooltip.style.color = currentPlayer === "yellow" ? "#333" : "#000"; + tooltip.style.borderRadius = "5px"; + tooltip.style.boxShadow = "0 0 10px rgba(0,0,0,0.5)"; + tooltip.style.fontSize = "1.2rem"; + tooltip.textContent = `${currentPlayer === "yellow" ? 'Yellow' : 'White'}'s Turn! Roll the dice to continue.`; + + document.body.appendChild(tooltip); + + setTimeout(() => { + tooltip.remove(); + }, 3000); + } + + // Toggle active player + function togglePlayer() { + currentPlayer = currentPlayer === "yellow" ? "white" : "yellow"; + } + + // Show valid moves for the current player + function highlightValidMoves() { + const allTriangles = Array.from(board.children); + allTriangles.forEach(triangle => { + if (Math.random() < 0.2) { + triangle.style.backgroundColor = "rgba(0, 255, 0, 0.3)"; + setTimeout(() => { + triangle.style.backgroundColor = ""; + }, 1000); + } + }); + } + + // Tooltips for invalid moves + function showInvalidMoveMessage() { + const invalidMoveTooltip = document.createElement("div"); + invalidMoveTooltip.id = "invalid-tooltip"; + invalidMoveTooltip.style.position = "absolute"; + invalidMoveTooltip.style.top = "50%"; + invalidMoveTooltip.style.left = "50%"; + invalidMoveTooltip.style.transform = "translate(-50%, -50%)"; + invalidMoveTooltip.style.padding = "15px"; + invalidMoveTooltip.style.backgroundColor = "#ff4444"; + invalidMoveTooltip.style.color = "#fff"; + invalidMoveTooltip.style.borderRadius = "5px"; + invalidMoveTooltip.style.boxShadow = "0 0 15px rgba(255,0,0,0.5)"; + invalidMoveTooltip.textContent = "Invalid Move! Try Again."; + + document.body.appendChild(invalidMoveTooltip); + + setTimeout(() => { + invalidMoveTooltip.remove(); + }, 2000); + } + + // Handle piece movements and check for validity + function handlePieceMove(diceRoll) { + const valid = Math.random() < 0.5; // Simulate move validation (to be implemented) + + if (valid) { + movePiece(draggedPiece, diceRoll); + } else { + showInvalidMoveMessage(); + } + } + + // Add event listener for dice roll button + document.getElementById("roll-btn").addEventListener("click", rollDice); + + // Initial player guidance + showPlayerTooltip(); +}); diff --git a/26.9-backgammon/bg3.js b/26.9-backgammon/bg3.js new file mode 100644 index 0000000..4d58603 --- /dev/null +++ b/26.9-backgammon/bg3.js @@ -0,0 +1,166 @@ +// bg3.js - Advanced gameplay mechanics and rule refinement + +document.addEventListener("DOMContentLoaded", () => { + const board = document.getElementById("board"); + const rollBtn = document.getElementById("roll-btn"); + let currentPlayer = "yellow"; + let diceRolls = []; + let activePiece = null; + const playerPieces = { yellow: [], white: [] }; + const maxBoardPositions = 24; + + // Dice Roll Functionality + function rollDice() { + const dice1 = Math.floor(Math.random() * 6) + 1; + const dice2 = Math.floor(Math.random() * 6) + 1; + diceRolls = [dice1, dice2]; + updateDiceDisplay(dice1, dice2); + enablePieceSelection(); + } + + function updateDiceDisplay(dice1, dice2) { + document.getElementById("dice1").textContent = dice1; + document.getElementById("dice2").textContent = dice2; + animateDiceRolls(); + } + + // Animate the dice rolls visually + function animateDiceRolls() { + const diceElements = [document.getElementById("dice1"), document.getElementById("dice2")]; + diceElements.forEach(dice => { + dice.style.transform = "rotateX(360deg) rotateY(360deg)"; + setTimeout(() => { + dice.style.transform = "rotateX(0deg) rotateY(0deg)"; + }, 500); + }); + } + + // Piece Selection - allowing the player to select one of their pieces + function enablePieceSelection() { + const pieces = document.querySelectorAll(`.${currentPlayer}-piece`); + pieces.forEach(piece => { + piece.style.cursor = "pointer"; + piece.addEventListener("click", () => { + if (!activePiece) { + activePiece = piece; + highlightPossibleMoves(piece); + } + }); + }); + } + + // Highlight possible moves based on dice roll + function highlightPossibleMoves(piece) { + const currentPosition = getCurrentPosition(piece); + diceRolls.forEach(dice => { + const newPosition = calculateNewPosition(currentPosition, dice); + if (newPosition >= 0 && newPosition < maxBoardPositions) { + const target = board.children[newPosition]; + highlightTargetPosition(target); + } + }); + } + + function getCurrentPosition(piece) { + return Array.from(board.children).indexOf(piece.parentElement); + } + + function calculateNewPosition(currentPosition, diceRoll) { + return currentPlayer === "yellow" + ? currentPosition + diceRoll + : currentPosition - diceRoll; + } + + function highlightTargetPosition(target) { + target.style.border = "2px solid #00ff00"; + target.addEventListener("click", () => movePieceToTarget(target)); + } + + function movePieceToTarget(target) { + if (activePiece && target) { + target.appendChild(activePiece); + activePiece.style.transition = "transform 0.5s ease"; + activePiece.style.transform = "scale(1.1)"; + + setTimeout(() => { + activePiece.style.transform = "scale(1)"; + resetHighlights(); + activePiece = null; + diceRolls.shift(); // Use up the dice + if (diceRolls.length === 0) endTurn(); + }, 300); + } + } + + // Reset highlights after a move + function resetHighlights() { + const triangles = document.querySelectorAll(".triangle"); + triangles.forEach(triangle => { + triangle.style.border = "none"; + }); + } + + // End the player's turn and switch to the next player + function endTurn() { + currentPlayer = currentPlayer === "yellow" ? "white" : "yellow"; + alert(`${currentPlayer === "yellow" ? 'Yellow' : 'White'}'s Turn!`); + showPlayerTooltip(); + } + + // Show a tooltip at the beginning of each turn + function showPlayerTooltip() { + const tooltip = document.createElement("div"); + tooltip.id = "player-tooltip"; + tooltip.style.position = "absolute"; + tooltip.style.bottom = "20px"; + tooltip.style.left = "50%"; + tooltip.style.transform = "translateX(-50%)"; + tooltip.style.padding = "10px"; + tooltip.style.backgroundColor = currentPlayer === "yellow" ? "#ffcc00" : "#ffffff"; + tooltip.style.color = currentPlayer === "yellow" ? "#333" : "#000"; + tooltip.style.borderRadius = "5px"; + tooltip.style.boxShadow = "0 0 10px rgba(0,0,0,0.5)"; + tooltip.style.fontSize = "1.2rem"; + tooltip.textContent = `${currentPlayer === "yellow" ? 'Yellow' : 'White'}'s Turn! Roll the dice to continue.`; + + document.body.appendChild(tooltip); + + setTimeout(() => { + tooltip.remove(); + }, 3000); + } + + // Rule Validation - Checking if moves are legal + function isValidMove(piece, targetPosition) { + const currentPosition = getCurrentPosition(piece); + if (currentPlayer === "yellow" && currentPosition >= targetPosition) return false; + if (currentPlayer === "white" && currentPosition <= targetPosition) return false; + // Add more logic for valid moves here... + return true; + } + + // Detect when a player wins + function checkWinCondition() { + const yellowPieces = document.querySelectorAll(".yellow-piece"); + const whitePieces = document.querySelectorAll(".white-piece"); + + if (yellowPieces.length === 0) { + alert("Yellow wins!"); + resetGame(); + } else if (whitePieces.length === 0) { + alert("White wins!"); + resetGame(); + } + } + + // Reset the game board after a win + function resetGame() { + location.reload(); // Reload the page to reset the game + } + + // Add event listener for dice roll button + rollBtn.addEventListener("click", rollDice); + + // Initialize the tooltip for the first player + showPlayerTooltip(); +}); diff --git a/26.9-backgammon/gameRules.js b/26.9-backgammon/gameRules.js new file mode 100644 index 0000000..9fefafc --- /dev/null +++ b/26.9-backgammon/gameRules.js @@ -0,0 +1,46 @@ +// gameRules.js - Enforcing the rules of Backgammon + +const gameRules = { + // Function to validate if the move is allowed + isMoveValid: function (piece, startPos, diceRoll) { + const targetPos = currentPlayer === "yellow" ? startPos + diceRoll : startPos - diceRoll; + + // Check if the move is within bounds + if (targetPos < 0 || targetPos >= board.children.length) return false; + + // Check if the target position is valid (implement capturing, blocking, etc.) + const targetSpot = board.children[targetPos]; + return !this.isBlocked(targetSpot); + }, + + // Check if a target position is blocked by two or more opponent's pieces + isBlocked: function (spot) { + const opponentColor = currentPlayer === "yellow" ? "white" : "yellow"; + const piecesInSpot = spot.querySelectorAll(`.${opponentColor}-piece`); + return piecesInSpot.length >= 2; + }, + + // Function to enforce capturing of a single opponent's piece + capturePiece: function (targetSpot) { + const opponentColor = currentPlayer === "yellow" ? "white" : "yellow"; + const opponentPiece = targetSpot.querySelector(`.${opponentColor}-piece`); + if (opponentPiece) { + // Move the captured piece to the bar + document.getElementById(`${opponentColor}-bar`).appendChild(opponentPiece); + } + }, + + // Function to bear off pieces once all of a player's pieces are in their home board + canBearOff: function (piece) { + const homeStart = currentPlayer === "yellow" ? 18 : 0; + const homeEnd = currentPlayer === "yellow" ? 23 : 5; + + // Check if all pieces are in the home quadrant + const pieces = document.querySelectorAll(`.${currentPlayer}-piece`); + for (const p of pieces) { + const pos = Array.from(board.children).indexOf(p.parentElement); + if (pos < homeStart || pos > homeEnd) return false; + } + return true; + } +}; diff --git a/26.9-backgammon/index.html b/26.9-backgammon/index.html new file mode 100644 index 0000000..77d6cf6 --- /dev/null +++ b/26.9-backgammon/index.html @@ -0,0 +1,211 @@ + + + + + + Backgammon Game + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+
1
+
6
+
+
+ + + + + diff --git a/26.9-backgammon/index.js b/26.9-backgammon/index.js new file mode 100644 index 0000000..26a052f --- /dev/null +++ b/26.9-backgammon/index.js @@ -0,0 +1,8 @@ +// index.js - Main script loader +import './bg1.js'; +import './bg2.js'; +import './bg3.js'; +import './gameRules.js'; +import './sounds.js'; +import './settings.js'; +import './localStorage.js'; diff --git a/26.9-backgammon/localStorage.js b/26.9-backgammon/localStorage.js new file mode 100644 index 0000000..adbf118 --- /dev/null +++ b/26.9-backgammon/localStorage.js @@ -0,0 +1,38 @@ +// localStorage.js - Save and load game state using browser's localStorage + +const storage = { + saveGameState: function () { + const gameState = { + pieces: Array.from(document.querySelectorAll('.piece')).map(piece => { + const position = Array.from(board.children).indexOf(piece.parentElement); + return { color: piece.classList.contains('white-piece') ? 'white' : 'yellow', position }; + }), + currentPlayer: currentPlayer, + diceRolls: diceRolls + }; + localStorage.setItem('backgammonGameState', JSON.stringify(gameState)); + alert('Game state saved!'); + }, + + loadGameState: function () { + const savedState = localStorage.getItem('backgammonGameState'); + if (savedState) { + const { pieces, currentPlayer: savedPlayer, diceRolls: savedDiceRolls } = JSON.parse(savedState); + this.restorePieces(pieces); + currentPlayer = savedPlayer; + diceRolls = savedDiceRolls; + alert('Game state loaded!'); + } else { + alert('No saved game state found.'); + } + }, + + restorePieces: function (pieces) { + pieces.forEach(pieceData => { + const piece = document.createElement('div'); + piece.classList.add('piece'); + piece.classList.add(`${pieceData.color}-piece`); + board.children[pieceData.position].appendChild(piece); + }); + } +}; diff --git a/26.9-backgammon/settings.js b/26.9-backgammon/settings.js new file mode 100644 index 0000000..3649f69 --- /dev/null +++ b/26.9-backgammon/settings.js @@ -0,0 +1,18 @@ +// settings.js - Game Settings and Preferences + +const gameSettings = { + theme: "classic", + soundEnabled: true, + playerNames: { yellow: "Player 1", white: "Player 2" }, + + toggleSound: function () { + this.soundEnabled = !this.soundEnabled; + alert(`Sound ${this.soundEnabled ? 'enabled' : 'disabled'}`); + }, + + setPlayerNames: function (yellowName, whiteName) { + this.playerNames.yellow = yellowName; + this.playerNames.white = whiteName; + alert(`Player names updated: ${yellowName} (Yellow), ${whiteName} (White)`); + } +}; diff --git a/26.9-backgammon/sounds.js b/26.9-backgammon/sounds.js new file mode 100644 index 0000000..da035cd --- /dev/null +++ b/26.9-backgammon/sounds.js @@ -0,0 +1,25 @@ +// sounds.js - Adding sound effects to the game + +const sounds = { + diceRoll: new Audio('assets/sounds/dice-roll.mp3'), + pieceMove: new Audio('assets/sounds/piece-move.mp3'), + invalidMove: new Audio('assets/sounds/invalid-move.mp3'), + win: new Audio('assets/sounds/win.mp3'), + + playSound: function (sound) { + switch (sound) { + case 'dice': + this.diceRoll.play(); + break; + case 'move': + this.pieceMove.play(); + break; + case 'invalid': + this.invalidMove.play(); + break; + case 'win': + this.win.play(); + break; + } + } +}; diff --git a/26.9-backgammon/styles.css b/26.9-backgammon/styles.css new file mode 100644 index 0000000..2ddf465 --- /dev/null +++ b/26.9-backgammon/styles.css @@ -0,0 +1,138 @@ +/* styles.css - Advanced Styles for the Backgammon Game */ + +/* Reset basic styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: Arial, sans-serif; + background-color: #f3f3f3; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} + +#backgammon-board { + width: 100vw; + max-width: 800px; + height: 100vw; + max-height: 800px; + background-color: #2f2f2f; + border-radius: 15px; + display: grid; + grid-template-columns: repeat(2, 1fr); + position: relative; + transition: transform 1s ease-in-out; + transform-style: preserve-3d; +} + +#left-bar, #right-bar { + position: absolute; + top: 0; + bottom: 0; + width: 50%; + background-color: #333; +} + +#right-bar { + right: 0; +} + +#board { + position: relative; + display: grid; + grid-template-columns: repeat(12, 1fr); + grid-template-rows: 1fr 1fr; +} + +.triangle { + position: relative; + clip-path: polygon(50% 0%, 100% 100%, 0% 100%); + background-color: #fff; + margin: 5px; + transition: background-color 0.3s; +} + +.triangle:nth-child(even) { + background-color: #ddd; +} + +.piece { + width: 90%; + height: 90%; + border-radius: 50%; + background-color: #ffcc00; + display: flex; + justify-content: center; + align-items: center; + color: #333; + font-weight: bold; + transition: transform 0.3s ease, box-shadow 0.3s ease; + cursor: pointer; +} + +.white-piece { + background-color: #fff; +} + +#dice-container { + position: absolute; + bottom: 10px; + left: 50%; + transform: translateX(-50%); + display: flex; + gap: 15px; +} + +.dice { + width: 60px; + height: 60px; + background-color: white; + border-radius: 8px; + display: flex; + justify-content: center; + align-items: center; + font-size: 2rem; + transition: transform 0.5s ease; +} + +#roll-btn { + position: absolute; + bottom: 90px; + left: 50%; + transform: translateX(-50%); + padding: 10px 20px; + background-color: #007bff; + color: white; + font-size: 1.2rem; + border-radius: 5px; + border: none; + cursor: pointer; + transition: transform 0.5s ease, background-color 0.3s; +} + +#roll-btn:hover { + background-color: #0056b3; +} + +@media (max-width: 768px) { + #backgammon-board { + width: 95vw; + height: 95vw; + } + + .dice { + width: 40px; + height: 40px; + font-size: 1.5rem; + } + + #roll-btn { + padding: 8px 16px; + font-size: 1rem; + } +}