SGNMAI/roll-rage-royale
0
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);