修改:检测代码里有没有方法 ‘_handle_run_analysis’ ,方法 ‘_handle_get_results’ ,没有的情况,根据代码的结构进行补充。(当模块收到子类界面的token里发送的“运行‘指令后就开始运行该模块(按照原来的方法进行)。。待分析数据完成,生成5注号码后回传数据到子类界面的token的相同标签的条目后面。)代码#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import uuid
import queue
import logging
import random
import numpy as np
import pandas as pd
import chardet
from typing import Dict, List, Tuple, Optional
import math
import threading
from collections import Counter, defaultdict
from threading import Lock
import time
# Global event center instance
event_center = None
# Utility functions
def map_positions_to_coords(position_matrix: Dict[str, str]) -> Dict[str, Tuple[int, int]]:
"""Map position strings to coordinate tuples"""
coords = {}
for num, pos in position_matrix.items():
row = int(pos[1:pos.find('c')])
col = int(pos[pos.find('c') + 1:])
coords[num] = (row, col)
return coords
def validate_numbers(num_list: List[int], min_val: int, max_val: int) -> bool:
"""Validate if numbers are within specified range"""
return all(min_val <= n <= max_val for n in num_list)
# Event system
class Event:
def __init__(self, event_id: str, event_type: str, source: str,
target: str = None, data: dict = None, token: str = None):
self.event_id = event_id
self.type = event_type
self.source = source
self.target = target
self.data = data or {}
self.token = token
class EventCenter:
_instance = None
_lock = Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._subscribers = defaultdict(list)
return cls._instance
def subscribe(self, event_type: str, token: str, callback):
with self._lock:
self._subscribers[(event_type, token)].append(callback)
def publish(self, event: Event):
with self._lock:
callbacks = self._subscribers.get((event.type, event.token), [])
for callback in callbacks:
callback(event)
# Global configuration
class GlobalConfig:
MODULE1_ID = "input_analysis"
MODULE2_ID = "combination_analysis"
MODULE3_ID = "follow_analysis"
MODULE4_ID = "trend_analysis"
MODULE5_ID = "number_generation"
class EventType:
COMMAND = "command"
DATA_RESULT = "data_result"
ERROR = "error"
# Position matrix configuration
FRONT_POSITION_MATRIX = {
'01': 'r4c3', '02': 'r3c3', '03': 'r3c4', '04': '极4c4', '05': 'r5c4',
'06': 'r5c3', '07': 'r5c2', '08': 'r4c2', '09': 'r3c2', '10': 'r2c2',
'11': 'r2c3', '12': 'r2c4', '13': 'r3c5', '14': 'r3c5', '15': 'r4c5',
'16': 'r5c5', '17': 'r6c5', '18': 'r6c4', '19': 'r6c3', '20': 'r6c2',
'21': 'r6c1', '22': 'r5c1', '23': 'r4c1', '24': 'r3c1', '25': 'r2c1',
'26': 'r1c1', '27': 'r1c2', '28': 'r1c3', '29': 'r1c4', '30': 'r1c5',
'31': 'r1c6', '32': 'r2c6', '33': 'r3c6', '34': 'r4c6', '35': 'r5c6'
}
BACK_POSITION_RANGES = {
'rows': ['r2', 'r3', 'r4', 'r5'],
'cols': ['c2', 'c3', 'c4']
}
# Configure logging
logging.basicConfig(
level=logging.WARNING,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
# Global event queues
channel_b = queue.Queue()
channel_c = queue.Queue()
# Initialize global event center
event_center = EventCenter()
class CorrelationMatrixAnalyzer:
def __init__(self, position_matrix: Dict[str, str]):
self.position_matrix = position_matrix
self.correlation_matrix: Dict[str, Dict[str, float]] = {}
self.position_coords = map_positions_to_coords(self.position_matrix)
def build_correlation_matrix(self, historical_data: pd.DataFrame):
num_keys = list(self.position_coords.keys())
self.correlation_matrix = {n: {m: 0.0 for m in num_keys} for n in num_keys}
# Co-occurrence frequency statistics
for _, row in historical_data.iterrows():
nums = [f"{n:02d}" for n in row['前区号码']]
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] in self.correlation_matrix and nums[j] in self.correlation_matrix:
self.correlation_matrix[nums[i]][nums[j]] += 1
self.correlation_matrix[nums[j]][nums[i]] += 1
# Position correlation enhancement
for n1 in num_keys:
for n2 in num_keys:
if n1 != n2:
coord1 = self.position_coords[n1]
coord2 = self.position_coords[n2]
distance = math.sqrt((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2)
self.correlation_matrix[n1][n2] *= (1 / (1 + distance))
# Normalization
max_val = max(max(row.values()) for row in self.correlation_matrix.values())
if max_val > 0:
for n1 in num_keys:
for n2 in num_keys:
self.correlation_matrix[n1][n2] /= max_val
def get_correlation(self, num1: int, num2: int) -> float:
"""Get correlation between two numbers"""
n1 = f"{num1:02d}"
n2 = f"{num2:02d}"
return self.correlation_matrix.get(n1, {}).get(n2, 0.0)
class LotteryDataAnalyzer:
def __init__(self, historical_data: pd.DataFrame):
self.df = historical_data
self.prime_numbers = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}
self.front_ranges = [(1, 5), (6, 10), (11, 15), (16, 20), (21, 25), (26, 30), (31, 35)]
def analyze_front(self) -> Dict:
"""Analyze front area numbers"""
data = self.df.tail(100)
return {
'sum_range': self._calc_sum_range(data),
'prime_ratio': self._calc_prime_ratio(data),
'odd_ratio': self._calc_odd_ratio(data),
'exclude_range': self._find_exclude_range(data),
'consecutive': self._has_consecutive(data),
'hot_cold': self._analyze_hot_cold(data, '前区号码')
}
def analyze_rear(self) -> Dict:
"""Analyze rear area numbers"""
data = self.df.tail(100)
return {
'span': self._calc_span(data),
'hot_cold': self._analyze_hot_cold(data, '后区号码')
}
@staticmethod
def _calc_sum_range(data: pd.DataFrame) -> List[int]:
sums = data['前区号码'].apply(sum)
avg, std = sums.mean(), sums.std()
return [
max(45, int(avg - std)),
int(avg - std / 2),
int(avg),
int(avg + std / 2),
min(135, int(avg + std))
]
def _calc_prime_ratio(self, data: pd.DataFrame) -> List[int]:
prime_counts = data['前区号码'].apply(lambda x: len(set(x) & self.prime_numbers))
ratio = prime_counts.mean() / 5
return [math.floor(ratio * 5), math.ceil(ratio * 5)]
@staticmethod
def _calc_odd_ratio(data: pd.DataFrame) -> List[int]:
odd_counts = data['前区号码'].apply(lambda x: sum(1 for n in x if n % 2 != 0))
ratio = odd_counts.mean() / 5
return [math.floor(ratio * 5), math.ceil(ratio * 5)]
def _find_exclude_range(self, data: pd.DataFrame) -> Tuple[int, int]:
range_counts = [0] * len(self.front_ranges)
for nums in data['前区号码']:
for idx, rng in enumerate(self.front_ranges):
if any(rng[0] <= n <= rng[1] for n in nums):
range_counts[idx] += 1
return self.front_ranges[range_counts.index(min(range_counts))]
@staticmethod
def _has_consecutive(data: pd.DataFrame) -> bool:
consecutive_counts = data['前区号码'].apply(
lambda x: sum(1 for i in range(4) if x[i + 1] - x[i] == 1))
return consecutive_counts.mean() > 0.5
@staticmethod
def _analyze_hot_cold(data: pd.DataFrame, area: str) -> Dict[str, List[int]]:
num_list = np.concatenate(data[area].values)
counts = Counter(num_list)
avg = sum(counts.values()) / len(counts)
hot = [n for n, c in counts.most_common(8) if c > avg * 1.2]
cold = [n for n, c in counts.items() if c < avg * 0.8]
if len(cold) < 3:
cold = [n for n, c in counts.most_common()[-3:]]
return {'hot': hot[:8], 'cold': cold[:3]}
@staticmethod
def _calc_span(data: pd.DataFrame) -> int:
spans = data['后区号码'].apply(lambda x: max(x) - min(x))
return spans.mode()[0]
class NumberGenerator:
def __init__(self, module_config: Optional[dict] = None):
config = module_config or {}
self.module_id = config.get('module_id', GlobalConfig.MODULE5_ID)
self.labels = config.get('labels', ['number_generation'])
self.lock = Lock()
self.position_matrix = FRONT_POSITION_MATRIX
self.position_coords = map_positions_to_coords(self.position_matrix)
self.correlation_matrix: Optional[Dict[str, Dict[str, float]]] = None
self._register_event_handlers()
def _register_event_handlers(self):
event_center.subscribe(
event_type=GlobalConfig.EventType.COMMAND,
token=self.module_id,
callback=self._handle_generation_command
)
def build_correlation_matrix(self, historical_data: pd.DataFrame):
num_keys = list(self.position_coords.keys())
self.correlation_matrix = {n: {m: 0.0 for m in num_keys} for n in num_keys}
for _, row in historical_data.iterrows():
nums = [f"{n:02d}" for n in row['前区号码']]
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] in self.correlation_matrix and nums[j] in self.correlation_matrix:
self.correlation_matrix[nums[i]][nums[j]] += 1
self.correlation_matrix[nums[j]][nums[i]] += 1
for n1 in num_keys:
for n2 in num_keys:
if n1 != n2:
coord1 = self.position_coords[n1]
coord2 = self.position_coords[n2]
distance = math.sqrt((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2)
self.correlation_matrix[n1][n2] *= (1 / (1 + distance))
max_val = max(max(row.values()) for row in self.correlation_matrix.values())
if max_val > 0:
for n1 in num_keys:
for n2 in num_keys:
self.correlation_matrix[n1][n2] /= max_val
def get_correlation(self, num1: int, num2: int) -> float:
n1 = f"{num1:02d}"
n2 = f"{num2:02d}"
return self.correlation_matrix.get(n1, {}).get(n2, 0.0) if self.correlation_matrix else 0.0
def _handle_generation_command(self, event: Event):
if not self._validate_command(event):
return
try:
with self.lock:
generated_numbers = self.generate_numbers(5)
self._send_results(
target_token=event.token,
numbers=generated_numbers,
labels=self.labels + event.data.get('labels', [])
)
except Exception as e:
logging.error(f"Generation failed: {str(e)}")
self._send_error(event.token, str(e))
def _validate_command(self, event: Event) -> bool:
return (event.token == self.module_id and
event.type == GlobalConfig.EventType.COMMAND and
event.data.get('action') == 'generate')
@staticmethod
def generate_numbers(n: int = 5) -> List[Tuple[List[int], List[int]]]:
"""Generate random lottery numbers"""
results = []
for _ in range(n):
front_nums = sorted(random.sample(range(1, 36), 5))
rear_nums = sorted(random.sample(range(1, 13), 2))
results.append((front_nums, rear_nums))
return results
def _send_results(self, target_token: str,
numbers: List[Tuple[List[int], List[int]]],
labels: List[str]):
result_event = Event(
event_id=str(uuid.uuid4()),
event_type=GlobalConfig.EventType.DATA_RESULT,
source=self.module_id,
target=GlobalConfig.MODULE5_ID,
data={'numbers': numbers, 'labels': labels},
token=target_token
)
event_center.publish(result_event)
def _send_error(self, target_token: str, error_msg: str):
error_event = Event(
event_id=str(uuid.uuid4()),
event_type=GlobalConfig.EventType.ERROR,
source=self.module_id,
target=GlobalConfig.MODULE5_ID,
data={'error': error_msg},
token=target_token
)
event_center.publish(error_event)
class NumberGeneratorCompat:
"""Compatibility layer for number generation"""
_instance = None
_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._module_config = kwargs.get('module_config', {})
return cls._instance
def __init__(self, module_config: Optional[Dict] = None):
if hasattr(self, '_generator'):
return
config = module_config or {
'module_id': GlobalConfig.MODULE5_ID,
'labels': ['compatibility_layer']
}
self._generator = NumberGenerator(config)
def get_generator(self) -> NumberGenerator:
return self._generator
@staticmethod
def generate(_data: Dict) -> List[Tuple[List[int], List[int]]]:
"""Generate random numbers (ignore unused parameter)"""
instance = NumberGeneratorCompat()
return instance._generator.generate_numbers(5)
class AdvancedLotteryGenerator:
def __init__(self, data_file: str):
self.data_file = data_file
self.df = self._load_data()
self.position_model = FRONT_POSITION_MATRIX
compat = NumberGeneratorCompat()
self.correlation_analyzer = compat.get_generator()
self.correlation_analyzer.build_correlation_matrix(self.df)
self.position_validity_cache = self._build_position_cache()
self.analyzer = LotteryDataAnalyzer(self.df)
self.module_data = {
'historical': self.analyzer.analyze_front(),
'module1': {'hot': [], 'cold': [], 'special': {}},
'module2': {'hot': [], 'cold': [], 'special': {}},
'module3': {'hot': [], 'cold': [], 'special': {}}
}
self._start_event_system()
def _load_data(self) -> pd.DataFrame:
if not os.path.exists(self.data_file):
raise FileNotFoundError(f"Data file not found: {self.data_file}")
with open(self.data_file, 'rb') as f:
encoding = chardet.detect(f.read())['encoding']
df = pd.read_csv(self.data_file, encoding=encoding)
df = df.rename(columns={
'开奖期号': 'issue',
'前区1': 'front1', '前区2': 'front2', '前区3': 'front3', '前区4': 'front4', '前区5': 'front5',
'后区1': 'rear1', '后区2': 'rear2'
})
df['前区号码'] = df[['front1', 'front2', 'front3', 'front4', 'front5']].values.tolist()
df['后区号码'] = df[['rear1', 'rear2']].values.tolist()
return df.drop_duplicates('issue')
def _build_position_cache(self) -> Dict[str, Dict[int, bool]]:
cache = {'front': {}, 'rear': {}}
for num_val in range(1, 36):
cache['front'][num_val] = f"{num_val:02d}" in self.position_model
rear_positions = []
for r in BACK_POSITION_RANGES['rows']:
for c in BACK_POSITION_RANGES['cols']:
rear_positions.append((int(r[1:]), int(c[1:])))
for num_val in range(1, 13):
cache['rear'][num_val] = num_val % len(rear_positions) in [c for _, c in rear_positions]
return cache
def _start_event_system(self):
def data_producer():
while True:
time.sleep(3)
module = random.choice(['module1', 'module2', 'module3'])
hot = random.sample(range(1, 36), random.randint(3, 6))
cold = random.sample(range(1, 36), random.randint(2, 4))
channel_b.put({
'module': module,
'hot': hot,
'cold': cold,
'special': {
'sum_range': [random.randint(80, 120)],
'prime_ratio': [random.randint(1, 3), random.randint(2, 4)],
'odd_ratio': [random.randint(1, 3), random.randint(2, 4)]
}
})
def event_listener():
while True:
try:
data = channel_b.get()
module = data['module']
if module in self.module_data:
self.module_data[module]['hot'] = list(set(
self.module_data[module]['hot'] + data['hot']))
self.module_data[module]['cold'] = list(set(
self.module_data[module]['cold'] + data['cold']))
for k, v in data['special'].items():
if k in self.module_data[module]['special']:
if isinstance(v, list):
self.module_data[module]['special'][k] = v
except Exception as e:
logging.error(f"Event processing error: {e}")
threading.Thread(target=data_producer, daemon=True).start()
threading.Thread(target=event_listener, daemon=True).start()
def generate_numbers(self, n: int = 5) -> List[Tuple[List[int], List[int]]]:
try:
combined_front = self._combine_front_data()
combined_rear = self.analyzer.analyze_rear()
candidates = []
for target_sum in combined_front['sum_range'][:5]:
for _ in range(n * 2):
front_nums = self._generate_front(target_sum, combined_front)
rear_nums = self._generate_rear(combined_rear)
if len(front_nums) == 5 and len(rear_nums) == 2:
candidates.append((front_nums, rear_nums))
valid = [c for c in candidates if self._validate_combination(c, combined_front, combined_rear)]
results = self._score_combinations(valid, combined_front)[:n]
if not results:
results = self._generate_backup(n)
return results
except Exception as e:
logging.error(f"Number generation error: {e}")
return self._generate_backup(n)
def _combine_front_data(self) -> Dict:
combined = {
'hot': [],
'cold': [],
'sum_range': [],
'prime_ratio': [1, 3],
'odd_ratio': [1, 4],
'exclude_range': (0, 0),
'consecutive': False
}
for module in self.module_data.values():
combined['hot'].extend(module.get('hot', []))
combined['cold'].extend(module.get('cold', []))
if 'sum_range' in module.get('special', {}):
combined['sum_range'].extend(module['special']['sum_range'])
if 'prime_ratio' in module.get('special', {}):
combined['prime_ratio'] = [
max(combined['prime_ratio'][0], module['special']['prime_ratio'][0]),
min(combined['prime_ratio'][1], module['special']['prime_ratio'][1])
]
if 'odd_ratio' in module.get('special', {}):
combined['odd_ratio'] = [
max(combined['odd_ratio'][0], module['special']['odd_ratio'][0]),
min(combined['odd_ratio'][1], module['special']['odd_ratio'][1])
]
if 'exclude_range' in module.get('special', {}):
combined['exclude_range'] = module['special']['exclude_range']
if 'consecutive' in module.get('special', {}):
combined['consecutive'] |= module['special']['consecutive']
combined['hot'] = list(set(combined['hot']))
combined['cold'] = list(set(combined['cold']))
if not combined['sum_range']:
combined['sum_range'] = self.module_data['historical']['sum_range']
return combined
def _generate_front(self, target_sum: int, analysis: Dict) -> List[int]:
valid_nums = [n for n in range(1, 36) if self.position_validity_cache['front'].get(n, False)]
hot_nums = [n for n in analysis['hot'] if n in valid_nums]
cold_nums = [n for n in analysis['cold'] if n in valid_nums]
for _ in range(100):
selected = []
if hot_nums:
selected.extend(random.sample(hot_nums, min(3, len(hot_nums))))
if cold_nums and len(selected) < 4:
selected.extend(random.sample(cold_nums, min(1, len(cold_nums))))
remaining = 5 - len(selected)
candidates = [n for n in valid_nums if n not in selected]
if remaining > 0 and candidates:
weights = [self._calc_number_weight(n, selected, analysis) for n in candidates]
selected.extend(random.choices(candidates, weights=weights, k=remaining))
selected = sorted(list(set(selected))[:5])
if len(selected) == 5 and abs(sum(selected) - target_sum) <= 5:
return selected
return random.sample(valid_nums, 5)
def _calc_number_weight(self, num: int, selected: List[int], analysis: Dict) -> float:
corr_weight = sum(self.correlation_analyzer.get_correlation(num, s) for s in selected) if selected else 1
hot_weight = 2 if num in analysis['hot'] else 0.5 if num in analysis['cold'] else 1
pos_key = f"{num:02d}"
pos_str = self.position_model.get(pos_key, 'r0c0')
row = int(pos_str[1:pos_str.find('c')])
col = int(pos_str[pos_str.find('c') + 1:])
pos_weight = 1 + (1 / (1 + row * col))
return corr_weight * hot_weight * pos_weight
def _generate_rear(self, analysis: Dict) -> List[int]:
valid_nums = [n for n in range(1, 13) if self.position_validity_cache['rear'].get(n, False)]
hot_nums = [n for n in analysis['hot_cold']['hot'] if n in valid_nums]
cold_nums = [n for n in analysis['hot_cold']['cold'] if n in valid_nums]
selected = random.sample(hot_nums, min(2, len(hot_nums))) if hot_nums else []
if len(selected) < 2 and cold_nums:
select_count = min(2 - len(selected), len(cold_nums))
selected.extend(random.sample(cold_nums, select_count))
if len(selected) < 2:
remaining = [n for n in valid_nums if n not in selected]
selected.extend(random.sample(remaining, 2 - len(selected)))
return sorted(selected)
def _validate_combination(self, combination: Tuple[List[int], List[int]],
front_analysis: Dict, rear_analysis: Dict) -> bool:
front_nums, rear_nums = combination
current_sum = sum(front_nums)
if not any(abs(current_sum - s) <= 5 for s in front_analysis['sum_range']):
return False
prime_count = len([n for n in front_nums if n in self.analyzer.prime_numbers])
if not (front_analysis['prime_ratio'][0] <= prime_count <= front_analysis['prime_ratio'][1]):
return False
odd_count = sum(1 for n in front_nums if n % 2 != 0)
if not (front_analysis['odd_ratio'][0] <= odd_count <= front_analysis['odd_ratio'][1]):
return False
has_consecutive = any(front_nums[i + 1] - front_nums[i] == 1 for i in range(4))
if front_analysis['consecutive'] != has_consecutive:
return False
rear_span = max(rear_nums) - min(rear_nums)
if rear_span not in [rear_analysis['span'] - 1, rear_analysis['span'], rear_analysis['span'] + 1]:
return False
return True
def _score_combinations(self, combinations: List[Tuple[List[int], List[int]]],
front_analysis: Dict) -> List[Tuple[float, Tuple[List[int], List[int]]]]:
scored = []
for front_nums, rear_nums in combinations:
score = 0
current_sum = sum(front_nums)
closest_sum = min(front_analysis['sum_range'], key=lambda x: abs(x - current_sum))
score += 10 - abs(current_sum - closest_sum)
corr_score = 0
for i in range(len(front_nums)):
for j in range(i + 1, len(front_nums)):
corr_score += self.correlation_analyzer.get_correlation(front_nums[i], front_nums[j])
score += corr_score / 10
positions = [self.position_model.get(f"{n:02d}", 'r0c0') for n in front_nums]
rows = [int(p[1:p.find('c')]) for p in positions]
cols = [int(p[p.find('c') + 1:]) for p in positions]
row_std = np.std(rows)
col_std = np.std(cols)
score += 5 / (1 + row_std + col_std)
scored.append((score, (front_nums, rear_nums)))
return sorted(scored, reverse=True, key=lambda x: x[0])
def _generate_backup(self, n: int) -> List[Tuple[List[int], List[int]]]:
valid_front = [n for n in range(1, 36) if self.position_validity_cache['front'].get(n, False)]
valid_rear = [n for n in range(1, 13) if self.position_validity_cache['rear'].get(n, False)]
results = []
for _ in range(n):
front_nums = sorted(random.sample(valid_front, 5))
rear_nums = sorted(random.sample(valid_rear, 2))
results.append((front_nums, rear_nums))
return results
if __name__ == "__main__":
generator = AdvancedLotteryGenerator('historical_data.csv')
number_list = generator.generate_numbers(5)
for idx, (front, rear) in enumerate(number_list, 1):
print(f"Group {idx}: Front {front} Rear {rear} (Sum:{sum(front)})")
# Ensure newline at end of file
print()