2025-11-04 17:18:21 +08:00
|
|
|
|
package com.xy.xyaicpzs.service.impl;
|
|
|
|
|
|
|
|
|
|
|
|
import com.xy.xyaicpzs.domain.entity.DltDrawRecord;
|
|
|
|
|
|
import com.xy.xyaicpzs.domain.entity.D5;
|
|
|
|
|
|
import com.xy.xyaicpzs.domain.entity.D6;
|
|
|
|
|
|
import com.xy.xyaicpzs.domain.entity.D7;
|
|
|
|
|
|
import com.xy.xyaicpzs.domain.entity.D8;
|
|
|
|
|
|
import com.xy.xyaicpzs.domain.vo.BallCombinationAnalysisVO;
|
|
|
|
|
|
import com.xy.xyaicpzs.service.DltCombinationAnalysisService;
|
|
|
|
|
|
import com.xy.xyaicpzs.service.DltDrawRecordService;
|
|
|
|
|
|
import com.xy.xyaicpzs.service.D5Service;
|
|
|
|
|
|
import com.xy.xyaicpzs.service.D6Service;
|
|
|
|
|
|
import com.xy.xyaicpzs.service.D7Service;
|
|
|
|
|
|
import com.xy.xyaicpzs.service.D8Service;
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.Comparator;
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 大乐透组合分析服务实现类
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
|
@Service
|
|
|
|
|
|
public class DltCombinationAnalysisServiceImpl implements DltCombinationAnalysisService {
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private D5Service d5Service;
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private D6Service d6Service;
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private D7Service d7Service;
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private D8Service d8Service;
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private DltDrawRecordService dltDrawRecordService;
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public BallCombinationAnalysisVO analyzeFrontFrontCombination(Integer masterBall, Integer slaveBall) {
|
|
|
|
|
|
// 参数校验
|
|
|
|
|
|
validateBallRange(masterBall, 1, 35, "主球(前区)");
|
|
|
|
|
|
validateBallRange(slaveBall, 1, 35, "随球(前区)");
|
|
|
|
|
|
|
|
|
|
|
|
// 查询指定组合记录
|
|
|
|
|
|
D5 targetRecord = d5Service.lambdaQuery()
|
|
|
|
|
|
.eq(D5::getMasterBallNumber, masterBall)
|
|
|
|
|
|
.eq(D5::getSlaveBallNumber, slaveBall)
|
|
|
|
|
|
.one();
|
|
|
|
|
|
|
|
|
|
|
|
if (targetRecord == null) {
|
|
|
|
|
|
throw new RuntimeException(String.format("未找到主球(前区)%d和随球(前区)%d的组合记录", masterBall, slaveBall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查询主球与所有其他球的组合记录
|
|
|
|
|
|
List<D5> allCombinations = d5Service.lambdaQuery()
|
|
|
|
|
|
.eq(D5::getMasterBallNumber, masterBall)
|
|
|
|
|
|
.ne(D5::getSlaveBallNumber, masterBall) // 排除自身
|
|
|
|
|
|
.list();
|
|
|
|
|
|
|
|
|
|
|
|
if (allCombinations.isEmpty()) {
|
|
|
|
|
|
throw new RuntimeException(String.format("未找到主球(前区)%d的组合记录", masterBall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return buildCombinationAnalysisVO(
|
|
|
|
|
|
targetRecord.getCoefficient(),
|
|
|
|
|
|
allCombinations,
|
|
|
|
|
|
D5::getCoefficient,
|
|
|
|
|
|
D5::getSlaveBallNumber
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public BallCombinationAnalysisVO analyzeFrontBackCombination(Integer masterBall, Integer slaveBall) {
|
|
|
|
|
|
// 参数校验
|
|
|
|
|
|
validateBallRange(masterBall, 1, 35, "主球(前区)");
|
|
|
|
|
|
validateBallRange(slaveBall, 1, 12, "随球(后区)");
|
|
|
|
|
|
|
|
|
|
|
|
// 查询指定组合记录
|
|
|
|
|
|
D6 targetRecord = d6Service.lambdaQuery()
|
|
|
|
|
|
.eq(D6::getMasterBallNumber, masterBall)
|
|
|
|
|
|
.eq(D6::getSlaveBallNumber, slaveBall)
|
|
|
|
|
|
.one();
|
|
|
|
|
|
|
|
|
|
|
|
if (targetRecord == null) {
|
|
|
|
|
|
throw new RuntimeException(String.format("未找到主球(前区)%d和随球(后区)%d的组合记录", masterBall, slaveBall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查询主球与所有其他球的组合记录
|
|
|
|
|
|
List<D6> allCombinations = d6Service.lambdaQuery()
|
|
|
|
|
|
.eq(D6::getMasterBallNumber, masterBall)
|
|
|
|
|
|
.list();
|
|
|
|
|
|
|
|
|
|
|
|
if (allCombinations.isEmpty()) {
|
|
|
|
|
|
throw new RuntimeException(String.format("未找到主球(前区)%d的组合记录", masterBall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return buildCombinationAnalysisVO(
|
|
|
|
|
|
targetRecord.getCoefficient(),
|
|
|
|
|
|
allCombinations,
|
|
|
|
|
|
D6::getCoefficient,
|
|
|
|
|
|
D6::getSlaveBallNumber
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public BallCombinationAnalysisVO analyzeBackBackCombination(Integer masterBall, Integer slaveBall) {
|
|
|
|
|
|
// 参数校验
|
|
|
|
|
|
validateBallRange(masterBall, 1, 12, "主球(后区)");
|
|
|
|
|
|
validateBallRange(slaveBall, 1, 12, "随球(后区)");
|
|
|
|
|
|
|
|
|
|
|
|
// 查询指定组合记录
|
|
|
|
|
|
D7 targetRecord = d7Service.lambdaQuery()
|
|
|
|
|
|
.eq(D7::getMasterBallNumber, masterBall)
|
|
|
|
|
|
.eq(D7::getSlaveBallNumber, slaveBall)
|
|
|
|
|
|
.one();
|
|
|
|
|
|
|
|
|
|
|
|
if (targetRecord == null) {
|
|
|
|
|
|
throw new RuntimeException(String.format("未找到主球(后区)%d和随球(后区)%d的组合记录", masterBall, slaveBall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查询主球与所有其他球的组合记录
|
|
|
|
|
|
List<D7> allCombinations = d7Service.lambdaQuery()
|
|
|
|
|
|
.eq(D7::getMasterBallNumber, masterBall)
|
|
|
|
|
|
.ne(D7::getSlaveBallNumber, masterBall) // 排除自身
|
|
|
|
|
|
.list();
|
|
|
|
|
|
|
|
|
|
|
|
if (allCombinations.isEmpty()) {
|
|
|
|
|
|
throw new RuntimeException(String.format("未找到主球(后区)%d的组合记录", masterBall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return buildCombinationAnalysisVO(
|
|
|
|
|
|
targetRecord.getCoefficient(),
|
|
|
|
|
|
allCombinations,
|
|
|
|
|
|
D7::getCoefficient,
|
|
|
|
|
|
D7::getSlaveBallNumber
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public BallCombinationAnalysisVO analyzeBackFrontCombination(Integer masterBall, Integer slaveBall) {
|
|
|
|
|
|
// 参数校验
|
|
|
|
|
|
validateBallRange(masterBall, 1, 12, "主球(后区)");
|
|
|
|
|
|
validateBallRange(slaveBall, 1, 35, "随球(前区)");
|
|
|
|
|
|
|
|
|
|
|
|
// 查询指定组合记录
|
|
|
|
|
|
D8 targetRecord = d8Service.lambdaQuery()
|
|
|
|
|
|
.eq(D8::getMasterBallNumber, masterBall)
|
|
|
|
|
|
.eq(D8::getSlaveBallNumber, slaveBall)
|
|
|
|
|
|
.one();
|
|
|
|
|
|
|
|
|
|
|
|
if (targetRecord == null) {
|
|
|
|
|
|
throw new RuntimeException(String.format("未找到主球(后区)%d和随球(前区)%d的组合记录", masterBall, slaveBall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查询主球与所有其他球的组合记录
|
|
|
|
|
|
List<D8> allCombinations = d8Service.lambdaQuery()
|
|
|
|
|
|
.eq(D8::getMasterBallNumber, masterBall)
|
|
|
|
|
|
.list();
|
|
|
|
|
|
|
|
|
|
|
|
if (allCombinations.isEmpty()) {
|
|
|
|
|
|
throw new RuntimeException(String.format("未找到主球(后区)%d的组合记录", masterBall));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return buildCombinationAnalysisVO(
|
|
|
|
|
|
targetRecord.getCoefficient(),
|
|
|
|
|
|
allCombinations,
|
|
|
|
|
|
D8::getCoefficient,
|
|
|
|
|
|
D8::getSlaveBallNumber
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 验证球号范围
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void validateBallRange(Integer ballNumber, int minValue, int maxValue, String ballType) {
|
|
|
|
|
|
if (ballNumber == null) {
|
|
|
|
|
|
throw new IllegalArgumentException(ballType + "号码不能为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ballNumber < minValue || ballNumber > maxValue) {
|
|
|
|
|
|
throw new IllegalArgumentException(String.format("%s号码必须在%d-%d范围内,错误值:%d",
|
|
|
|
|
|
ballType, minValue, maxValue, ballNumber));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 构建组合分析结果VO
|
|
|
|
|
|
*/
|
|
|
|
|
|
private <T> BallCombinationAnalysisVO buildCombinationAnalysisVO(
|
|
|
|
|
|
Double targetCoefficient,
|
|
|
|
|
|
List<T> allCombinations,
|
|
|
|
|
|
Function<T, Double> coefficientGetter,
|
|
|
|
|
|
Function<T, Integer> ballNumberGetter) {
|
|
|
|
|
|
|
|
|
|
|
|
// 找出系数最高的球号
|
|
|
|
|
|
T highest = allCombinations.stream()
|
|
|
|
|
|
.max(Comparator.comparing(coefficientGetter))
|
|
|
|
|
|
.orElse(null);
|
|
|
|
|
|
|
|
|
|
|
|
// 找出系数最低的球号
|
|
|
|
|
|
T lowest = allCombinations.stream()
|
|
|
|
|
|
.min(Comparator.comparing(coefficientGetter))
|
|
|
|
|
|
.orElse(null);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算平均系数
|
|
|
|
|
|
double avgCoefficient = allCombinations.stream()
|
|
|
|
|
|
.mapToDouble(coefficientGetter::apply)
|
|
|
|
|
|
.average()
|
|
|
|
|
|
.orElse(0.0);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取最新开奖期号
|
|
|
|
|
|
Long latestDrawId = getLatestDrawId();
|
|
|
|
|
|
|
|
|
|
|
|
return BallCombinationAnalysisVO.builder()
|
|
|
|
|
|
.faceCoefficient(targetCoefficient)
|
|
|
|
|
|
.highestBall(highest != null ? ballNumberGetter.apply(highest) : null)
|
|
|
|
|
|
.highestCoefficient(highest != null ? coefficientGetter.apply(highest) : null)
|
|
|
|
|
|
.lowestBall(lowest != null ? ballNumberGetter.apply(lowest) : null)
|
|
|
|
|
|
.lowestCoefficient(lowest != null ? coefficientGetter.apply(lowest) : null)
|
|
|
|
|
|
.averageCoefficient(avgCoefficient)
|
|
|
|
|
|
.latestDrawId(latestDrawId)
|
|
|
|
|
|
.build();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取最新开奖期号
|
|
|
|
|
|
*/
|
|
|
|
|
|
private Long getLatestDrawId() {
|
|
|
|
|
|
String latestDrawId = dltDrawRecordService.lambdaQuery()
|
2026-03-18 20:55:49 +08:00
|
|
|
|
.orderByDesc(DltDrawRecord::getDrawDate)
|
2025-11-04 17:18:21 +08:00
|
|
|
|
.last("LIMIT 1")
|
|
|
|
|
|
.oneOpt()
|
|
|
|
|
|
.map(DltDrawRecord::getDrawId)
|
|
|
|
|
|
.orElse(null);
|
|
|
|
|
|
|
|
|
|
|
|
if (latestDrawId != null) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
return Long.parseLong(latestDrawId);
|
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
|
log.warn("开奖期号格式转换失败:{}", latestDrawId);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|