From 6edd2637e684f2a488d9cdf807667a2a7d56f15e Mon Sep 17 00:00:00 2001 From: sibron131 Date: Sun, 15 Feb 2026 10:58:58 +0100 Subject: [PATCH] initial commit --- mines.css | 845 +++++++++++++++++++++++++++++++++++++++++++++++++++++ mines.html | 133 +++++++++ mines.js | 384 ++++++++++++++++++++++++ 3 files changed, 1362 insertions(+) create mode 100644 mines.css create mode 100644 mines.html create mode 100644 mines.js diff --git a/mines.css b/mines.css new file mode 100644 index 0000000..3b4fd65 --- /dev/null +++ b/mines.css @@ -0,0 +1,845 @@ +/* ===== CSS VARIABLES ===== */ +:root { + /* Main Palette - Elegant & Subdued */ + --bg-primary: #0d0d12; + --bg-secondary: #14141c; + --bg-tertiary: #1c1c28; + --bg-card: #1a1a24; + --bg-card-hover: #222230; + + /* Text Colors */ + --text-primary: #f5f5f7; + --text-secondary: #a0a0b0; + --text-muted: #606070; + + /* Accent Colors */ + --gold: #c9a962; + --gold-light: #e0c887; + --gold-dark: #a08840; + + /* Green - RARE ACCENT (only for wins/success) */ + --green-accent: #2d9469; + --green-light: #3db87f; + --green-glow: rgba(45, 148, 105, 0.3); + + /* Danger */ + --red: #c44545; + --red-light: #e05555; + --red-glow: rgba(196, 69, 69, 0.4); + + /* UI Elements */ + --border-color: #2a2a3a; + --border-light: #3a3a4a; + + /* Tile States */ + --tile-bg: linear-gradient(145deg, #252535, #1e1e2a); + --tile-hover: linear-gradient(145deg, #2a2a3c, #232332); + --tile-revealed-safe: linear-gradient(145deg, #1a2e25, #152520); + --tile-revealed-mine: linear-gradient(145deg, #2e1a1a, #251515); + + /* Shadows */ + --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5); + --shadow-gold: 0 0 20px rgba(201, 169, 98, 0.2); + + /* Typography */ + --font-display: 'Playfair Display', Georgia, serif; + --font-body: 'Inter', -apple-system, sans-serif; + + /* Sizing */ + --grid-size: 5; + --tile-size: 70px; + --tile-gap: 8px; + + /* Transitions */ + --transition-fast: 0.15s ease; + --transition-normal: 0.25s ease; + --transition-slow: 0.4s ease; +} + +/* ===== RESET & BASE ===== */ +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: var(--font-body); + background: var(--bg-primary); + color: var(--text-primary); + min-height: 100vh; + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} + +/* ===== LAYOUT ===== */ +.casino-container { + max-width: 1400px; + margin: 0 auto; + padding: 20px; + min-height: 100vh; +} + +/* ===== HEADER ===== */ +.header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px 30px; + background: var(--bg-secondary); + border-radius: 16px; + border: 1px solid var(--border-color); + margin-bottom: 24px; +} + +.logo { + display: flex; + align-items: center; + gap: 12px; +} + +.logo-icon { + font-size: 28px; + color: var(--gold); + text-shadow: var(--shadow-gold); +} + +.logo-text { + font-family: var(--font-display); + font-size: 28px; + font-weight: 700; + letter-spacing: 4px; + background: linear-gradient(135deg, var(--gold-light), var(--gold)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.balance-display { + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 4px; +} + +.balance-label { + font-size: 12px; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 1px; +} + +.balance-value { + font-size: 24px; + font-weight: 600; + color: var(--gold); +} + +/* ===== MAIN GAME AREA ===== */ +.game-area { + display: grid; + grid-template-columns: 280px 1fr 240px; + gap: 24px; + align-items: start; +} + +/* ===== PANELS ===== */ +.controls-panel, +.history-panel { + background: var(--bg-secondary); + border-radius: 16px; + border: 1px solid var(--border-color); + padding: 24px; +} + +.panel-section { + margin-bottom: 24px; + padding-bottom: 24px; + border-bottom: 1px solid var(--border-color); +} + +.panel-section:last-child { + margin-bottom: 0; + padding-bottom: 0; + border-bottom: none; +} + +.panel-title { + font-family: var(--font-display); + font-size: 16px; + font-weight: 600; + color: var(--text-secondary); + margin-bottom: 16px; + text-transform: uppercase; + letter-spacing: 2px; +} + +/* ===== INPUT STYLES ===== */ +.input-label { + display: block; + font-size: 12px; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 10px; +} + +.bet-input-group { + display: flex; + align-items: center; + background: var(--bg-tertiary); + border-radius: 10px; + border: 1px solid var(--border-color); + overflow: hidden; + transition: border-color var(--transition-fast); +} + +.bet-input-group:focus-within { + border-color: var(--gold-dark); +} + +.currency-symbol { + padding: 12px; + color: var(--text-muted); + font-weight: 500; +} + +.bet-input { + flex: 1; + background: transparent; + border: none; + color: var(--text-primary); + font-size: 18px; + font-weight: 600; + padding: 12px 8px; + outline: none; + width: 100%; +} + +.bet-input::-webkit-outer-spin-button, +.bet-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +.bet-buttons { + display: flex; + border-left: 1px solid var(--border-color); +} + +.bet-btn { + background: transparent; + border: none; + color: var(--text-secondary); + padding: 12px 14px; + cursor: pointer; + font-size: 14px; + font-weight: 600; + transition: all var(--transition-fast); +} + +.bet-btn:hover { + background: var(--bg-card-hover); + color: var(--gold); +} + +.bet-btn:first-child { + border-right: 1px solid var(--border-color); +} + +/* ===== MINES SELECTOR ===== */ +.mines-selector { + display: flex; + align-items: center; + justify-content: center; + gap: 20px; + margin-bottom: 16px; +} + +.mines-btn { + width: 40px; + height: 40px; + border-radius: 10px; + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); + font-size: 20px; + cursor: pointer; + transition: all var(--transition-fast); +} + +.mines-btn:hover { + background: var(--bg-card-hover); + border-color: var(--gold-dark); + color: var(--gold); +} + +.mines-btn:active { + transform: scale(0.95); +} + +.mines-value { + font-size: 32px; + font-weight: 700; + color: var(--gold); + min-width: 50px; + text-align: center; +} + +.mines-range { + display: flex; + align-items: center; + gap: 12px; + font-size: 12px; + color: var(--text-muted); +} + +.mines-range input[type="range"] { + flex: 1; + -webkit-appearance: none; + appearance: none; + height: 4px; + background: var(--bg-tertiary); + border-radius: 4px; + cursor: pointer; +} + +.mines-range input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 16px; + height: 16px; + background: var(--gold); + border-radius: 50%; + cursor: pointer; + transition: transform var(--transition-fast); +} + +.mines-range input[type="range"]::-webkit-slider-thumb:hover { + transform: scale(1.2); +} + +/* ===== STATS SECTION ===== */ +.stats-section { + background: var(--bg-tertiary); + border-radius: 10px; + padding: 16px !important; + margin-left: -8px; + margin-right: -8px; + width: calc(100% + 16px); +} + +.stat-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 0; +} + +.stat-row:not(:last-child) { + border-bottom: 1px solid var(--border-color); +} + +.stat-label { + font-size: 13px; + color: var(--text-secondary); +} + +.stat-value { + font-size: 14px; + font-weight: 600; + color: var(--text-primary); +} + +.stat-value.multiplier { + color: var(--gold); +} + +/* ===== PAYOUT SECTION ===== */ +.payout-section { + text-align: center; +} + +.current-multiplier, +.potential-win { + margin-bottom: 16px; +} + +.payout-label { + display: block; + font-size: 11px; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 6px; +} + +.payout-value { + font-size: 28px; + font-weight: 700; + color: var(--text-primary); +} + +.payout-value.win-value { + color: var(--gold); +} + +/* ===== ACTION BUTTONS ===== */ +.action-section { + border-bottom: none !important; +} + +.action-btn { + width: 100%; + padding: 16px 24px; + border-radius: 12px; + border: none; + font-size: 16px; + font-weight: 600; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + transition: all var(--transition-normal); + text-transform: uppercase; + letter-spacing: 1px; +} + +.start-btn { + background: linear-gradient(135deg, var(--gold), var(--gold-dark)); + color: var(--bg-primary); + box-shadow: var(--shadow-gold); +} + +.start-btn:hover:not(:disabled) { + transform: translateY(-2px); + box-shadow: 0 6px 24px rgba(201, 169, 98, 0.4); +} + +.start-btn:active:not(:disabled) { + transform: translateY(0); +} + +.start-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.cashout-btn { + background: linear-gradient(135deg, var(--green-accent), #257a55); + color: var(--text-primary); + box-shadow: 0 4px 16px var(--green-glow); + animation: pulse-green 2s infinite; +} + +.cashout-btn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 24px var(--green-glow); +} + +@keyframes pulse-green { + 0%, 100% { box-shadow: 0 4px 16px var(--green-glow); } + 50% { box-shadow: 0 4px 24px rgba(45, 148, 105, 0.5); } +} + +.btn-icon { + font-size: 14px; +} + +/* ===== GAME GRID ===== */ +.grid-container { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; +} + +.grid-wrapper { + position: relative; + padding: 24px; + background: var(--bg-secondary); + border-radius: 20px; + border: 1px solid var(--border-color); +} + +.game-grid { + display: grid; + grid-template-columns: repeat(var(--grid-size), var(--tile-size)); + grid-template-rows: repeat(var(--grid-size), var(--tile-size)); + gap: var(--tile-gap); +} + +.tile { + width: var(--tile-size); + height: var(--tile-size); + background: var(--tile-bg); + border-radius: 12px; + border: 1px solid var(--border-color); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 28px; + transition: all var(--transition-normal); + position: relative; + overflow: hidden; +} + +.tile::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(135deg, rgba(255,255,255,0.05), transparent); + border-radius: 12px; +} + +.tile:hover:not(.revealed):not(.disabled) { + background: var(--tile-hover); + transform: translateY(-3px); + box-shadow: var(--shadow-md); + border-color: var(--border-light); +} + +.tile:active:not(.revealed):not(.disabled) { + transform: translateY(-1px); +} + +.tile.disabled { + cursor: not-allowed; + opacity: 0.7; +} + +.tile.revealed { + cursor: default; + transform: none; +} + +.tile.revealed.safe { + background: var(--tile-revealed-safe); + border-color: var(--green-accent); + animation: reveal-safe 0.4s ease; +} + +.tile.revealed.safe .tile-icon { + color: var(--green-light); + text-shadow: 0 0 10px var(--green-glow); +} + +.tile.revealed.mine { + background: var(--tile-revealed-mine); + border-color: var(--red); + animation: reveal-mine 0.5s ease; +} + +.tile.revealed.mine .tile-icon { + color: var(--red-light); + text-shadow: 0 0 10px var(--red-glow); +} + +.tile.show-mine { + background: var(--tile-revealed-mine); + border-color: rgba(196, 69, 69, 0.5); +} + +.tile.show-mine .tile-icon { + color: var(--red); + opacity: 0.7; +} + +@keyframes reveal-safe { + 0% { transform: scale(0.8); opacity: 0; } + 50% { transform: scale(1.1); } + 100% { transform: scale(1); opacity: 1; } +} + +@keyframes reveal-mine { + 0% { transform: scale(0.8) rotate(-10deg); opacity: 0; } + 30% { transform: scale(1.2) rotate(5deg); } + 60% { transform: scale(0.95) rotate(-2deg); } + 100% { transform: scale(1) rotate(0); opacity: 1; } +} + +.tile-icon { + position: relative; + z-index: 1; +} + +/* Grid Overlay */ +.grid-overlay { + position: absolute; + inset: 0; + background: rgba(13, 13, 18, 0.9); + border-radius: 20px; + display: flex; + align-items: center; + justify-content: center; + backdrop-filter: blur(4px); +} + +.overlay-content { + text-align: center; +} + +.overlay-icon { + font-size: 48px; + display: block; + margin-bottom: 16px; +} + +.overlay-text { + font-size: 16px; + color: var(--text-secondary); +} + +.revealed-counter { + font-size: 14px; + color: var(--text-muted); + text-align: center; +} + +/* ===== HISTORY PANEL ===== */ +.history-panel { + max-height: 600px; + overflow-y: auto; +} + +.history-list { + display: flex; + flex-direction: column; + gap: 12px; +} + +.history-empty { + color: var(--text-muted); + font-size: 14px; + text-align: center; + padding: 20px; +} + +.history-item { + background: var(--bg-tertiary); + border-radius: 10px; + padding: 14px; + border-left: 3px solid var(--border-color); + transition: all var(--transition-fast); +} + +.history-item:hover { + background: var(--bg-card-hover); +} + +.history-item.win { + border-left-color: var(--green-accent); +} + +.history-item.loss { + border-left-color: var(--red); +} + +.history-bet { + font-size: 12px; + color: var(--text-muted); + margin-bottom: 4px; +} + +.history-result { + font-size: 16px; + font-weight: 600; +} + +.history-item.win .history-result { + color: var(--green-light); +} + +.history-item.loss .history-result { + color: var(--red-light); +} + +.history-details { + font-size: 11px; + color: var(--text-muted); + margin-top: 6px; +} + +/* ===== MODAL ===== */ +.modal { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + backdrop-filter: blur(8px); + animation: modal-fade-in 0.3s ease; +} + +@keyframes modal-fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +.modal-content { + background: var(--bg-secondary); + border-radius: 24px; + padding: 48px; + text-align: center; + border: 1px solid var(--border-color); + box-shadow: var(--shadow-lg); + animation: modal-scale-in 0.4s ease; + min-width: 320px; +} + +.modal-content.win { + border-color: var(--green-accent); + box-shadow: 0 0 60px var(--green-glow); +} + +.modal-content.loss { + border-color: var(--red); + box-shadow: 0 0 60px var(--red-glow); +} + +@keyframes modal-scale-in { + from { transform: scale(0.8); opacity: 0; } + to { transform: scale(1); opacity: 1; } +} + +.modal-icon { + font-size: 64px; + margin-bottom: 20px; + display: block; +} + +.modal-title { + font-family: var(--font-display); + font-size: 28px; + font-weight: 700; + margin-bottom: 16px; +} + +.modal-content.win .modal-title { + color: var(--green-light); +} + +.modal-content.loss .modal-title { + color: var(--red-light); +} + +.modal-amount { + font-size: 42px; + font-weight: 700; + margin-bottom: 8px; +} + +.modal-content.win .modal-amount { + color: var(--green-light); +} + +.modal-content.loss .modal-amount { + color: var(--red-light); +} + +.modal-subtitle { + font-size: 14px; + color: var(--text-muted); + margin-bottom: 32px; +} + +.modal-btn { + background: linear-gradient(135deg, var(--gold), var(--gold-dark)); + color: var(--bg-primary); + border: none; + padding: 14px 40px; + border-radius: 10px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all var(--transition-normal); + text-transform: uppercase; + letter-spacing: 1px; +} + +.modal-btn:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-gold); +} + +/* ===== UTILITIES ===== */ +.hidden { + display: none !important; +} + +/* ===== SCROLLBAR ===== */ +::-webkit-scrollbar { + width: 6px; +} + +::-webkit-scrollbar-track { + background: var(--bg-tertiary); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb { + background: var(--border-light); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} + +/* ===== RESPONSIVE ===== */ +@media (max-width: 1200px) { + .game-area { + grid-template-columns: 260px 1fr; + } + + .history-panel { + display: none; + } +} + +@media (max-width: 900px) { + .game-area { + grid-template-columns: 1fr; + } + + .controls-panel { + order: 2; + } + + .grid-container { + order: 1; + } + + :root { + --tile-size: 60px; + --tile-gap: 6px; + } +} + +@media (max-width: 500px) { + :root { + --tile-size: 50px; + --tile-gap: 5px; + } + + .casino-container { + padding: 12px; + } + + .header { + padding: 16px 20px; + } + + .logo-text { + font-size: 22px; + } + + .grid-wrapper { + padding: 16px; + } +} \ No newline at end of file diff --git a/mines.html b/mines.html new file mode 100644 index 0000000..b1c123c --- /dev/null +++ b/mines.html @@ -0,0 +1,133 @@ + + + + + + Mines - Elegant Casino + + + + +
+ +
+ +
+ Balance + $1,000.00 +
+
+ + +
+ + + + +
+
+
+ +
+ +
+
+ 0 / 22 tiles revealed +
+
+ + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/mines.js b/mines.js new file mode 100644 index 0000000..40196d3 --- /dev/null +++ b/mines.js @@ -0,0 +1,384 @@ +/** + * MINES - Casino Game + * Elegant browser-based Mines game simulation + */ + +class MinesGame { + constructor(config = {}) { + // Grid configuration (easily changeable) + this.gridSize = config.gridSize || 5; + this.totalTiles = this.gridSize * this.gridSize; + + // Game state + this.balance = 1000; + this.bet = 10; + this.minesCount = 3; + this.isPlaying = false; + this.revealedCount = 0; + this.currentMultiplier = 1.0; + this.minePositions = []; + this.history = []; + + // DOM Elements + this.elements = { + balance: document.getElementById('balance'), + betInput: document.getElementById('bet-amount'), + minesCount: document.getElementById('mines-count'), + minesSlider: document.getElementById('mines-slider'), + minesDecrease: document.getElementById('mines-decrease'), + minesIncrease: document.getElementById('mines-increase'), + tilesInfo: document.getElementById('tiles-info'), + safeTiles: document.getElementById('safe-tiles'), + nextMultiplier: document.getElementById('next-multiplier'), + currentMultiplier: document.getElementById('current-multiplier'), + potentialWin: document.getElementById('potential-win'), + startBtn: document.getElementById('start-btn'), + cashoutBtn: document.getElementById('cashout-btn'), + gameGrid: document.getElementById('game-grid'), + gridOverlay: document.getElementById('grid-overlay'), + overlayIcon: document.getElementById('overlay-icon'), + overlayText: document.getElementById('overlay-text'), + revealedCount: document.getElementById('revealed-count'), + totalSafe: document.getElementById('total-safe'), + historyList: document.getElementById('history-list'), + modal: document.getElementById('result-modal'), + modalContent: document.getElementById('modal-content'), + modalIcon: document.getElementById('modal-icon'), + modalTitle: document.getElementById('modal-title'), + modalAmount: document.getElementById('modal-amount'), + modalSubtitle: document.getElementById('modal-subtitle'), + modalClose: document.getElementById('modal-close') + }; + + // Initialize + this.init(); + } + + init() { + this.updateGridCSS(); + this.createGrid(); + this.bindEvents(); + this.updateUI(); + this.showOverlay('💎', 'Place your bet and start!'); + } + + updateGridCSS() { + document.documentElement.style.setProperty('--grid-size', this.gridSize); + this.elements.tilesInfo.textContent = `${this.totalTiles} (${this.gridSize}×${this.gridSize})`; + } + + createGrid() { + this.elements.gameGrid.innerHTML = ''; + for (let i = 0; i < this.totalTiles; i++) { + const tile = document.createElement('div'); + tile.className = 'tile disabled'; + tile.dataset.index = i; + tile.innerHTML = ''; + this.elements.gameGrid.appendChild(tile); + } + } + + bindEvents() { + // Bet input + this.elements.betInput.addEventListener('input', (e) => { + this.bet = Math.max(1, parseFloat(e.target.value) || 1); + this.updateUI(); + }); + + // Bet buttons (half/double) + document.querySelectorAll('.bet-btn').forEach(btn => { + btn.addEventListener('click', () => { + const action = btn.dataset.action; + if (action === 'half') { + this.bet = Math.max(1, Math.floor(this.bet / 2)); + } else if (action === 'double') { + this.bet = Math.min(this.balance, this.bet * 2); + } + this.elements.betInput.value = this.bet; + this.updateUI(); + }); + }); + + // Mines selector + this.elements.minesDecrease.addEventListener('click', () => { + this.minesCount = Math.max(1, this.minesCount - 1); + this.elements.minesSlider.value = this.minesCount; + this.updateUI(); + }); + + this.elements.minesIncrease.addEventListener('click', () => { + this.minesCount = Math.min(this.totalTiles - 1, this.minesCount + 1); + this.elements.minesSlider.value = this.minesCount; + this.updateUI(); + }); + + this.elements.minesSlider.addEventListener('input', (e) => { + this.minesCount = parseInt(e.target.value); + this.updateUI(); + }); + + // Update slider max based on grid size + this.elements.minesSlider.max = this.totalTiles - 1; + + // Start button + this.elements.startBtn.addEventListener('click', () => this.startRound()); + + // Cashout button + this.elements.cashoutBtn.addEventListener('click', () => this.cashOut()); + + // Modal close + this.elements.modalClose.addEventListener('click', () => this.hideModal()); + + // Tile clicks + this.elements.gameGrid.addEventListener('click', (e) => { + const tile = e.target.closest('.tile'); + if (tile && this.isPlaying && !tile.classList.contains('revealed') && !tile.classList.contains('disabled')) { + this.revealTile(parseInt(tile.dataset.index)); + } + }); + } + + /** + * Calculate multiplier based on mines count and revealed tiles + * Formula: Each safe reveal increases multiplier based on probability + * The fewer safe tiles remaining, the higher the reward + */ + calculateMultiplier(revealed) { + if (revealed === 0) return 1.0; + + const safeTiles = this.totalTiles - this.minesCount; + let multiplier = 1.0; + + // House edge (around 3%) + const houseEdge = 0.97; + + for (let i = 0; i < revealed; i++) { + const remainingTiles = this.totalTiles - i; + const remainingSafe = safeTiles - i; + // Fair odds * house edge + const stepMultiplier = (remainingTiles / remainingSafe) * houseEdge; + multiplier *= stepMultiplier; + } + + return Math.round(multiplier * 100) / 100; + } + + getNextMultiplier() { + return this.calculateMultiplier(this.revealedCount + 1); + } + + updateUI() { + // Update mines count display + this.elements.minesCount.textContent = this.minesCount; + + // Update safe tiles count + const safeTiles = this.totalTiles - this.minesCount; + this.elements.safeTiles.textContent = safeTiles; + this.elements.totalSafe.textContent = safeTiles; + + // Update multipliers + this.elements.currentMultiplier.textContent = `×${this.currentMultiplier.toFixed(2)}`; + this.elements.nextMultiplier.textContent = `×${this.getNextMultiplier().toFixed(2)}`; + + // Update potential win + const potentialWin = this.bet * this.currentMultiplier; + this.elements.potentialWin.textContent = this.formatCurrency(potentialWin); + + // Update revealed count + this.elements.revealedCount.textContent = this.revealedCount; + + // Update balance + this.elements.balance.textContent = this.formatCurrency(this.balance); + + // Update start button state + this.elements.startBtn.disabled = this.bet > this.balance || this.bet <= 0; + } + + formatCurrency(amount) { + return '$' + amount.toLocaleString('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); + } + + showOverlay(icon, text) { + this.elements.overlayIcon.textContent = icon; + this.elements.overlayText.textContent = text; + this.elements.gridOverlay.classList.remove('hidden'); + } + + hideOverlay() { + this.elements.gridOverlay.classList.add('hidden'); + } + + generateMinePositions() { + const positions = []; + while (positions.length < this.minesCount) { + const pos = Math.floor(Math.random() * this.totalTiles); + if (!positions.includes(pos)) { + positions.push(pos); + } + } + return positions; + } + + startRound() { + if (this.bet > this.balance) return; + + // Deduct bet from balance + this.balance -= this.bet; + + // Reset game state + this.isPlaying = true; + this.revealedCount = 0; + this.currentMultiplier = 1.0; + this.minePositions = this.generateMinePositions(); + + // Update UI + this.hideOverlay(); + this.elements.startBtn.classList.add('hidden'); + this.elements.cashoutBtn.classList.remove('hidden'); + + // Reset all tiles + document.querySelectorAll('.tile').forEach(tile => { + tile.className = 'tile'; + tile.querySelector('.tile-icon').textContent = ''; + }); + + // Disable bet controls during game + this.elements.betInput.disabled = true; + this.elements.minesSlider.disabled = true; + this.elements.minesDecrease.disabled = true; + this.elements.minesIncrease.disabled = true; + + this.updateUI(); + } + + revealTile(index) { + const tile = document.querySelectorAll('.tile')[index]; + const icon = tile.querySelector('.tile-icon'); + + if (this.minePositions.includes(index)) { + // Hit a mine - GAME OVER + tile.classList.add('revealed', 'mine'); + icon.textContent = '💣'; + this.endRound(false); + } else { + // Safe tile + tile.classList.add('revealed', 'safe'); + icon.textContent = '💎'; + this.revealedCount++; + this.currentMultiplier = this.calculateMultiplier(this.revealedCount); + this.updateUI(); + + // Check if all safe tiles are revealed + const safeTiles = this.totalTiles - this.minesCount; + if (this.revealedCount >= safeTiles) { + this.cashOut(); + } + } + } + + cashOut() { + if (!this.isPlaying) return; + + const winnings = this.bet * this.currentMultiplier; + this.balance += winnings; + this.endRound(true, winnings); + } + + endRound(isWin, winnings = 0) { + this.isPlaying = false; + + // Reveal all mines + this.minePositions.forEach(pos => { + const tile = document.querySelectorAll('.tile')[pos]; + if (!tile.classList.contains('revealed')) { + tile.classList.add('show-mine'); + tile.querySelector('.tile-icon').textContent = '💣'; + } + }); + + // Disable all tiles + document.querySelectorAll('.tile').forEach(tile => { + tile.classList.add('disabled'); + }); + + // Re-enable controls + this.elements.betInput.disabled = false; + this.elements.minesSlider.disabled = false; + this.elements.minesDecrease.disabled = false; + this.elements.minesIncrease.disabled = false; + + // Update buttons + this.elements.cashoutBtn.classList.add('hidden'); + this.elements.startBtn.classList.remove('hidden'); + + // Add to history + this.addToHistory(isWin, winnings); + + // Show result modal + this.showResultModal(isWin, winnings); + + this.updateUI(); + } + + showResultModal(isWin, winnings) { + this.elements.modalContent.className = 'modal-content ' + (isWin ? 'win' : 'loss'); + + if (isWin) { + this.elements.modalIcon.textContent = '💎'; + this.elements.modalTitle.textContent = 'You Won!'; + this.elements.modalAmount.textContent = '+' + this.formatCurrency(winnings); + this.elements.modalSubtitle.textContent = `×${this.currentMultiplier.toFixed(2)} multiplier • ${this.revealedCount} tiles revealed`; + } else { + this.elements.modalIcon.textContent = '💣'; + this.elements.modalTitle.textContent = 'Mine Hit!'; + this.elements.modalAmount.textContent = '-' + this.formatCurrency(this.bet); + this.elements.modalSubtitle.textContent = `${this.revealedCount} tiles revealed before explosion`; + } + + this.elements.modal.classList.remove('hidden'); + } + + hideModal() { + this.elements.modal.classList.add('hidden'); + } + + addToHistory(isWin, winnings) { + const historyItem = { + isWin, + bet: this.bet, + winnings: isWin ? winnings : -this.bet, + multiplier: this.currentMultiplier, + mines: this.minesCount, + revealed: this.revealedCount + }; + + this.history.unshift(historyItem); + if (this.history.length > 20) this.history.pop(); + + this.renderHistory(); + } + + renderHistory() { + if (this.history.length === 0) { + this.elements.historyList.innerHTML = '
No rounds played yet
'; + return; + } + + this.elements.historyList.innerHTML = this.history.map(item => ` +
+
Bet: ${this.formatCurrency(item.bet)}
+
${item.isWin ? '+' : ''}${this.formatCurrency(item.winnings)}
+
×${item.multiplier.toFixed(2)} • ${item.mines} mines • ${item.revealed} revealed
+
+ `).join(''); + } +} + +// Initialize game when DOM is loaded +document.addEventListener('DOMContentLoaded', () => { + // You can change grid size here: 5, 6, 7, etc. + window.minesGame = new MinesGame({ gridSize: 5 }); +}); \ No newline at end of file