// Global state let bankroll = 10000.00; let currentPredictions = []; let topNumbers = []; let spinResult = null; let selectedNumber = null; let lastFetchedResults = []; // DOM Elements const predictionsContainer = document.getElementById('predictions-container'); const topNumbersList = document.getElementById('top-numbers-list'); const bankrollValue = document.getElementById('bankroll-value'); const betAmountEl = document.getElementById('bet-amount'); const betTargetEl = document.getElementById('bet-target'); const fetchButton = document.getElementById('fetch-button'); // Initialize the app document.addEventListener('DOMContentLoaded', () => { generateMockData(); renderPredictions(); renderTopNumbers(); renderOracleStatus(); updateBankrollDisplay(); // Event listeners fetchButton.addEventListener('click', fetchLatestResults); }); // Fetch latest results from the roulette game async function fetchLatestResults() { fetchButton.disabled = true; fetchButton.textContent = 'Fetching...'; try { // Simulate fetching results (in a real implementation, this would call the Python backend) const response = await fetch('/api/fetch-results'); const data = await response.json(); if (data.success && data.results && data.results.length > 0) { // Process the latest result (first in array since they're ordered newest first) const latestResult = data.results[0]; recordSpinResult(latestResult); // Store results for reference lastFetchedResults = data.results; // Show notification showNotification(`Fetched result: ${latestResult}`, 'success'); } else { showNotification('No new results found', 'info'); } } catch (error) { console.error('Error fetching results:', error); showNotification('Failed to fetch results', 'error'); } finally { fetchButton.disabled = false; fetchButton.textContent = 'Fetch Latest Results'; } } // Show notification message function showNotification(message, type = 'info') { // Remove any existing notifications const existingNotification = document.querySelector('.notification'); if (existingNotification) { existingNotification.remove(); } const notification = document.createElement('div'); notification.className = `notification fixed top-4 right-4 px-6 py-4 rounded-lg shadow-lg z-50 transform transition-transform duration-300 ${ type === 'success' ? 'bg-green-600' : type === 'error' ? 'bg-red-600' : 'bg-blue-600' }`; notification.textContent = message; document.body.appendChild(notification); // Auto remove after 3 seconds setTimeout(() => { notification.style.transform = 'translateX(150%)'; setTimeout(() => { notification.remove(); }, 300); }, 3000); } // Generate mock data for demonstration function generateMockData() { // Generate mock predictions currentPredictions = []; const predictionCount = 20; for (let i = 0; i < predictionCount; i++) { const number = Math.floor(Math.random() * 37); const predictors = Math.floor(Math.random() * 15) + 1; currentPredictions.push({ number, predictors }); } // Sort by predictor count descending currentPredictions.sort((a, b) => b.predictors - a.predictors); // Generate top 12 numbers topNumbers = currentPredictions.slice(0, 12); // Calculate recommended bet calculateRecommendedBet(); } // Render predictions function renderPredictions() { predictionsContainer.innerHTML = ''; currentPredictions.forEach((pred, index) => { const card = document.createElement('custom-prediction-card'); card.prediction = pred; card.rank = index + 1; predictionsContainer.appendChild(card); }); } // Render top numbers function renderTopNumbers() { topNumbersList.innerHTML = ''; topNumbers.forEach((pred, index) => { const topNumber = document.createElement('custom-top-number'); topNumber.prediction = pred; topNumber.rank = index + 1; topNumbersList.appendChild(topNumber); }); } // Render oracle status indicators function renderOracleStatus() { const container = document.querySelector('.grid.grid-cols-2.md\\:grid-cols-4.lg\\:grid-cols-7'); container.innerHTML = ''; // Create 70 oracle indicators for (let i = 1; i <= 70; i++) { const indicator = document.createElement('custom-oracle-indicator'); indicator.oracle = { id: i, active: Math.random() > 0.3, accuracy: Math.floor(Math.random() * 100) }; container.appendChild(indicator); } } // Calculate recommended bet using Kelly criterion function calculateRecommendedBet() { if (topNumbers.length === 0) return; // Get the top prediction const topPrediction = topNumbers[0]; // Kelly fractions based on rank (simplified for demo) const kellyFractions = [ 0.0619, 0.0237, 0.000902, 0.00035, 0.000133, 0.0005, 0.0002, 0.000074, 0.000029, 0.000011, 0.0000041, 0.0000026 ]; // Get fraction for top prediction (default to smallest if beyond top 12) const fraction = topNumbers.indexOf(topPrediction) < 12 ? kellyFractions[topNumbers.indexOf(topPrediction)] : 0.0000026; const betAmount = bankroll * fraction; betAmountEl.textContent = betAmount.toFixed(2); betTargetEl.textContent = `#${topPrediction.number}`; } // Update bankroll display function updateBankrollDisplay() { bankrollValue.textContent = bankroll.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ","); } // Record spin result and update bankroll function recordSpinResult(number) { spinResult = number; // Check if we had a bet on this number const topPrediction = topNumbers[0]; const betAmount = parseFloat(betAmountEl.textContent); if (topPrediction && topPrediction.number === number && betAmount > 0) { // Win! 35:1 payout bankroll += betAmount * 35; showNotification(`WIN! +${(betAmount * 35).toFixed(2)} on number ${number}`, 'success'); } else if (betAmount > 0) { // Loss bankroll -= betAmount; showNotification(`Loss of ${betAmount.toFixed(2)}`, 'error'); } // Update display updateBankrollDisplay(); // Regenerate predictions for next spin setTimeout(() => { generateMockData(); renderPredictions(); renderTopNumbers(); calculateRecommendedBet(); }, 500); }