Spaces:
Running
Running
| class DiceGrid extends HTMLElement { | |
| constructor() { | |
| super(); | |
| this.grid = Array(4).fill().map(() => Array(4).fill().map(() => [])); | |
| this.colors = [ | |
| 'bg-red-500', 'bg-blue-500', 'bg-green-500', 'bg-yellow-500', | |
| 'bg-purple-500', 'bg-pink-500', 'bg-indigo-500', 'bg-teal-500' | |
| ]; | |
| } | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.render(); | |
| } | |
| render() { | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| .grid { | |
| display: grid; | |
| grid-template-columns: repeat(4, 1fr); | |
| grid-template-rows: repeat(4, 1fr); | |
| gap: 8px; | |
| aspect-ratio: 1/1; | |
| } | |
| .dice { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 6px; | |
| font-weight: bold; | |
| color: white; | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); | |
| } | |
| .grid-slot { | |
| position: relative; | |
| min-height: 80px; | |
| border: 1px solid #e2e8f0; | |
| transition: all 0.2s ease; | |
| } | |
| .grid-slot.highlight { | |
| background-color: #e0e7ff; | |
| } | |
| .dice-stack { | |
| position: absolute; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 4px; | |
| } | |
| .dice-enter { | |
| animation: diceRoll 0.5s ease-out forwards; | |
| } | |
| @keyframes diceRoll { | |
| 0% { transform: translateY(-10px) rotate(0deg); opacity: 0; } | |
| 100% { transform: translateY(0) rotate(360deg); opacity: 1; } | |
| } | |
| </style> | |
| <div class="grid"> | |
| ${Array(4).fill().map((_, row) => | |
| Array(4).fill().map((_, col) => ` | |
| <div class="grid-slot" data-row="${row}" data-col="${col}"> | |
| ${this.grid[row][col].length > 0 ? ` | |
| <div class="dice-stack"> | |
| ${this.grid[row][col].map((die, index) => ` | |
| <div class="dice ${this.colors[die.charCodeAt(0) - 65 % this.colors.length]} dice-enter" style="animation-delay: ${index * 0.1}s"> | |
| ${Math.floor(Math.random() * 6) + 1} | |
| </div> | |
| `).join('')} | |
| </div> | |
| ` : ''} | |
| </div> | |
| `).join('') | |
| ).join('')} | |
| </div> | |
| `; | |
| } | |
| placeDice(diceLabels) { | |
| // Reset the grid | |
| this.grid = Array(4).fill().map(() => Array(4).fill().map(() => [])); | |
| // Place each die randomly with a random face value | |
| diceLabels.forEach((die, index) => { | |
| const faceValue = Math.floor(Math.random() * 6) + 1; | |
| let row, col; | |
| // Try to find a random position (max 5 attempts to avoid infinite loops) | |
| let attempts = 0; | |
| do { | |
| row = Math.floor(Math.random() * 4); | |
| col = Math.floor(Math.random() * 4); | |
| attempts++; | |
| } while (attempts < 5 && this.grid[row][col].length >= 2); | |
| // If slot has 2 dice already, find adjacent slot | |
| if (this.grid[row][col].length >= 2) { | |
| const adjacent = this.findAvailableAdjacentSlot(row, col); | |
| if (adjacent) { | |
| row = adjacent.row; | |
| col = adjacent.col; | |
| } | |
| } | |
| this.grid[row][col].push({label: die, value: faceValue}); | |
| }); | |
| this.render(); | |
| } | |
| findAvailableAdjacentSlot(row, col) { | |
| // Check all adjacent slots (up, down, left, right) | |
| const directions = [ | |
| { dr: -1, dc: 0 }, // up | |
| { dr: 1, dc: 0 }, // down | |
| { dr: 0, dc: -1 }, // left | |
| { dr: 0, dc: 1 } // right | |
| ]; | |
| // Shuffle directions to randomize selection | |
| directions.sort(() => Math.random() - 0.5); | |
| for (const dir of directions) { | |
| const newRow = row + dir.dr; | |
| const newCol = col + dir.dc; | |
| // Check if new position is within bounds | |
| if (newRow >= 0 && newRow < 4 && newCol >= 0 && newCol < 4) { | |
| // Check if slot has less than 2 dice | |
| if (this.grid[newRow][newCol].length < 2) { | |
| return { row: newRow, col: newCol }; | |
| } | |
| } | |
| } | |
| // If no adjacent slots available, find first available slot | |
| for (let r = 0; r < 4; r++) { | |
| for (let c = 0; c < 4; c++) { | |
| if (this.grid[r][c].length < 2) { | |
| return { row: r, col: c }; | |
| } | |
| } | |
| } | |
| return null; // No available slots (shouldn't happen with only 5 dice) | |
| } | |
| } | |
| customElements.define('dice-grid', DiceGrid); |