from typing import Dict import numpy as np from collections import defaultdict from sqlalchemy.orm import Session from ..models.lottery import SSQLottery, DLTLottery class AdvancedAnalysisService: def __init__(self, db: Session): self.db = db def get_missing_value_analysis(self, lottery_type: str, periods: int = 100) -> Dict: model = SSQLottery if lottery_type == 'ssq' else DLTLottery recent_draws = self.db.query(model).order_by( model.open_time.desc()).limit(periods).all() if lottery_type == 'ssq': red_range = 33 blue_range = 16 else: red_range = 35 blue_range = 12 red_missing = {i: 0 for i in range(1, red_range + 1)} blue_missing = {i: 0 for i in range(1, blue_range + 1)} for draw in reversed(recent_draws): if lottery_type == 'ssq': red_numbers = [draw.red_ball_1, draw.red_ball_2, draw.red_ball_3, draw.red_ball_4, draw.red_ball_5, draw.red_ball_6] blue_numbers = [draw.blue_ball] else: red_numbers = [draw.front_ball_1, draw.front_ball_2, draw.front_ball_3, draw.front_ball_4, draw.front_ball_5] blue_numbers = [draw.back_ball_1, draw.back_ball_2] for num in range(1, red_range + 1): if num not in red_numbers: red_missing[num] += 1 for num in range(1, blue_range + 1): if num not in blue_numbers: blue_missing[num] += 1 return { 'red_missing': red_missing, 'blue_missing': blue_missing, 'max_red_missing': max(red_missing.values()), 'max_blue_missing': max(blue_missing.values()), 'avg_red_missing': sum(red_missing.values()) / len(red_missing), 'avg_blue_missing': sum(blue_missing.values()) / len(blue_missing) } def get_sum_value_analysis(self, lottery_type: str, periods: int = 100) -> Dict: model = SSQLottery if lottery_type == 'ssq' else DLTLottery recent_draws = self.db.query(model).order_by( model.open_time.desc()).limit(periods).all() sums = [] for draw in recent_draws: if lottery_type == 'ssq': red_numbers = [draw.red_ball_1, draw.red_ball_2, draw.red_ball_3, draw.red_ball_4, draw.red_ball_5, draw.red_ball_6] else: red_numbers = [draw.front_ball_1, draw.front_ball_2, draw.front_ball_3, draw.front_ball_4, draw.front_ball_5] sums.append(sum(red_numbers)) sum_distribution = defaultdict(int) for s in sums: sum_distribution[s] += 1 return { 'sums': sums, 'sum_distribution': dict(sum_distribution), 'min_sum': min(sums), 'max_sum': max(sums), 'avg_sum': float(np.mean(sums)), 'median_sum': float(np.median(sums)), 'std_sum': float(np.std(sums)), 'most_common_sums': sorted(sum_distribution.items(), key=lambda x: x[1], reverse=True)[:10] } def get_ac_value_analysis(self, lottery_type: str, periods: int = 100) -> Dict: model = SSQLottery if lottery_type == 'ssq' else DLTLottery recent_draws = self.db.query(model).order_by( model.open_time.desc()).limit(periods).all() ac_values = [] for draw in recent_draws: if lottery_type == 'ssq': red_numbers = sorted([draw.red_ball_1, draw.red_ball_2, draw.red_ball_3, draw.red_ball_4, draw.red_ball_5, draw.red_ball_6]) else: red_numbers = sorted([draw.front_ball_1, draw.front_ball_2, draw.front_ball_3, draw.front_ball_4, draw.front_ball_5]) ac = sum(abs(red_numbers[i+1] - red_numbers[i]) for i in range(len(red_numbers)-1)) ac_values.append(ac) ac_distribution = defaultdict(int) for ac in ac_values: ac_distribution[ac] += 1 return { 'ac_values': ac_values, 'ac_distribution': dict(ac_distribution), 'min_ac': min(ac_values), 'max_ac': max(ac_values), 'avg_ac': float(np.mean(ac_values)), 'median_ac': float(np.median(ac_values)), 'std_ac': float(np.std(ac_values)), 'most_common_ac': sorted(ac_distribution.items(), key=lambda x: x[1], reverse=True)[:10] } def get_prime_composite_analysis(self, lottery_type: str, periods: int = 100) -> Dict: def is_prime(n): if n < 2: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True model = SSQLottery if lottery_type == 'ssq' else DLTLottery recent_draws = self.db.query(model).order_by( model.open_time.desc()).limit(periods).all() prime_ratios = [] for draw in recent_draws: if lottery_type == 'ssq': red_numbers = [draw.red_ball_1, draw.red_ball_2, draw.red_ball_3, draw.red_ball_4, draw.red_ball_5, draw.red_ball_6] else: red_numbers = [draw.front_ball_1, draw.front_ball_2, draw.front_ball_3, draw.front_ball_4, draw.front_ball_5] prime_count = sum(1 for num in red_numbers if is_prime(num)) composite_count = len(red_numbers) - prime_count prime_ratios.append(f"{prime_count}:{composite_count}") ratio_distribution = defaultdict(int) for ratio in prime_ratios: ratio_distribution[ratio] += 1 return { 'prime_ratios': prime_ratios, 'ratio_distribution': dict(ratio_distribution), 'most_common_ratios': sorted(ratio_distribution.items(), key=lambda x: x[1], reverse=True)[:10] } def get_road_012_analysis(self, lottery_type: str, periods: int = 100) -> Dict: model = SSQLottery if lottery_type == 'ssq' else DLTLottery recent_draws = self.db.query(model).order_by( model.open_time.desc()).limit(periods).all() road_012_counts = [] for draw in recent_draws: if lottery_type == 'ssq': red_numbers = [draw.red_ball_1, draw.red_ball_2, draw.red_ball_3, draw.red_ball_4, draw.red_ball_5, draw.red_ball_6] else: red_numbers = [draw.front_ball_1, draw.front_ball_2, draw.front_ball_3, draw.front_ball_4, draw.front_ball_5] road_0 = sum(1 for num in red_numbers if num % 3 == 0) road_1 = sum(1 for num in red_numbers if num % 3 == 1) road_2 = sum(1 for num in red_numbers if num % 3 == 2) road_012_counts.append({ 'road_0': road_0, 'road_1': road_1, 'road_2': road_2, 'pattern': f"{road_0}:{road_1}:{road_2}" }) pattern_distribution = defaultdict(int) for count in road_012_counts: pattern_distribution[count['pattern']] += 1 return { 'road_012_counts': road_012_counts, 'pattern_distribution': dict(pattern_distribution), 'most_common_patterns': sorted(pattern_distribution.items(), key=lambda x: x[1], reverse=True)[:10] } def get_span_analysis(self, lottery_type: str, periods: int = 100) -> Dict: model = SSQLottery if lottery_type == 'ssq' else DLTLottery recent_draws = self.db.query(model).order_by( model.open_time.desc()).limit(periods).all() spans = [] for draw in recent_draws: if lottery_type == 'ssq': red_numbers = [draw.red_ball_1, draw.red_ball_2, draw.red_ball_3, draw.red_ball_4, draw.red_ball_5, draw.red_ball_6] else: red_numbers = [draw.front_ball_1, draw.front_ball_2, draw.front_ball_3, draw.front_ball_4, draw.front_ball_5] span = max(red_numbers) - min(red_numbers) spans.append(span) span_distribution = defaultdict(int) for span in spans: span_distribution[span] += 1 return { 'spans': spans, 'span_distribution': dict(span_distribution), 'min_span': min(spans), 'max_span': max(spans), 'avg_span': float(np.mean(spans)), 'median_span': float(np.median(spans)), 'std_span': float(np.std(spans)), 'most_common_spans': sorted(span_distribution.items(), key=lambda x: x[1], reverse=True)[:10] } def get_comprehensive_analysis(self, lottery_type: str, periods: int = 100) -> Dict: return { 'missing_value': self.get_missing_value_analysis(lottery_type, periods), 'sum_value': self.get_sum_value_analysis(lottery_type, periods), 'ac_value': self.get_ac_value_analysis(lottery_type, periods), 'prime_composite': self.get_prime_composite_analysis(lottery_type, periods), 'road_012': self.get_road_012_analysis(lottery_type, periods), 'span': self.get_span_analysis(lottery_type, periods) }