// ==UserScript== // @name 综合彩票助手 // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 涵盖福彩、体彩、竞彩的综合彩票助手,支持开奖查询、投注计算、走势分析、缩水过滤等功能 // @author 彩票助手 // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_registerMenuCommand // @connect * // @require https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js // @license MIT // ==/UserScript== (function() { 'use strict'; // ==================== 配置 ==================== const CONFIG = { colors: { primary: '#e74c3c', secondary: '#3498db', success: '#27ae60', warning: '#f39c12', info: '#9b59b6', background: '#1a1a2e', cardBg: '#16213e', text: '#eee' }, storageKey: 'lotteryHelperData' }; // ==================== 彩票类型定义 ==================== const LOTTERY_TYPES = { // 福利彩票 welfare: [ { id: 'ssq', name: '双色球', redCount: 33, redPick: 6, blueCount: 16, bluePick: 1 }, { id: 'fc3d', name: '福彩3D', type: 'digital', digits: 3, maxNum: 10 }, { id: 'qlc', name: '七乐彩', ballCount: 30, pickCount: 7 }, { id: 'ks', name: '快3', type: 'k3', maxNum: 6, diceCount: 3 } ], // 体育彩票 sports: [ { id: 'dlt', name: '大乐透', frontCount: 35, frontPick: 5, backCount: 12, backPick: 2 }, { id: 'qxc', name: '七星彩', ballCount: 10, pickCount: 7, special: true }, { id: 'pl3', name: '排列三', type: 'digital', digits: 3, maxNum: 10 }, { id: 'pl5', name: '排列五', digits: 5, maxNum: 10 }, { id: 'x115', name: '11选5', maxNum: 11, pickCount: 5 } ], // 竞彩 lottery: [ { id: 'jczq', name: '竞彩足球', category: 'sport' }, { id: 'jclq', name: '竞彩篮球', category: 'sport' } ] }; // ==================== 工具函数 ==================== const Utils = { // 生成随机数 randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }, // 生成随机号码 generateRandomNumbers(max, count, exclude = []) { const numbers = []; while (numbers.length < count) { const num = this.randomInt(1, max); if (!numbers.includes(num) && !exclude.includes(num)) { numbers.push(num); } } return numbers.sort((a, b) => a - b); }, // 计算注数 calculateBets(total, pick) { return this.combination(total, pick); }, // 计算组合数 combination(n, r) { if (r > n) return 0; if (r === 0 || r === n) return 1; let result = 1; for (let i = 0; i < r; i++) { result = result * (n - i) / (i + 1); } return Math.round(result); }, // 金额格式化 formatMoney(num) { return num.toLocaleString('zh-CN'); }, // 获取颜色 getColor(index, type = 'red') { if (type === 'red') { const colors = ['#ff6b6b', '#ee5a5a', '#ff4757', '#c0392b', '#e74c3c']; return colors[index % colors.length]; } else if (type === 'blue') { const colors = ['#5dade2', '#3498db', '#2980b9', '#1f618d', '#2471a3']; return colors[index % colors.length]; } return '#fff'; }, // 格式化日期 formatDate(date) { const d = new Date(date); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; } }; // ==================== 历史数据管理 ==================== class LotteryData { constructor() { this.data = this.load(); } load() { const stored = GM_getValue(CONFIG.storageKey, null); return stored || this.getDefaultData(); } save() { GM_setValue(CONFIG.storageKey, this.data); } getDefaultData() { return { ssq: this.generateHistoricalData('ssq', 100), dlt: this.generateHistoricalData('dlt', 100), fc3d: this.generateHistoricalData('fc3d', 100), jczq: [], jclq: [], favorites: [], notes: [] }; } generateHistoricalData(type, count) { const history = []; const now = new Date(); if (type === 'ssq') { for (let i = 0; i < count; i++) { const date = new Date(now - i * 3 * 24 * 60 * 60 * 1000); history.push({ issue: `20${24 - Math.floor(i / 100)}-${String(1000 + count - i).slice(1)}`, date: Utils.formatDate(date), red: Utils.generateRandomNumbers(33, 6), blue: [Utils.randomInt(1, 16)] }); } } else if (type === 'dlt') { for (let i = 0; i < count; i++) { const date = new Date(now - i * 3 * 24 * 60 * 60 * 1000); history.push({ issue: `24${String(1000 + count - i).slice(1)}`, date: Utils.formatDate(date), front: Utils.generateRandomNumbers(35, 5), back: Utils.generateRandomNumbers(12, 2) }); } } else if (type === 'fc3d') { for (let i = 0; i < count; i++) { const date = new Date(now - i * 24 * 60 * 60 * 1000); history.push({ issue: `20${24 - Math.floor(i / 100)}${String(1000 + count - i).slice(1)}`, date: Utils.formatDate(date), numbers: [Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9)], sum: Utils.randomInt(0, 27) }); } } return history; } addToFavorites(lotteryType, numbers, note = '') { this.data.favorites.push({ id: Date.now(), type: lotteryType, numbers: numbers, note: note, createdAt: new Date().toISOString() }); this.save(); } removeFavorite(id) { this.data.favorites = this.data.favorites.filter(f => f.id !== id); this.save(); } addNote(text) { this.data.notes.push({ id: Date.now(), text: text, createdAt: new Date().toISOString() }); this.save(); } } // ==================== 缩水过滤器 ==================== class NumberFilter { static filter(numbers, options) { let result = numbers; // 奇偶比例过滤 if (options.oddEvenRatio) { result = result.filter(nums => { const oddCount = nums.filter(n => n % 2 === 1).length; const evenCount = nums.length - oddCount; return oddCount >= options.oddEvenMin && oddCount <= options.oddEvenMax; }); } // 和值过滤 if (options.sumRange) { result = result.filter(nums => { const sum = nums.reduce((a, b) => a + b, 0); return sum >= options.sumMin && sum <= options.sumMax; }); } // 连号过滤 if (options.noConsecutive) { result = result.filter(nums => { for (let i = 0; i < nums.length - 1; i++) { if (nums[i + 1] - nums[i] === 1) return false; } return true; }); } // 跨度过滤 if (options.spanRange) { result = result.filter(nums => { const span = Math.max(...nums) - Math.min(...nums); return span >= options.spanMin && span <= options.spanMax; }); } // AC值过滤 if (options.acValue) { result = result.filter(nums => { const ac = this.calculateAC(nums); return ac >= options.acMin && ac <= options.acMax; }); } return result; } static calculateAC(numbers) { const sorted = [...numbers].sort((a, b) => a - b); const diffs = []; for (let i = 0; i < sorted.length - 1; i++) { for (let j = i + 1; j < sorted.length; j++) { diffs.push(sorted[j] - sorted[i]); } } return new Set(diffs).size - (numbers.length - 1); } static generateCombinations(redMax, redCount, blueMax = 16) { const combinations = []; const redBalls = []; const generateRed = (start, count) => { if (count === 0) { const blue = Utils.generateRandomNumbers(blueMax, 1); combinations.push({ red: [...redBalls].sort((a, b) => a - b), blue: blue }); return; } for (let i = start; i <= redMax - count + 1; i++) { redBalls.push(i); generateRed(i + 1, count - 1); redBalls.pop(); } }; generateRed(1, redCount); return combinations; } } // ==================== 奖金计算器 ==================== class PrizeCalculator { static calculateSSQ(red, blue, winRed, winBlue) { let prize = 0; let level = '未中奖'; const matchRed = red.filter(n => winRed.includes(n)).length; const matchBlue = blue[0] === winBlue[0]; if (matchBlue && matchRed === 6) { prize = 10000000; level = '一等奖'; } else if (matchRed === 6) { prize = 500000; level = '二等奖'; } else if (matchBlue && matchRed === 5) { prize = 3000; level = '三等奖'; } else if (matchRed === 5 || (matchBlue && matchRed === 4)) { prize = 200; level = '四等奖'; } else if (matchRed === 4 || (matchBlue && matchRed === 3)) { prize = 10; level = '五等奖'; } else if (matchBlue || matchRed === 3) { prize = 5; level = '六等奖'; } return { prize, level, matchRed, matchBlue }; } static calculateDLT(front, back, winFront, winBack) { let prize = 0; let level = '未中奖'; const matchFront = front.filter(n => winFront.includes(n)).length; const matchBack = back.filter(n => winBack.includes(n)).length; if (matchFront === 5 && matchBack === 2) { prize = 10000000; level = '一等奖'; } else if (matchFront === 5 && matchBack === 1) { prize = 10000000; level = '一等奖(追加)'; } else if (matchFront === 5 || (matchFront === 4 && matchBack === 2)) { prize = matchBack === 2 ? 500000 : 200; level = matchBack === 2 ? '二等奖' : '四等奖'; } else if (matchFront === 4 || (matchFront === 3 && matchBack === 2)) { prize = matchBack === 2 ? 300 : 100; level = matchBack === 2 ? '四等奖' : '六等奖'; } else if (matchFront === 3 || (matchFront === 2 && matchBack === 2)) { prize = matchBack === 2 ? 200 : 15; level = matchBack === 2 ? '五等奖' : '九等奖'; } else if (matchFront === 2 || (matchFront === 1 && matchBack === 2)) { prize = matchBack === 2 ? 200 : 5; level = matchBack === 2 ? '六等奖' : '九等奖'; } else if (matchBack === 2) { prize = 15; level = '八等奖'; } else if (matchBack === 1) { prize = 5; level = '九等奖'; } return { prize, level, matchFront, matchBack }; } } // ==================== 走势分析 ==================== class TrendAnalyzer { static analyzeMissing(history, maxNum) { const missing = new Array(maxNum + 1).fill(0); const lastAppear = new Array(maxNum + 1).fill(-1); history.forEach((item, index) => { let numbers = []; if (item.red) numbers = item.red; else if (item.front) numbers = [...item.front, ...item.back]; else if (item.numbers) numbers = item.numbers; numbers.forEach(n => { missing[n] = 0; if (lastAppear[n] === -1) lastAppear[n] = index; }); for (let i = 1; i <= maxNum; i++) { if (!numbers.includes(i)) { missing[i]++; } } }); return { missing, lastAppear }; } static analyzeHotCold(history, maxNum, recentCount = 30) { const recent = history.slice(0, recentCount); const frequency = new Array(maxNum + 1).fill(0); recent.forEach(item => { let numbers = []; if (item.red) numbers = item.red; else if (item.front) numbers = [...item.front, ...item.back]; else if (item.numbers) numbers = item.numbers; numbers.forEach(n => { if (n <= maxNum) frequency[n]++; }); }); const sorted = frequency.map((f, i) => ({ num: i, freq: f })) .sort((a, b) => b.freq - a.freq); return { hot: sorted.slice(0, 10), cold: sorted.slice(-10).reverse(), frequency }; } static analyzeSum(history) { const sums = {}; history.forEach(item => { let numbers = []; if (item.red) numbers = [...item.red, ...item.blue]; else if (item.front) numbers = [...item.front, ...item.back]; else if (item.numbers) numbers = item.numbers; const sum = numbers.reduce((a, b) => a + b, 0); sums[sum] = (sums[sum] || 0) + 1; }); return sums; } } // ==================== UI组件 ==================== class LotteryUI { constructor() { this.lotteryData = new LotteryData(); this.currentLottery = 'ssq'; this.isVisible = false; this.init(); } init() { // 创建主面板 this.createPanel(); // 注册菜单 GM_registerMenuCommand('📊 打开彩票助手', () => this.toggle()); // 监听快捷键 document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.shiftKey && e.key === 'L') { this.toggle(); } }); } createPanel() { const panel = document.createElement('div'); panel.id = 'lottery-helper-panel'; panel.innerHTML = `
综合彩票助手 v1.0.0
涵盖福利彩票、体育彩票、竞彩足球/篮球
功能包括:
• 智能机选
• 奖金计算
• 走势分析
• 缩水过滤
• 收藏管理
快捷键:Ctrl+Shift+L 打开/关闭
红球 (33选6)
蓝球 (16选1)
`; break; case 'dlt': html = `前区 (35选5)
后区 (12选2)
`; break; case 'fc3d': case 'pl3': html = `百位
十位
个位
`; break; default: html = `该彩种暂不支持手动选号
`; } container.innerHTML = html; // 生成号码球 if (type === 'ssq') { this.createNumberBalls('manual-red', 33, 'red', 6); this.createNumberBalls('manual-blue', 16, 'blue', 1); } else if (type === 'dlt') { this.createNumberBalls('manual-front', 35, 'red', 5); this.createNumberBalls('manual-back', 12, 'blue', 2); } else if (type === 'fc3d' || type === 'pl3') { this.createNumberBalls('manual-d1', 10, 'green', 1); this.createNumberBalls('manual-d2', 10, 'green', 1); this.createNumberBalls('manual-d3', 10, 'green', 1); } // 初始化计算器 this.initCalculator(); } createNumberBalls(containerId, max, colorClass, maxSelect) { const container = document.getElementById(containerId); for (let i = 1; i <= max; i++) { const ball = document.createElement('div'); ball.className = `lh-number-ball ${colorClass}`; ball.textContent = String(i).padStart(2, '0'); ball.dataset.num = i; ball.addEventListener('click', () => this.toggleBall(ball, containerId, maxSelect)); container.appendChild(ball); } } toggleBall(ball, containerId, maxSelect) { const container = document.getElementById(containerId); const selected = container.querySelectorAll('.selected'); if (ball.classList.contains('selected')) { ball.classList.remove('selected'); ball.style.transform = ''; } else { if (selected.length >= maxSelect) { selected[0].classList.remove('selected'); selected[0].style.transform = ''; } ball.classList.add('selected'); ball.style.transform = 'scale(1.2)'; } } clearManualNumbers() { document.querySelectorAll('.lh-number-ball.selected').forEach(ball => { ball.classList.remove('selected'); ball.style.transform = ''; }); } randomGenerate(count) { const container = document.getElementById('generated-numbers'); let html = ''; for (let i = 0; i < count; i++) { const numbers = this.generateRandom(this.currentLottery); html += this.renderNumbers(numbers, i + 1); } container.innerHTML = html; this.updateStats(); } generateRandom(type) { switch(type) { case 'ssq': return { red: Utils.generateRandomNumbers(33, 6), blue: Utils.generateRandomNumbers(16, 1) }; case 'dlt': return { front: Utils.generateRandomNumbers(35, 5), back: Utils.generateRandomNumbers(12, 2) }; case 'fc3d': case 'pl3': return { numbers: [Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9)] }; case 'pl5': return { numbers: [Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9), Utils.randomInt(0, 9)] }; case 'x115': return { numbers: Utils.generateRandomNumbers(11, 5) }; default: return { numbers: [] }; } } renderNumbers(numbers, index) { const type = this.currentLottery; if (type === 'ssq') { return `最热号码
最冷号码