CoolFace
Apppublic

SGNMAI/roll-rage-royale

sourceHugging Faceupdated 11mo agoView on Hugging Face
0likes
script.js418 linesDownload Raw Back to root
1// Game state2const gameState = {3    players: [4        { id: 0, name: "Jij", color: "red", pieces: Array(4).fill(-1), home: 0 }, // -1 = in home, 0-39 = on board, 40 = finished5        { id: 1, name: "AI 1", color: "green", pieces: Array(4).fill(-1), home: 10 },6        { id: 2, name: "AI 2", color: "yellow", pieces: Array(4).fill(-1), home: 20 },7        { id: 3, name: "AI 3", color: "purple", pieces: Array(4).fill(-1), home: 30 }8    ],9    currentPlayer: 0,10    diceValue: 0,11    gameStarted: false,12    difficulty: 3 // 1-513};14 15// DOM elements16const diceContainer = document.getElementById('dice-container');17const diceElement = document.getElementById('dice');18const rollDiceButton = document.getElementById('roll-dice');19const startGameButton = document.getElementById('start-game');20const difficultySelect = document.getElementById('difficulty');21const gameStatus = document.getElementById('game-status');22const playerTurn = document.getElementById('player-turn');23const playerPieces = document.getElementById('player-pieces');24const ai1Pieces = document.getElementById('ai1-pieces');25const ai2Pieces = document.getElementById('ai2-pieces');26const ai3Pieces = document.getElementById('ai3-pieces');27 28// Initialize game board29function initBoard() {30    const board = document.getElementById('game-board');31    board.innerHTML = '';32    33    // Create board path34    const path = document.createElement('div');35    path.className = 'board-path';36    board.appendChild(path);37    38    // Create player homes39    createHome(board, 'board-home board-home-player', 'Jij');40    createHome(board, 'board-home board-home-ai1', 'AI 1');41    createHome(board, 'board-home board-home-ai2', 'AI 2');42    createHome(board, 'board-home board-home-ai3', 'AI 3');43    44    // Create board spaces (40 spaces)45    for (let i = 0; i < 40; i++) {46        const space = document.createElement('div');47        space.className = 'board-space board-space-safe';48        space.dataset.position = i;49        50        // Position spaces in a circle51        const angle = (i / 40) * 2 * Math.PI;52        const centerX = 50;53        const centerY = 50;54        const radius = 40;55        56        space.style.left = `${centerX + radius * Math.sin(angle)}%`;57        space.style.top = `${centerY - radius * Math.cos(angle)}%`;58        59        board.appendChild(space);60    }61    62    updateBoard();63}64 65function createHome(board, className, text) {66    const home = document.createElement('div');67    home.className = className;68    home.textContent = text;69    board.appendChild(home);70}71 72// Update board with current pieces73function updateBoard() {74    // Clear all pieces75    document.querySelectorAll('.board-space').forEach(space => {76        space.innerHTML = '';77    });78    79    // Update each player's pieces80    gameState.players.forEach(player => {81        player.pieces.forEach((position, pieceIndex) => {82            if (position >= 0 && position < 40) {83                // Piece is on the board84                const space = document.querySelector(`.board-space[data-position="${position}"]`);85                if (space) {86                    space.className = `board-space board-space-${player.color}`;87                    88                    const piece = document.createElement('div');89                    piece.className = `game-piece game-piece-${player.color}`;90                    piece.dataset.player = player.id;91                    piece.dataset.piece = pieceIndex;92                    space.appendChild(piece);93                }94            }95        });96    });97    98    // Update piece counters99    updatePieceCounters();100}101 102function updatePieceCounters() {103    const playerFinished = gameState.players[0].pieces.filter(p => p === 40).length;104    const ai1Finished = gameState.players[1].pieces.filter(p => p === 40).length;105    const ai2Finished = gameState.players[2].pieces.filter(p => p === 40).length;106    const ai3Finished = gameState.players[3].pieces.filter(p => p === 40).length;107    108    playerPieces.textContent = `${playerFinished}/4`;109    ai1Pieces.textContent = `${ai1Finished}/4`;110    ai2Pieces.textContent = `${ai2Finished}/4`;111    ai3Pieces.textContent = `${ai3Finished}/4`;112}113 114// Roll dice115function rollDice() {116    rollDiceButton.disabled = true;117    diceElement.classList.add('dice-rolling');118    119    // Animate dice120    let rolls = 0;121    const maxRolls = 5;122    const interval = setInterval(() => {123        gameState.diceValue = Math.floor(Math.random() * 6) + 1;124        diceElement.textContent = gameState.diceValue;125        rolls++;126        127        if (rolls >= maxRolls) {128            clearInterval(interval);129            diceElement.classList.remove('dice-rolling');130            handleDiceResult();131        }132    }, 100);133}134 135function handleDiceResult() {136    if (gameState.currentPlayer === 0) {137        // Human player138        gameStatus.textContent = `Je hebt een ${gameState.diceValue} gegooid!`;139        140        // Check for possible moves141        const possibleMoves = checkPossibleMoves(gameState.currentPlayer);142        143        if (possibleMoves.length === 0) {144            gameStatus.textContent += " Geen mogelijke zetten. Beurt voorbij.";145            setTimeout(nextPlayer, 1500);146        } else {147            // Highlight possible moves148            possibleMoves.forEach(move => {149                const space = document.querySelector(`.board-space[data-position="${move.newPos}"]`);150                if (space) {151                    space.classList.add('ring-2', 'ring-offset-2', 'ring-blue-500');152                    space.addEventListener('click', () => makeMove(move));153                }154            });155        }156    } else {157        // AI player158        gameStatus.textContent = `${gameState.players[gameState.currentPlayer].name} gooit een ${gameState.diceValue}`;159        160        setTimeout(() => {161            makeAIMove(gameState.currentPlayer);162        }, 1000);163    }164}165 166function checkPossibleMoves(playerId) {167    const player = gameState.players[playerId];168    const moves = [];169    170    player.pieces.forEach((position, pieceIndex) => {171        if (position === -1 && gameState.diceValue === 6) {172            // Piece can exit home173            moves.push({174                pieceIndex,175                newPos: player.home,176                fromHome: true177            });178        } else if (position >= 0 && position < 40) {179            const newPos = (position + gameState.diceValue) % 40;180            181            // Check if landing on own piece (invalid)182            const hasOwnPiece = player.pieces.some(p => p === newPos);183            184            if (!hasOwnPiece) {185                moves.push({186                    pieceIndex,187                    newPos,188                    fromHome: false189                });190            }191        } else if (position === 40) {192            // Piece already finished193        }194    });195    196    return moves;197}198 199function makeMove(move) {200    // Remove all highlight and event listeners201    document.querySelectorAll('.board-space').forEach(space => {202        space.classList.remove('ring-2', 'ring-offset-2', 'ring-blue-500');203        space.replaceWith(space.cloneNode(true));204    });205    206    const player = gameState.players[gameState.currentPlayer];207    208    // Move the piece209    if (move.fromHome) {210        // Exit home211        player.pieces[move.pieceIndex] = move.newPos;212    } else {213        // Move on board214        const currentPos = player.pieces[move.pieceIndex];215        216        // Check if landing on opponent piece (send them home)217        gameState.players.forEach((opponent, oppId) => {218            if (oppId !== gameState.currentPlayer) {219                opponent.pieces.forEach((oppPos, oppPieceIndex) => {220                    if (oppPos === move.newPos) {221                        opponent.pieces[oppPieceIndex] = -1; // Send home222                        gameStatus.textContent = `Je hebt ${opponent.name}'s pion naar huis gestuurd!`;223                    }224                });225            }226        });227        228        player.pieces[move.pieceIndex] = move.newPos;229        230        // Check if piece can finish (exact move to position 40)231        if (currentPos + gameState.diceValue >= 40) {232            player.pieces[move.pieceIndex] = 40; // Finished233            gameStatus.textContent = `Je hebt een pion thuisgebracht!`;234            235            // Check if player won236            if (player.pieces.every(p => p === 40)) {237                gameStatus.textContent = `Gefeliciteerd! Je hebt gewonnen!`;238                endGame();239                return;240            }241        }242    }243    244    updateBoard();245    nextPlayer();246}247 248function makeAIMove(playerId) {249    const player = gameState.players[playerId];250    const possibleMoves = checkPossibleMoves(playerId);251    252    if (possibleMoves.length === 0) {253        gameStatus.textContent += " Geen mogelijke zetten. Beurt voorbij.";254        nextPlayer();255        return;256    }257    258    // AI logic based on difficulty259    let chosenMove;260    261    switch (gameState.difficulty) {262        case 1: // Easy - random move263            chosenMove = possibleMoves[Math.floor(Math.random() * possibleMoves.length)];264            break;265        case 2: // Medium - prefer capturing and exiting home266            chosenMove = possibleMoves.find(move => {267                // Check if move captures an opponent268                return gameState.players.some((opponent, oppId) => {269                    return oppId !== playerId && opponent.pieces.some(p => p === move.newPos);270                });271            }) || possibleMoves.find(move => move.fromHome) || possibleMoves[0];272            break;273        case 3: // Normal - balance between offense and defense274            chosenMove = possibleMoves.find(move => {275                // Check if move captures an opponent276                return gameState.players.some((opponent, oppId) => {277                    return oppId !== playerId && opponent.pieces.some(p => p === move.newPos);278                });279            }) || possibleMoves.find(move => {280                // Prefer moves that advance pieces closer to finish281                return (move.newPos > player.pieces[move.pieceIndex]) && 282                       (move.newPos % 10 < 5); // Prefer positions not too close to home283            }) || possibleMoves[0];284            break;285        case 4: // Hard - aggressive and strategic286            chosenMove = possibleMoves.find(move => {287                // Always capture if possible288                return gameState.players.some((opponent, oppId) => {289                    return oppId !== playerId && opponent.pieces.some(p => p === move.newPos);290                });291            }) || possibleMoves.find(move => {292                // Prefer moves that bring pieces closer to finish293                const distToFinish = (40 - player.pieces[move.pieceIndex]) % 40;294                return (distToFinish <= gameState.diceValue * 2);295            }) || possibleMoves.find(move => move.fromHome) || possibleMoves[0];296            break;297        case 5: // Expert - very strategic298            chosenMove = possibleMoves.find(move => {299                // Check if this move leads to potential future captures300                const futurePositions = Array.from({length: 6}, (_, i) => (move.newPos + i + 1) % 40);301                return futurePositions.some(pos => {302                    return gameState.players.some((opponent, oppId) => {303                        if (oppId === playerId) return false;304                        return opponent.pieces.some(p => p === pos);305                    });306                });307            }) || possibleMoves.find(move => {308                // Prefer moves that block opponents309                const nextPositions = [1, 2, 3, 4, 5, 6].map(i => (move.newPos + i) % 40);310                return nextPositions.some(pos => {311                    return gameState.players.some((opponent, oppId) => {312                        if (oppId === playerId) return false;313                        return opponent.pieces.some(p => p === pos);314                    });315                });316            }) || possibleMoves.find(move => move.fromHome) || possibleMoves[0];317            break;318        default:319            chosenMove = possibleMoves[0];320    }321    322    // Execute the chosen move323    if (chosenMove.fromHome) {324        // Exit home325        player.pieces[chosenMove.pieceIndex] = chosenMove.newPos;326        gameStatus.textContent += ` Pion uit huis gehaald.`;327    } else {328        const currentPos = player.pieces[chosenMove.pieceIndex];329        330        // Check if landing on opponent piece (send them home)331        let captured = false;332        gameState.players.forEach((opponent, oppId) => {333            if (oppId !== playerId) {334                opponent.pieces.forEach((oppPos, oppPieceIndex) => {335                    if (oppPos === chosenMove.newPos) {336                        opponent.pieces[oppPieceIndex] = -1; // Send home337                        captured = true;338                        gameStatus.textContent += ` ${player.name} heeft jouw pion naar huis gestuurd!`;339                    }340                });341            }342        });343        344        player.pieces[chosenMove.pieceIndex] = chosenMove.newPos;345        346        // Check if piece can finish (exact move to position 40)347        if (currentPos + gameState.diceValue >= 40) {348            player.pieces[chosenMove.pieceIndex] = 40; // Finished349            gameStatus.textContent += ` ${player.name} heeft een pion thuisgebracht.`;350            351            // Check if AI won352            if (player.pieces.every(p => p === 40)) {353                gameStatus.textContent = `Helaas! ${player.name} heeft gewonnen!`;354                endGame();355                return;356            }357        } else if (!captured) {358            gameStatus.textContent += ` Pion verplaatst naar positie ${chosenMove.newPos + 1}.`;359        }360    }361    362    updateBoard();363    nextPlayer();364}365 366function nextPlayer() {367    rollDiceButton.disabled = false;368    369    gameState.currentPlayer = (gameState.currentPlayer + 1) % 4;370    371    if (gameState.currentPlayer === 0) {372        // Human player's turn373        playerTurn.classList.remove('hidden');374    } else {375        // AI player's turn376        playerTurn.classList.add('hidden');377        378        // Auto-roll for AI379        setTimeout(() => {380            rollDice();381        }, 1000);382    }383}384 385function startGame() {386    gameState.gameStarted = true;387    gameState.currentPlayer = 0;388    389    // Reset all pieces to home390    gameState.players.forEach(player => {391        player.pieces = Array(4).fill(-1);392    });393    394    gameState.difficulty = parseInt(difficultySelect.value);395    396    // Update UI397    startGameButton.textContent = 'Spel Herstarten';398    diceContainer.classList.remove('hidden');399    playerTurn.classList.remove('hidden');400    gameStatus.textContent = 'Spel gestart! Jij mag beginnen.';401    402    updateBoard();403    updatePieceCounters();404}405 406function endGame() {407    gameState.gameStarted = false;408    diceContainer.classList.add('hidden');409    playerTurn.classList.add('hidden');410    rollDiceButton.disabled = true;411}412 413// Event listeners414startGameButton.addEventListener('click', startGame);415rollDiceButton.addEventListener('click', rollDice);416 417// Initialize the board when page loads418document.addEventListener('DOMContentLoaded', initBoard);