无聊的国庆,总得做点什么好玩的是不是,那就写代码获取大乐透,让后按照自己的算法推测下一期的结果吧。
话不多说,上代码
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
initDataBase();
auto db = QSqlDatabase::database();
if(db.isValid())
{
QSqlTableModel *model = new QSqlTableModel(this);
model->setTable(his_tb_name);
model->setSort(0,Qt::DescendingOrder);
model->select();
model->setHeaderData(0, Qt::Horizontal, tr("期号"));
model->setHeaderData(1, Qt::Horizontal, tr("号码"));
model->setHeaderData(2, Qt::Horizontal, tr("开奖日期"));
ui->tableView->setModel(model);
ui->tableView->resizeColumnsToContents();
Log(" model db tables "<<model->database().tables());
}
connect(this,&Widget::finishedCurrentPage,this,&Widget::onCurrentPageFinished,Qt::QueuedConnection);
initialChat();
addLog(QSysInfo::buildAbi());
}
上述代码的作用就是UI入口,主要是创建的sqlite数据库,然后显示最近获取的期号数据
void initDataBase()
{
QString log;
auto db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("./lotus.db");
auto ret = db.open();
log.append(QString("open db ")+ (ret?" ok ":"error"+db.lastError().text()));
auto tables = db.tables();
if(!tables.contains(his_tb_name))
{
QString sql =QString("create table %1 (%2 text PRIMARY KEY NOT NULL, %3 text,%4 text);").arg(his_tb_name).arg(Serial_No).arg(front_no).arg(end_no);
auto retsql = db.exec(sql);
log.append( " \n create table "+db.lastError().text());
}
qDebug()<<" log "<<log;
}
上述代码和名字一致,主要是创建了sqlite和对应的表。
const QString lotusUrl ="https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry?gameNo=85&provinceId=0&pageSize=100&isVerify=1&pageNo=%1";
const QString end_no ="End_No";
const QString Serial_No ="Serial_No";
const QString front_no ="Front_No";
需要使用的常量,主要是后需要http请求获取彩票数据,然后是表头等
void Widget::getCurrentPageData()
{
auto mng = manager();
QUrl url(lotusUrl.arg(currentPage));
auto reply = mng->get(QNetworkRequest(url));
connect(reply,&QNetworkReply::finished,this,&Widget::handleReply,Qt::QueuedConnection);
}
void Widget::handleReply()
{
auto reply = dynamic_cast<QNetworkReply*>(sender());
auto json = reply->readAll();
auto doc = QJsonDocument::fromJson(json);
if(doc.isNull())
{
Log(" empty json "<<json<<reply->errorString());
return ;
}
auto value = doc.object().value("value").toObject();
auto db = QSqlDatabase::database();
qDebug()<<" tables "<<db.tables();
QSqlQuery query(db);
query.prepare(QString("insert into %1 values(?,?,?)").arg(his_tb_name));
auto records = value.value("list").toArray();
QVariantList serials;
QVariantList frontnumbers;
QVariantList endNumbers;
QDate minDate;
QDate maxDate;
for(auto record : records)
{
auto dateString = record.toObject().value("lotteryDrawTime").toString();
auto tmpDate = QDate::fromString(dateString,Qt::ISODate);
if(!minDate.isValid())
{
minDate = tmpDate;
}
if(!maxDate.isValid())
{
maxDate = tmpDate;
}
if(maxDate<tmpDate)
{
maxDate = tmpDate;
}
if(minDate>tmpDate)
{
minDate = tmpDate;
}
qDebug()<<" date "<<tmpDate;
if(this->isExist(dateString))
{
qDebug()<<" has exists!";
continue;
}
endNumbers<<dateString;
serials<<record.toObject().value("lotteryDrawNum").toString();
frontnumbers<<record.toObject().value("lotteryDrawResult").toString();
}
query.addBindValue(serials);
query.addBindValue(frontnumbers);
query.addBindValue(endNumbers);
qDebug()<<" from "<<minDate <<" to "<<maxDate;
if(this->fromDate.isNull() || this->fromDate >minDate)
{
this->fromDate = minDate;
}
if(this->toDate.isNull() || this->toDate< maxDate)
{
this->toDate = maxDate;
}
if(!query.execBatch())
{
qDebug()<<" exe error "<<query.lastError().text()
<<" serial "<<serials.size()
<<" front "<<frontnumbers.size()
<<" end "<<endNumbers.size()
<<" query "<<query.lastQuery();
}
qDebug()<<" exe end ";
emit finishedCurrentPage();
reply->deleteLater();
}
主要用于获取当前页面对应的彩票号码,插入到数据库;中间去重;每次都活获取单页网页数据,后续需要继续下一页还是停止,由UI上的天数决定。
这里省略掉关于统计的代码,很简单,就是便利数据库,把所有的数据全部统计一次,后面计算最佳的时候使用到。
所以界面需要先 刷新,按统计,再按最佳
void Widget::on_bestBtn_clicked()
{
if(lastEnds.isEmpty() || lastFronts.isEmpty())
{
on_CalculateBtn_clicked();
}
ui->toolBox->setCurrentIndex(2);
ValueList fronts = convertMapToList(this->lastFronts);
ValueList ends = convertMapToList(this->lastEnds);
// get max
auto theMax = [](const ValuePair&left,const ValuePair&right )
{
return left.second>right.second;
};
std::stable_sort(fronts.begin(),fronts.end(),theMax);
std::stable_sort(ends.begin(),ends.end(),theMax);
qDebug()<<" fronts "<<fronts
<<"\n ends "<<ends;
//max team
QStringList maxValues;
for(short i=0;i<5;++i)
{
auto value =fronts.at(i).first;
maxValues<< QString::number(value);
}
for(short i=0;i<2;++i)
{
auto value =ends.at(i).first;
maxValues<< QString::number(value);
}
//min team
QStringList minValues;
for(short i=0;i<5;++i)
{
auto value =fronts.at(fronts.size()-i-1).first;
minValues<< QString::number(value);
}
for(short i=0;i<2;++i)
{
auto value =ends.at(ends.size()-i-1).first;
minValues<< QString::number(value);
}
//middle team
QStringList middleValues;
short frontdiff = fronts.size()/3+1;
short endDiff = ends.size()/3+1;
for(short i=0;i<5;++i)
{
auto value =fronts.at(frontdiff+i).first;
middleValues<< QString::number(value);
}
for(short i=0;i<2;++i)
{
auto value =ends.at(endDiff+i).first;
middleValues<< QString::number(value);
}
auto isValueSmaller = [](const QString &left,const QString&right){
return left.toShort()<right.toShort();
};
std::stable_sort(maxValues.begin(),maxValues.end()-2,isValueSmaller);
std::stable_sort(minValues.begin(),minValues.end()-2,isValueSmaller);
std::stable_sort(middleValues.begin(),middleValues.end()-2,isValueSmaller);
QString result = QDateTime::currentDateTime().toString();
result+=QString("根据玄学推断,下一期开奖结果是:\n");
result+="\n 最大期望 "+maxValues.join(" -- ");
result+="\n 最小期望 "+minValues.join(" -- ");
result+="\n 中间期望 "+ middleValues.join(" -- ");
addLog(result);
}
上述代码就是彩票计算;
lastFronts是通过点击计算按钮开始统计最近的前区号码(1-35)的出现的频次;
lastEnds对应后区(1-12);
通过统计结果进行排序,分别统计出最高频率组,最低频率组,和中间频率组,这三组结果就是下一期推测(哈哈,纯属搞笑的)
注意,stable_sort是为了保证不同平台的一致性结果;结果测试,如果使用sort函数,Android和我window结果在顺序相同的时候,排序结果不一致;Android在排序过程中把顺序打乱了,因此需要使用稳定排序;
我的代码是基于Qt 6.3可以编译,Android的话需要自己配置,我是用的是33 API;项目使用的是qmake的pro,因为目前qt的6.3还不能很好的支持cmake Android编译,暂时只能这样子;项目中需要网络请求,所以使用了ssl工程,这个是qt的文档说的。事实上也是这样子。下面附上Qt配置Android的环境截图,需要自己搞定 jdk,Android ndk和sdk
后面是我的代码和打包的程序,包括window 11的exe和Android 12能够运行的app
window程序界面
Android app界面
以下是资源链接: