Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>CodeCover Quest | Pattern Analysis</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap'); | |
| body { | |
| font-family: 'Space Grotesk', sans-serif; | |
| } | |
| .gradient-bg { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| } | |
| .code-block { | |
| background-color: rgba(15, 23, 42, 0.7); | |
| backdrop-filter: blur(10px); | |
| } | |
| .pattern-cell { | |
| font-family: 'Courier New', monospace; | |
| } | |
| .highlight { | |
| background-color: rgba(255, 255, 0, 0.2); | |
| } | |
| </style> | |
| </head> | |
| <body class="gradient-bg min-h-screen text-white"> | |
| <div id="vanta-net" class="fixed inset-0 z-0"></div> | |
| <div class="relative z-10 container mx-auto px-4 py-16"> | |
| <header class="mb-8"> | |
| <h1 class="text-4xl md:text-5xl font-bold mb-2 tracking-tight">Pattern Analysis</h1> | |
| <p class="text-lg opacity-90">Top combinatorial patterns for optimal coverage</p> | |
| <nav class="mt-4 flex space-x-4"> | |
| <a href="/" class="text-white opacity-80 hover:opacity-100">← Back to Home</a> | |
| <a href="/weighted-coverings.html" class="text-white opacity-80 hover:opacity-100">Weighted Coverings →</a> | |
| </nav> | |
| </header> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8"> | |
| <div class="code-block rounded-xl p-4"> | |
| <h3 class="font-bold mb-2 flex items-center"> | |
| <i data-feather="filter" class="mr-2"></i> Filter | |
| </h3> | |
| <input type="text" id="patternFilter" placeholder="Search patterns..." class="w-full bg-gray-800 text-white rounded px-3 py-2 mb-2"> | |
| <div class="flex items-center mb-2"> | |
| <input type="checkbox" id="showHighProb" class="mr-2" checked> | |
| <label for="showHighProb">High Probability</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="showLowInv" class="mr-2" checked> | |
| <label for="showLowInv">Low 1/Probability</label> | |
| </div> | |
| </div> | |
| <div class="code-block rounded-xl p-4"> | |
| <h3 class="font-bold mb-2 flex items-center"> | |
| <i data-feather="bar-chart-2" class="mr-2"></i> Stats | |
| </h3> | |
| <div class="mb-1">Total Patterns: <span id="totalPatterns" class="font-bold">0</span></div> | |
| <div class="mb-1">Showing: <span id="showingPatterns" class="font-bold">0</span></div> | |
| <div>Avg Probability: <span id="avgProb" class="font-bold">0.00</span></div> | |
| </div> | |
| <div class="code-block rounded-xl p-4"> | |
| <h3 class="font-bold mb-2 flex items-center"> | |
| <i data-feather="info" class="mr-2"></i> Legend | |
| </h3> | |
| <div class="flex items-center mb-1"> | |
| <div class="w-3 h-3 bg-green-500 mr-2"></div> | |
| <span>Highest 10%</span> | |
| </div> | |
| <div class="flex items-center mb-1"> | |
| <div class="w-3 h-3 bg-yellow-500 mr-2"></div> | |
| <span>Middle 80%</span> | |
| </div> | |
| <div class="flex items-center"> | |
| <div class="w-3 h-3 bg-red-500 mr-2"></div> | |
| <span>Lowest 10%</span> | |
| </div> | |
| </div> | |
| <div class="code-block rounded-xl p-4"> | |
| <h3 class="font-bold mb-2 flex items-center"> | |
| <i data-feather="download" class="mr-2"></i> Export | |
| </h3> | |
| <button id="exportCSV" class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded mb-2"> | |
| Export to CSV | |
| </button> | |
| <button id="exportJSON" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-2 px-4 rounded"> | |
| Export to JSON | |
| </button> | |
| </div> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="w-full code-block rounded-xl overflow-hidden"> | |
| <thead> | |
| <tr class="bg-gray-900"> | |
| <th class="py-3 px-4 text-left">Pattern</th> | |
| <th class="py-3 px-4 text-right">Probability</th> | |
| <th class="py-3 px-4 text-right">1/Prob</th> | |
| <th class="py-3 px-4 text-left">A</th> | |
| <th class="py-3 px-4 text-left">B</th> | |
| <th class="py-3 px-4 text-left">C</th> | |
| <th class="py-3 px-4 text-left">D</th> | |
| </tr> | |
| </thead> | |
| <tbody id="patternTable"> | |
| <!-- Patterns will be loaded here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="text-center mt-8"> | |
| <button id="loadMore" class="px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-full"> | |
| <i data-feather="plus-circle" class="mr-2 inline"></i> | |
| Load More Patterns | |
| </button> | |
| </div> | |
| </div> | |
| <script> | |
| // Initialize Vanta.js effect | |
| VANTA.NET({ | |
| el: "#vanta-net", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x7d5fff, | |
| backgroundColor: 0x0, | |
| points: 10.00, | |
| maxDistance: 22.00 | |
| }); | |
| // Initialize table with sample data | |
| function loadPatterns(patterns) { | |
| const table = document.getElementById('patternTable'); | |
| table.innerHTML = ''; | |
| patterns.forEach((p, index) => { | |
| const row = document.createElement('tr'); | |
| row.className = index % 2 === 0 ? 'bg-gray-800 bg-opacity-50' : 'bg-gray-800 bg-opacity-70'; | |
| // Determine color class based on probability percentile | |
| let colorClass = ''; | |
| if (index < patterns.length * 0.1) { | |
| colorClass = 'text-green-400'; | |
| } else if (index >= patterns.length * 0.9) { | |
| colorClass = 'text-red-400'; | |
| } else { | |
| colorClass = 'text-yellow-400'; | |
| } | |
| row.innerHTML = ` | |
| <td class="py-3 px-4 pattern-cell ${colorClass} font-mono">${p.pattern}</td> | |
| <td class="py-3 px-4 text-right font-mono">${p.prob.toExponential(4)}</td> | |
| <td class="py-3 px-4 text-right font-mono">${p.invProb}</td> | |
| <td class="py-3 px-4 text-center">${p.a}</td> | |
| <td class="py-3 px-4 text-center">${p.b}</td> | |
| <td class="py-3 px-4 text-center">${p.c}</td> | |
| <td class="py-3 px-4 text-center">${p.d}</td> | |
| `; | |
| table.appendChild(row); | |
| }); | |
| document.getElementById('totalPatterns').textContent = patterns.length; | |
| document.getElementById('showingPatterns').textContent = patterns.length; | |
| // Calculate average probability (weighted geometric mean) | |
| const logAvg = patterns.reduce((sum, p) => sum + Math.log(p.prob), 0) / patterns.length; | |
| document.getElementById('avgProb').textContent = Math.exp(logAvg).toExponential(4); | |
| } | |
| // Load patterns from API endpoint | |
| async function fetchPatterns() { | |
| try { | |
| const response = await fetch('/api/patterns'); | |
| if (!response.ok) throw new Error('Failed to fetch patterns'); | |
| const patterns = await response.json(); | |
| loadPatterns(patterns); | |
| } catch (error) { | |
| console.error('Error loading patterns:', error); | |
| // Fallback to sample data | |
| const samplePatterns = [ | |
| { pattern: "0(12)111(02)0010", prob: 0.045678, invProb: 22, a: 40, b: 13, c: 40, d: 4 }, | |
| { pattern: "1(02)010(12)1101", prob: 0.038912, invProb: 26, a: 71, b: 35, c: 98, d: 17 } | |
| ]; | |
| loadPatterns(samplePatterns); | |
| } | |
| } | |
| // Initialize with API data | |
| fetchPatterns(); | |
| // Export functionality | |
| document.getElementById('exportCSV').addEventListener('click', () => { | |
| const patterns = Array.from(document.querySelectorAll('#patternTable tr')).map(row => { | |
| return Array.from(row.querySelectorAll('td')).map(td => td.textContent).join(','); | |
| }); | |
| const csvContent = "data:text/csv;charset=utf-8," + patterns.join("\n"); | |
| const encodedUri = encodeURI(csvContent); | |
| const link = document.createElement("a"); | |
| link.setAttribute("href", encodedUri); | |
| link.setAttribute("download", "patterns.csv"); | |
| document.body.appendChild(link); | |
| link.click(); | |
| }); | |
| document.getElementById('exportJSON').addEventListener('click', () => { | |
| const patterns = Array.from(document.querySelectorAll('#patternTable tr')).map(row => { | |
| const cells = Array.from(row.querySelectorAll('td')); | |
| return { | |
| pattern: cells[0].textContent, | |
| probability: parseFloat(cells[1].textContent), | |
| invProbability: parseInt(cells[2].textContent), | |
| a: parseInt(cells[3].textContent), | |
| b: parseInt(cells[4].textContent), | |
| c: parseInt(cells[5].textContent), | |
| d: parseInt(cells[6].textContent) | |
| }; | |
| }); | |
| const jsonContent = "data:text/json;charset=utf-8," + JSON.stringify(patterns, null, 2); | |
| const encodedUri = encodeURI(jsonContent); | |
| const link = document.createElement("a"); | |
| link.setAttribute("href", encodedUri); | |
| link.setAttribute("download", "patterns.json"); | |
| document.body.appendChild(link); | |
| link.click(); | |
| }); | |
| // Filter functionality | |
| document.getElementById('patternFilter').addEventListener('input', (e) => { | |
| const filter = e.target.value.toLowerCase(); | |
| const rows = document.querySelectorAll('#patternTable tr'); | |
| rows.forEach(row => { | |
| const pattern = row.querySelector('td:first-child').textContent.toLowerCase(); | |
| row.style.display = pattern.includes(filter) ? '' : 'none'; | |
| }); | |
| updateShowingCount(); | |
| }); | |
| function updateShowingCount() { | |
| const showing = document.querySelectorAll('#patternTable tr:not([style*="none"])').length; | |
| document.getElementById('showingPatterns').textContent = showing; | |
| } | |
| // Feather icons | |
| feather.replace(); | |
| </script> | |
| </body> | |
| </html> |