效果演示
代码
#include <QCoreApplication>
#include <QGuiApplication>
#include <QPixmap>
#include <QVector>
#include <QImage>
#include <QSet>
#include <QQueue>
#include <QPainter>
#include <QMap>
#include <QHash>
#include <QThread>
#include <QProcess>
#include <iostream>
#include <map>
#include <unordered_map>
#include <QDebug>
using namespace std;
#define SCREENSHOT_PATH "D:/zhuyunpeng/program/processWater/screenshot.png"
#define OUTFILE_PATH "D:/zhuyunpeng/program/processWater/test.png"
#define TUBE_COLOR QColor(192, 192, 192, 255)
#define VIS_TUBE_COLOR QColor(0, 0, 0, 255)
#define DEFAULE_BACKGROUND_COLOR QColor(239, 250, 229, 255)
struct Tube{
int id;
unsigned int color[4];
int size;
QPoint position;
bool operator <(const Tube &t)const{
return size < t.size;
}
};
struct Step{
QPoint click1;
QPoint click2;
};
bool cmpQPoint(const QPoint a, const QPoint b){
if(a.x() == b.x()) return a.y() < b.y();
return a.x() < b.x();
}
void printTubes(const QVector<Tube> tubes)
{
for(const Tube &tube : tubes)
{
for(int i = 0;i < tube.size; i++)
{
std::cout << tube.color[i] << " ";
}
std::cout << std::endl;
}
printf("\n\n\n");
}
QVector<QPoint> getTubeCenter(QImage &image)
{
QVector<QPoint> res;
int w = image.width();
int h = image.height();
int dx[4] = {0, -1, 0, 1};
int dy[4] = {-1, 0, 1, 0};
for(int i = 0;i < w; ++i)
{
for(int j = 0;j < h; ++j)
{
QColor pColor = image.pixelColor(i, j);
int cnt = 1;
if(pColor == TUBE_COLOR)
{
QPoint leftTop(i, j);
QPoint rightButtom(i, j);
QQueue<QPoint> que;
que.push_back(QPoint(i, j));
image.setPixelColor(i, j, VIS_TUBE_COLOR);
while(que.count()){
QPoint p = que.front();
que.pop_front();
for(int d = 0; d < 4; ++d)
{
int xx = p.x() + dx[d];
int yy = p.y() + dy[d];
QColor tc = image.pixelColor(xx, yy);
if(xx < 0 || yy < 0 || xx >= w || yy >= h || !(tc == TUBE_COLOR)) continue;
que.push_back(QPoint(xx, yy));
leftTop.setX(qMin(leftTop.x(), xx));
leftTop.setY(qMin(leftTop.y(), yy));
rightButtom.setX(qMax(rightButtom.x(), xx));
rightButtom.setY(qMax(rightButtom.y(), yy));
image.setPixelColor(xx, yy, VIS_TUBE_COLOR);
cnt++;
}
}
if(cnt > 200)
{
res.push_back(QPoint((leftTop.x() + rightButtom.x()) / 2,
(leftTop.y() + rightButtom.y()) / 2));
}
}
}
}
return res;
}
QVector<QPoint> findColor(QImage image, int i, int j)
{
int w = image.width();
int h = image.height();
int dx[4] = {0, -1, 0, 1};
int dy[4] = {-1, 0, 1, 0};
QVector<QPoint> res;
QColor flagColor = image.pixelColor(i, j);
QColor visColor(255-flagColor.red(), 255-flagColor.green(), 255-flagColor.blue(), 255);
QQueue<QPoint> que;
que.push_back({i, j});
image.setPixelColor(i, j, visColor);
res.push_back({i, j});
while(que.size())
{
QPoint p = que.front();
que.pop_front();
for(int d = 0;d < 4; ++d)
{
int xx = p.x() + dx[d];
int yy = p.y() + dy[d];
if(xx < 0 || yy < 0 || xx >= w || yy >= h
|| image.pixelColor(xx, yy) != flagColor) continue;
image.setPixelColor(xx, yy, visColor);
que.push_back({xx, yy});
res.push_back({xx, yy});
}
}
return res;
}
QVector<QPoint> findColor(QImage image, QPoint p)
{
return findColor(image, p.x(), p.y());
}
bool isEnd(const QVector<Tube> &tubes)
{
for(const Tube &tube : tubes)
{
if(tube.size > 0 && tube.size < 4)
return false;
if(tube.size == 0)
continue;
if(tube.size == 4)
{
if(tube.color[0] == tube.color[1]
&& tube.color[1] == tube.color[2]
&& tube.color[2] == tube.color[3])
continue;
else
return false;
}
}
return true;
}
void pushWater(Tube &t1, Tube &t2)
{
if(t2.size == 4 || t1.size == 0) return;
if(t2.size == 0 || t2.color[t2.size - 1] == t1.color[t1.size - 1])
{
t2.color[t2.size] = t1.color[t1.size - 1];
t2.size++;
t1.size--;
pushWater(t1, t2);
}
}
bool findSteps(QVector<Tube> &tubes, map<QVector<Tube>, bool> &vis, QVector<Step> &steps, int deep)
{
if(deep > 500) return false;
if(isEnd(tubes))
return true;
if(vis.find(tubes) != vis.end()) return false;
vis[tubes] = true;
for(int i = 0;i < tubes.size(); ++i)
{
if(tubes[i].size == 0) continue;
bool colorOver1 = false;
for(int k = 1;k < tubes[i].size; ++k)
{
if(tubes[i].color[k] != tubes[i].color[k - 1])
colorOver1 = true;
}
for(int j = 0;j < tubes.size(); ++j)
{
if(i == j) continue;
if(tubes[j].size == 4) continue;
if(tubes[j].size == 0 && !colorOver1) continue;
if(tubes[j].size == 0 ||
tubes[j].color[tubes[j].size - 1] == tubes[i].color[tubes[i].size - 1])
{
Tube tubei = tubes[i];
Tube tubej = tubes[j];
steps.push_back({tubes[i].position, tubes[j].position});
pushWater(tubes[i], tubes[j]);
bool flag = true;
flag = (tubes[i].size > 0 &&
tubes[i].color[tubes[i].size - 1] != tubes[j].color[tubes[j].size - 1])
|| tubes[i].size == 0;
if(flag && findSteps(tubes, vis, steps, deep + 1))
{
return true;
}
steps.pop_back();
tubes[i] = tubei;
tubes[j] = tubej;
}
}
}
return false;
}
int main(int argc, char *argv[])
{
system("D:/zhuyunpeng/program/processWater/screenshot.bat");
QThread::sleep(3);
QGuiApplication a(argc, argv);
QImage sFile(SCREENSHOT_PATH);
QVector<Tube> tubes;
map<QVector<Tube>, bool> visState;
QVector<QPoint> tubesPostion = getTubeCenter(sFile);
qDebug() << "一共有 " << tubesPostion.size() << " 个试管";
for(int i = 0;i < tubesPostion.size(); ++i)
{
Tube tube;
tube.id = i;
tube.position = tubesPostion[i];
QPoint keyPoints[4] = {
{tube.position.x(), tube.position.y() + 165},
{tube.position.x(), tube.position.y() + 75},
{tube.position.x(), tube.position.y() - 25},
{tube.position.x(), tube.position.y() - 120}
};
tube.size = 0;
for(int j = 0;j < 4; ++j)
{
QPoint keyPoint = keyPoints[j];
QColor pColor = sFile.pixelColor(keyPoint);
QVector<QPoint> points = findColor(sFile, keyPoint);
if(points.size() >= 9000)
{
tube.color[tube.size++] = (unsigned int)pColor.rgba();
}else{
break;
}
}
tubes.push_back(tube);
}
for(int i = 0;i < tubes.size(); ++i){
Tube &tube = tubes[i];
qDebug() << "第" << i <<"个试管内的情况: "
<< "position=(" << tube.position.x() << ", " << tube.position.y() << ") "
<< "size = " << tube.size;
for(int j = tube.size - 1;j >= 0; --j){
qDebug() << tube.color[j] << " ";
}
}
QVector<Step> steps;
if(findSteps(tubes, visState, steps, 1))
{
qDebug() << "已找到解决方案! 步骤数=" << steps.size();
}else{
qDebug() << "未找到解决方案! 步骤数=" << steps.size();
}
QVector<Step> runSteps;
for(int i = 0;i < steps.size(); ++i){
Step &step = steps[i];
if(runSteps.size())
{
bool canRun = true;
for(Step &s : runSteps){
if(s.click1 == steps[i].click1
|| s.click1 == steps[i].click2
|| s.click2 == steps[i].click1)
{
canRun = false;
break;
}
}
if(!canRun){
runSteps.clear();
QThread::sleep(3);
}
}
runSteps.push_back(steps[i]);
qDebug() << "from (" << step.click1.x() << ", " << step.click1.y() << ")"
<< "to (" << step.click2.x() << ", " << step.click2.y() << ")";
QString cmd1 = QString("adb shell input tap %1 %2")
.arg(step.click1.x()).arg(step.click1.y());
system(cmd1.toStdString().c_str());
QThread::msleep(100);
QString cmd2 = QString("adb shell input tap %1 %2")
.arg(step.click2.x()).arg(step.click2.y());
system(cmd2.toStdString().c_str());
}
return 0;
}