无聊的国庆,总得做点什么好玩的是不是,那就写代码获取大乐透,让后按照自己的算法推测下一期的结果吧。
话不多说,上代码
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 maxauto 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 teamQStringList 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 teamQStringList 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 teamQStringList 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界面
以下是资源链接:
lotus源码和app-C++文档类资源-CSDN下载