| |
| |
| |
|
|
| const canvas = document.getElementById('mensch-board'); |
| const ctx = canvas.getContext('2d'); |
|
|
| |
| const PLAYERS = { |
| RED: { name: 'قرمز', color: '#e74c3c', homeColor: '#ff6b6b', lightColor: '#ffcccc' }, |
| BLUE: { name: 'آبی', color: '#2980b9', homeColor: '#5dade2', lightColor: '#cce5ff' }, |
| GREEN: { name: 'سبز', color: '#27ae60', homeColor: '#58d68d', lightColor: '#ccffcc' }, |
| YELLOW: { name: 'زرد', color: '#f39c12', homeColor: '#f7dc6f', lightColor: '#fff9cc' } |
| }; |
|
|
| const PLAYER_ORDER = ['RED', 'BLUE', 'GREEN', 'YELLOW']; |
| const TOTAL_PATH = 40; |
| const HOME_STRETCH = 4; |
|
|
| |
| const PLAYER_CONFIG = { |
| RED: { startPath: 0, homeEntry: 39, startCell: { x: 6, y: 6 }, direction: 1 }, |
| BLUE: { startPath: 10, homeEntry: 9, startCell: { x: 6, y: 0 }, direction: 1 }, |
| GREEN: { startPath: 20, homeEntry: 19, startCell: { x: 0, y: 0 }, direction: 1 }, |
| YELLOW: { startPath: 30, homeEntry: 29, startCell: { x: 0, y: 6 }, direction: 1 } |
| }; |
|
|
| |
| const gameState = { |
| players: { |
| RED: { pieces: [-1, -1, -1, -1], finished: 0 }, |
| BLUE: { pieces: [-1, -1, -1, -1], finished: 0 }, |
| GREEN: { pieces: [-1, -1, -1, -1], finished: 0 }, |
| YELLOW: { pieces: [-1, -1, -1, -1], finished: 0 } |
| }, |
| currentPlayerIndex: 0, |
| diceValue: null, |
| gamePhase: 'rolling', |
| selectedPiece: null, |
| sixCount: 0, |
| winner: null, |
| validMoves: [] |
| }; |
|
|
| |
| |
| const mainPath = []; |
|
|
| |
| function buildMainPath() { |
| |
| |
| for (let col = 10; col >= 0; col--) mainPath.push({ x: col, y: 0 }); |
| |
| for (let row = 1; row <= 10; row++) mainPath.push({ x: 0, y: row }); |
| |
| for (let col = 1; col <= 10; col++) mainPath.push({ x: col, y: 10 }); |
| |
| for (let row = 9; row >= 1; row--) mainPath.push({ x: 10, y: row }); |
| |
| |
| } |
|
|
| |
| const homeStretches = {}; |
|
|
| function buildHomeStretches() { |
| |
| homeStretches.RED = [ |
| { x: 9, y: 5 }, { x: 8, y: 5 }, { x: 7, y: 5 }, { x: 6, y: 5 } |
| ]; |
| |
| homeStretches.BLUE = [ |
| { x: 5, y: 1 }, { x: 5, y: 2 }, { x: 5, y: 3 }, { x: 5, y: 4 } |
| ]; |
| |
| homeStretches.GREEN = [ |
| { x: 1, y: 5 }, { x: 2, y: 5 }, { x: 3, y: 5 }, { x: 4, y: 5 } |
| ]; |
| |
| homeStretches.YELLOW = [ |
| { x: 5, y: 9 }, { x: 5, y: 8 }, { x: 5, y: 7 }, { x: 5, y: 6 } |
| ]; |
| } |
|
|
| |
| const safeCells = [0, 8, 13, 21, 26, 34, 39]; |
|
|
| |
| function initGame() { |
| buildMainPath(); |
| buildHomeStretches(); |
| |
| gameState.players = { |
| RED: { pieces: [-1, -1, -1, -1], finished: 0 }, |
| BLUE: { pieces: [-1, -1, -1, -1], finished: 0 }, |
| GREEN: { pieces: [-1, -1, -1, -1], finished: 0 }, |
| YELLOW: { pieces: [-1, -1, -1, -1], finished: 0 } |
| }; |
| gameState.currentPlayerIndex = 0; |
| gameState.diceValue = null; |
| gameState.gamePhase = 'rolling'; |
| gameState.selectedPiece = null; |
| gameState.sixCount = 0; |
| gameState.winner = null; |
| gameState.validMoves = []; |
| |
| updateUI(); |
| updateStatusMessage(`نوبت بازیکن ${PLAYERS[getCurrentPlayer()].name} - تاس بریزید`); |
| document.getElementById('roll-btn').disabled = false; |
| document.getElementById('extra-turn-indicator').classList.add('hidden'); |
| document.getElementById('moves-remaining').classList.add('hidden'); |
| hideWinModal(); |
| drawBoard(); |
| } |
|
|
| function getCurrentPlayer() { |
| return PLAYER_ORDER[gameState.currentPlayerIndex]; |
| } |
|
|
| |
| function rollDice() { |
| if (gameState.gamePhase !== 'rolling') return; |
| if (gameState.winner) return; |
| |
| const value = Math.floor(Math.random() * 6) + 1; |
| gameState.diceValue = value; |
| |
| |
| animateDice(value); |
| |
| const player = getCurrentPlayer(); |
| |
| |
| if (value === 6) { |
| gameState.sixCount++; |
| if (gameState.sixCount === 3) { |
| |
| penaltyThreeSixes(player); |
| gameState.sixCount = 0; |
| switchTurn(); |
| return; |
| } |
| } else { |
| gameState.sixCount = 0; |
| } |
| |
| |
| gameState.validMoves = findValidMoves(player, value); |
| gameState.selectedPiece = null; |
| |
| if (gameState.validMoves.length === 0) { |
| updateStatusMessage(`بازیکن ${PLAYERS[player].name}: هیچ حرکت معتبری نیست - نوبت عوض شد`); |
| if (value !== 6) { |
| setTimeout(() => switchTurn(), 1200); |
| } else { |
| |
| updateStatusMessage(`تاس ۶ ولی حرکتی نیست! دوباره تاس بریزید`); |
| gameState.gamePhase = 'rolling'; |
| } |
| document.getElementById('roll-btn').disabled = true; |
| drawBoard(); |
| return; |
| } |
| |
| gameState.gamePhase = 'moving'; |
| document.getElementById('roll-btn').disabled = true; |
| |
| if (value === 6) { |
| document.getElementById('extra-turn-indicator').classList.remove('hidden'); |
| } |
| |
| updateStatusMessage(`بازیکن ${PLAYERS[player].name}: مهره را انتخاب کنید (تاس: ${value})`); |
| drawBoard(); |
| } |
|
|
| function findValidMoves(player, dice) { |
| const moves = []; |
| const pieces = gameState.players[player].pieces; |
| |
| pieces.forEach((pos, idx) => { |
| |
| if (pos === -1 && dice === 6) { |
| moves.push({ piece: idx, from: 'start', to: getStartPath(player) }); |
| } |
| |
| else if (pos >= 0 && pos < TOTAL_PATH) { |
| let newPos = (pos + dice) % TOTAL_PATH; |
| |
| const homeEntry = PLAYER_CONFIG[player].homeEntry; |
| |
| |
| if (pos <= homeEntry && (pos + dice) > homeEntry + 1) { |
| |
| const homeSteps = (pos + dice) - (homeEntry + 1); |
| if (homeSteps >= 0 && homeSteps < HOME_STRETCH) { |
| moves.push({ piece: idx, from: pos, to: 'home-' + homeSteps, isHome: true }); |
| } |
| } |
| |
| if (canMoveTo(player, newPos)) { |
| moves.push({ piece: idx, from: pos, to: newPos }); |
| } |
| } |
| |
| else if (pos >= 100) { |
| const homeStep = pos - 100; |
| const newHomeStep = homeStep + dice; |
| if (newHomeStep < HOME_STRETCH) { |
| moves.push({ piece: idx, from: pos, to: 100 + newHomeStep, isHome: true }); |
| } else if (newHomeStep === HOME_STRETCH) { |
| moves.push({ piece: idx, from: pos, to: 'finish', isWin: true }); |
| } |
| } |
| }); |
| |
| |
| moves.sort((a, b) => { |
| if (a.isWin) return -1; |
| if (b.isWin) return 1; |
| if (a.isHome && !b.isHome) return -1; |
| if (!a.isHome && b.isHome) return 1; |
| if (a.from === 'start') return 1; |
| if (b.from === 'start') return -1; |
| return 0; |
| }); |
| |
| return moves; |
| } |
|
|
| function canMoveTo(player, pathIndex) { |
| |
| for (const p of PLAYER_ORDER) { |
| const pieces = gameState.players[p].pieces; |
| for (const pos of pieces) { |
| if (pos === pathIndex) { |
| if (p === player) return false; |
| |
| if (safeCells.includes(pathIndex)) return false; |
| return true; |
| } |
| } |
| } |
| return true; |
| } |
|
|
| function getStartPath(player) { |
| return PLAYER_CONFIG[player].startPath; |
| } |
|
|
| function penaltyThreeSixes(player) { |
| |
| const pieces = gameState.players[player].pieces; |
| let maxPos = -1; |
| let maxIdx = -1; |
| |
| pieces.forEach((pos, idx) => { |
| if (pos > maxPos && pos < 100) { |
| maxPos = pos; |
| maxIdx = idx; |
| } |
| }); |
| |
| if (maxIdx >= 0) { |
| pieces[maxIdx] = -1; |
| updateStatusMessage(`⚠️ بازیکن ${PLAYERS[player].name}: ۳ تا تاس ۶! مهره به خانه شروع برگشت!`); |
| } |
| } |
|
|
| |
| function executeMove(move) { |
| const player = getCurrentPlayer(); |
| const pieces = gameState.players[player].pieces; |
| |
| if (move.to === 'finish') { |
| pieces[move.piece] = 'finished'; |
| gameState.players[player].finished++; |
| } else if (typeof move.to === 'string' && move.to.startsWith('home-')) { |
| const step = parseInt(move.to.split('-')[1]); |
| pieces[move.piece] = 100 + step; |
| } else { |
| |
| for (const p of PLAYER_ORDER) { |
| if (p !== player) { |
| const opPieces = gameState.players[p].pieces; |
| opPieces.forEach((pos, idx) => { |
| if (pos === move.to) { |
| opPieces[idx] = -1; |
| } |
| }); |
| } |
| } |
| pieces[move.piece] = move.to; |
| } |
| |
| |
| if (gameState.players[player].finished === 4) { |
| endGame(player); |
| return; |
| } |
| |
| |
| if (gameState.diceValue === 6) { |
| gameState.gamePhase = 'rolling'; |
| gameState.validMoves = []; |
| gameState.selectedPiece = null; |
| gameState.diceValue = null; |
| document.getElementById('roll-btn').disabled = false; |
| document.getElementById('extra-turn-indicator').classList.add('hidden'); |
| updateStatusMessage(`🎯 تاس ۶! بازیکن ${PLAYERS[player].name} دوباره تاس بریز`); |
| } else { |
| switchTurn(); |
| } |
| |
| drawBoard(); |
| } |
|
|
| function switchTurn() { |
| gameState.currentPlayerIndex = (gameState.currentPlayerIndex + 1) % PLAYER_ORDER.length; |
| gameState.diceValue = null; |
| gameState.gamePhase = 'rolling'; |
| gameState.selectedPiece = null; |
| gameState.validMoves = []; |
| gameState.sixCount = 0; |
| |
| document.getElementById('roll-btn').disabled = false; |
| document.getElementById('extra-turn-indicator').classList.add('hidden'); |
| document.getElementById('moves-remaining').classList.add('hidden'); |
| |
| updateUI(); |
| updateStatusMessage(`نوبت بازیکن ${PLAYERS[getCurrentPlayer()].name} - تاس بریزید`); |
| drawBoard(); |
| } |
|
|
| function endGame(player) { |
| gameState.winner = player; |
| gameState.gamePhase = 'gameOver'; |
| document.getElementById('roll-btn').disabled = true; |
| updateStatusMessage(`🎉 بازیکن ${PLAYERS[player].name} برنده شد!`); |
| showWinModal(player); |
| drawBoard(); |
| } |
|
|
| |
| function animateDice(value) { |
| const diceEl = document.getElementById('dice-display'); |
| diceEl.classList.add('dice-rolling'); |
| |
| const interval = setInterval(() => { |
| const r = Math.floor(Math.random() * 6) + 1; |
| renderDiceFace(r); |
| }, 80); |
| |
| setTimeout(() => { |
| clearInterval(interval); |
| diceEl.classList.remove('dice-rolling'); |
| renderDiceFace(value); |
| }, 500); |
| } |
|
|
| function renderDiceFace(value) { |
| const container = document.getElementById('dice-dots'); |
| container.innerHTML = ''; |
| |
| const dotPositions = { |
| 1: ['center'], |
| 2: ['top-right', 'bottom-left'], |
| 3: ['top-right', 'center', 'bottom-left'], |
| 4: ['top-left', 'top-right', 'bottom-left', 'bottom-right'], |
| 5: ['top-left', 'top-right', 'center', 'bottom-left', 'bottom-right'], |
| 6: ['top-left', 'top-right', 'mid-left', 'mid-right', 'bottom-left', 'bottom-right'] |
| }; |
| |
| const positions = dotPositions[value] || []; |
| positions.forEach(pos => { |
| const dot = document.createElement('div'); |
| dot.className = `dot ${pos}`; |
| container.appendChild(dot); |
| }); |
| } |
|
|
| |
| function drawBoard() { |
| const w = canvas.width; |
| const h = canvas.height; |
| const cellSize = w / 11; |
| |
| |
| ctx.fillStyle = '#f5e6ca'; |
| ctx.fillRect(0, 0, w, h); |
| |
| |
| ctx.strokeStyle = '#d4c5a0'; |
| ctx.lineWidth = 1; |
| for (let i = 0; i <= 11; i++) { |
| ctx.beginPath(); |
| ctx.moveTo(i * cellSize, 0); |
| ctx.lineTo(i * cellSize, h); |
| ctx.stroke(); |
| ctx.beginPath(); |
| ctx.moveTo(0, i * cellSize); |
| ctx.lineTo(w, i * cellSize); |
| ctx.stroke(); |
| } |
| |
| |
| mainPath.forEach((pos, idx) => { |
| const x = pos.x * cellSize; |
| const y = pos.y * cellSize; |
| |
| |
| if (safeCells.includes(idx)) { |
| ctx.fillStyle = '#fff3cd'; |
| } else { |
| ctx.fillStyle = '#e8dcc8'; |
| } |
| ctx.fillRect(x + 2, y + 2, cellSize - 4, cellSize - 4); |
| |
| |
| ctx.strokeStyle = '#c4b896'; |
| ctx.lineWidth = 1; |
| ctx.strokeRect(x + 2, y + 2, cellSize - 4, cellSize - 4); |
| |
| |
| if (safeCells.includes(idx)) { |
| ctx.fillStyle = '#ffc107'; |
| ctx.font = `${cellSize * 0.5}px Vazirmatn`; |
| ctx.textAlign = 'center'; |
| ctx.textBaseline = 'middle'; |
| ctx.fillText('⭐', x + cellSize / 2, y + cellSize / 2); |
| } |
| }); |
| |
| |
| for (const [player, cells] of Object.entries(homeStretches)) { |
| cells.forEach((pos, idx) => { |
| const x = pos.x * cellSize; |
| const y = pos.y * cellSize; |
| ctx.fillStyle = PLAYERS[player].lightColor; |
| ctx.fillRect(x + 2, y + 2, cellSize - 4, cellSize - 4); |
| ctx.strokeStyle = PLAYERS[player].color; |
| ctx.lineWidth = 2; |
| ctx.strokeRect(x + 2, y + 2, cellSize - 4, cellSize - 4); |
| }); |
| } |
| |
| |
| const startHouses = { |
| RED: { x: 7, y: 7, w: 4, h: 4 }, |
| BLUE: { x: 7, y: 0, w: 4, h: 4 }, |
| GREEN: { x: 0, y: 0, w: 4, h: 4 }, |
| YELLOW: { x: 0, y: 7, w: 4, h: 4 } |
| }; |
| |
| for (const [player, rect] of Object.entries(startHouses)) { |
| const x = rect.x * cellSize; |
| const y = rect.y * cellSize; |
| const rw = rect.w * cellSize; |
| const rh = rect.h * cellSize; |
| |
| ctx.fillStyle = PLAYERS[player].lightColor; |
| ctx.fillRect(x + 4, y + 4, rw - 8, rh - 8); |
| ctx.strokeStyle = PLAYERS[player].color; |
| ctx.lineWidth = 3; |
| ctx.strokeRect(x + 4, y + 4, rw - 8, rh - 8); |
| } |
| |
| |
| const centerX = 4 * cellSize; |
| const centerY = 4 * cellSize; |
| ctx.fillStyle = '#e8dcc8'; |
| ctx.fillRect(centerX + 4, centerY + 4, 3 * cellSize - 8, 3 * cellSize - 8); |
| ctx.strokeStyle = '#c4b896'; |
| ctx.lineWidth = 2; |
| ctx.strokeRect(centerX + 4, centerY + 4, 3 * cellSize - 8, 3 * cellSize - 8); |
| |
| |
| ctx.fillStyle = '#8b7355'; |
| ctx.font = `bold ${cellSize * 0.5}px Vazirmatn`; |
| ctx.textAlign = 'center'; |
| ctx.textBaseline = 'middle'; |
| ctx.fillText('🏠', centerX + 1.5 * cellSize, centerY + 1.5 * cellSize); |
| |
| |
| for (const [player, data] of Object.entries(gameState.players)) { |
| const config = PLAYER_CONFIG[player]; |
| |
| data.pieces.forEach((pos, idx) => { |
| if (pos === 'finished') return; |
| |
| let px, py; |
| |
| if (pos === -1) { |
| |
| const startHouse = startHouses[player]; |
| const offsetX = (idx % 2) * cellSize * 0.5; |
| const offsetY = Math.floor(idx / 2) * cellSize * 0.5; |
| px = startHouse.x * cellSize + cellSize * 0.7 + offsetX; |
| py = startHouse.y * cellSize + cellSize * 0.7 + offsetY; |
| } else if (pos >= 100) { |
| |
| const step = pos - 100; |
| const homeCell = homeStretches[player][step]; |
| px = homeCell.x * cellSize + cellSize / 2; |
| py = homeCell.y * cellSize + cellSize / 2; |
| } else { |
| |
| const pathCell = mainPath[pos]; |
| px = pathCell.x * cellSize + cellSize / 2; |
| py = pathCell.y * cellSize + cellSize / 2; |
| |
| |
| let sameCellCount = 0; |
| for (const p of PLAYER_ORDER) { |
| for (const pp of gameState.players[p].pieces) { |
| if (pp === pos) sameCellCount++; |
| } |
| } |
| if (sameCellCount > 1) { |
| const offset = (idx - sameCellCount / 2) * (cellSize * 0.18); |
| px += offset; |
| } |
| } |
| |
| |
| ctx.beginPath(); |
| ctx.arc(px, py, cellSize * 0.3, 0, Math.PI * 2); |
| ctx.fillStyle = PLAYERS[player].color; |
| ctx.fill(); |
| ctx.strokeStyle = '#fff'; |
| ctx.lineWidth = 2; |
| ctx.stroke(); |
| ctx.fillStyle = '#fff'; |
| ctx.font = `bold ${cellSize * 0.25}px Vazirmatn`; |
| ctx.fillText(idx + 1, px, py); |
| }); |
| } |
| |
| |
| if (gameState.gamePhase === 'moving' && gameState.selectedPiece !== null) { |
| |
| ctx.strokeStyle = '#ffd700'; |
| ctx.lineWidth = 3; |
| |
| } else if (gameState.gamePhase === 'moving') { |
| |
| const highlightedPieces = new Set(); |
| gameState.validMoves.forEach(m => highlightedPieces.add(m.piece)); |
| |
| const player = getCurrentPlayer(); |
| const pieces = gameState.players[player].pieces; |
| |
| highlightedPieces.forEach(pieceIdx => { |
| const pos = pieces[pieceIdx]; |
| if (pos === -1) { |
| const startHouse = startHouses[player]; |
| const px = startHouse.x * cellSize + cellSize * 0.7 + (pieceIdx % 2) * cellSize * 0.5; |
| const py = startHouse.y * cellSize + cellSize * 0.7 + Math.floor(pieceIdx / 2) * cellSize * 0.5; |
| ctx.strokeStyle = '#ffd700'; |
| ctx.lineWidth = 4; |
| ctx.beginPath(); |
| ctx.arc(px, py, cellSize * 0.35, 0, Math.PI * 2); |
| ctx.stroke(); |
| } else if (pos >= 0 && pos < TOTAL_PATH) { |
| const pathCell = mainPath[pos]; |
| const px = pathCell.x * cellSize + cellSize / 2; |
| const py = pathCell.y * cellSize + cellSize / 2; |
| ctx.strokeStyle = '#ffd700'; |
| ctx.lineWidth = 4; |
| ctx.beginPath(); |
| ctx.arc(px, py, cellSize * 0.35, 0, Math.PI * 2); |
| ctx.stroke(); |
| } else if (pos >= 100) { |
| const step = pos - 100; |
| const homeCell = homeStretches[player][step]; |
| const px = homeCell.x * cellSize + cellSize / 2; |
| const py = homeCell.y * cellSize + cellSize / 2; |
| ctx.strokeStyle = '#ffd700'; |
| ctx.lineWidth = 4; |
| ctx.beginPath(); |
| ctx.arc(px, py, cellSize * 0.35, 0, Math.PI * 2); |
| ctx.stroke(); |
| } |
| }); |
| } |
| } |
|
|
| |
| canvas.addEventListener('click', (e) => { |
| if (gameState.gamePhase !== 'moving') return; |
| |
| const rect = canvas.getBoundingClientRect(); |
| const scaleX = canvas.width / rect.width; |
| const scaleY = canvas.height / rect.height; |
| const mouseX = (e.clientX - rect.left) * scaleX; |
| const mouseY = (e.clientY - rect.top) * scaleY; |
| |
| const cellSize = canvas.width / 11; |
| const col = Math.floor(mouseX / cellSize); |
| const row = Math.floor(mouseY / cellSize); |
| |
| const player = getCurrentPlayer(); |
| const pieces = gameState.players[player].pieces; |
| |
| |
| let clickedPiece = -1; |
| let minDist = cellSize * 0.4; |
| |
| gameState.validMoves.forEach(move => { |
| const pieceIdx = move.piece; |
| const pos = pieces[pieceIdx]; |
| let px, py; |
| |
| if (pos === -1) { |
| const startHouse = { |
| RED: { x: 7, y: 7 }, |
| BLUE: { x: 7, y: 0 }, |
| GREEN: { x: 0, y: 0 }, |
| YELLOW: { x: 0, y: 7 } |
| }[player]; |
| px = startHouse.x * cellSize + cellSize * 0.7 + (pieceIdx % 2) * cellSize * 0.5; |
| py = startHouse.y * cellSize + cellSize * 0.7 + Math.floor(pieceIdx / 2) * cellSize * 0.5; |
| } else if (pos >= 100) { |
| const step = pos - 100; |
| const homeCell = homeStretches[player][step]; |
| px = homeCell.x * cellSize + cellSize / 2; |
| py = homeCell.y * cellSize + cellSize / 2; |
| } else { |
| const pathCell = mainPath[pos]; |
| px = pathCell.x * cellSize + cellSize / 2; |
| py = pathCell.y * cellSize + cellSize / 2; |
| } |
| |
| const dist = Math.sqrt((mouseX - px) ** 2 + (mouseY - py) ** 2); |
| if (dist < minDist) { |
| minDist = dist; |
| clickedPiece = pieceIdx; |
| } |
| }); |
| |
| if (clickedPiece >= 0) { |
| const move = gameState.validMoves.find(m => m.piece === clickedPiece); |
| if (move) { |
| executeMove(move); |
| } |
| } |
| }); |
|
|
| |
| function updateUI() { |
| const player = getCurrentPlayer(); |
| const emojis = { RED: '🔴', BLUE: '🔵', GREEN: '🟢', YELLOW: '🟡' }; |
| document.getElementById('current-player-display').textContent = emojis[player]; |
| } |
|
|
| function updateStatusMessage(message) { |
| document.getElementById('game-status').textContent = message; |
| } |
|
|
| |
| function showWinModal(player) { |
| const modal = document.getElementById('win-modal'); |
| const content = document.getElementById('win-modal-content'); |
| const message = document.getElementById('win-message'); |
| const detail = document.getElementById('win-detail'); |
| |
| message.textContent = `بازیکن ${PLAYERS[player].name} برنده شد! 🏆`; |
| detail.textContent = 'بازی فوقالعادهای بود! آمادهای برای یه دور دیگه؟'; |
| |
| modal.classList.remove('hidden'); |
| setTimeout(() => content.classList.add('show'), 100); |
| } |
|
|
| function hideWinModal() { |
| const modal = document.getElementById('win-modal'); |
| const content = document.getElementById('win-modal-content'); |
| content.classList.remove('show'); |
| setTimeout(() => modal.classList.add('hidden'), 300); |
| } |
|
|
| |
| document.getElementById('roll-btn').addEventListener('click', rollDice); |
| document.getElementById('new-game-btn').addEventListener('click', initGame); |
| document.getElementById('win-new-game').addEventListener('click', () => { |
| hideWinModal(); |
| initGame(); |
| }); |
|
|
| document.getElementById('win-modal').addEventListener('click', function(e) { |
| if (e.target === this) { |
| hideWinModal(); |
| initGame(); |
| } |
| }); |
|
|
| |
| document.addEventListener('keydown', (e) => { |
| if (e.key === ' ' || e.key === 'Spacebar') { |
| e.preventDefault(); |
| rollDice(); |
| } else if (e.key === 'n' || e.key === 'N') { |
| initGame(); |
| } |
| }); |
|
|
| |
| initGame(); |
| renderDiceFace(1); |
| document.getElementById('dice-dots').innerHTML = ''; |
|
|
| console.log('🎲 منچ آماده است!'); |
| console.log('⌨️ کلید میانبر: Space = تاس بریز | N = بازی جدید'); |
| console.log('🔴 قرمز | 🔵 آبی | 🟢 سبز | 🟡 زرد'); |