AI自动还原OpenCV制作的九宫格拼图游戏(附源码)

学更好的别人,

做更好的自己。

——《微卡智享》

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第1张图片

本文长度为3215,预计阅读9分钟

前言

上一篇《C++ OpenCV制作九宫格拼图游戏》已经实现了制作九宫格拼图游戏,本章就来说说九宫格拼图游戏的自自动还原方法,完整的源码在文章最后链接中。

e709de1718d6fdaf77eaefe8fbdf130e.png

实现效果

Q1

九宫格拼图自动还原核心是什么?

要完成九宫格拼图AI自动还原,最核心的就是两点:

1.需要计算指定图像到对应区域的路径,并实现移动。

2.按指定路径移动的过程中遇到的可能性问题的解决方法。

核心思路讲解

a63cede433583dff9e60a9b278c547be.png

微卡智享

01

路径规划

其实路径规划的算法上次在《趣玩算法--OpenCV华容道AI自动解题》中就已经写完了,可以点击文章看实现的原理。

上一篇也说过,这个项目创建和数字华容道项目都放在一起了,并且将路径规划的类(CalcPathPlan)和计算数字的逆序数类(CalcReverseNum)都移动到Utils文件夹下,两个项目都直接添加现在项即可。

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第2张图片

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第3张图片

在CalcPathPlan里最核心的两个方法:

  1. InitSites-----初始化地图

  2. GetPath-----计算行动路径

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第4张图片

调用方式:

//查找行动路径
std::vector> ImgPuzzles::FindPath(std::vector>& sites, std::pair& startpos, std::pair& endpos, int directfirst)
{
  CalcPathPlan plan = CalcPathPlan();
  plan.DirectFirst = directfirst;
  plan.InitSites(sites);


  return plan.GetPath(startpos, endpos);
}

通过初始化地图方式,可以将3X3九宫格,和4X4的数字华容道或是其它的二维表格都能实现路径规划。

行动原理

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第5张图片

上图中先找到了左上角的图像,现在我们要将其移动到左上角位置

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第6张图片

调用路径规划时,左边是传入的地图,还原的顺序就是从上到下的,所以刚开始地图中不存在任何障碍点,左边的地图都是空白色,将起点和终点两个(上图中橙色框)位置传入后,计算出了行动的路径。

上面这一步只是计算出了图像应该行动的路径,接下来具体行动方式需要我们自己实现。

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第7张图片

已经规划好的路线,接下来按规划路径走,必须让空白格出现在图像要走的下一步位置,这里重要的一点就是需要移动的图像格不能移动,实现不能移动的方法就是将其设置为地图中的障碍点后,再计算空白格到指定位置的路径规划。

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第8张图片

按上面的方式将空白格移动过来

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第9张图片

接下来就要按原来图像规划的路径计算下一个空白格

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第10张图片

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第11张图片

接上面的原理,最终将左上角的图像移动到指定位置,当位置锁定后,下面路径规划时传入的地图,锁定位置就要设置成为障碍点,不允许通过了。

02

特殊处理

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第12张图片

当上图中右上的图像需要移动上去时,在计算空白格规划路径时没有可行动的路径,如下图所示:

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第13张图片

这里就需要进行特殊步骤的处理

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第14张图片

代码中使用了DealStep的函数将所有的特殊处理都在里面,除了像上面这种情况外,还有第二行中间和右边的图像有时也会遇到特殊情况。

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第15张图片

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第16张图片

上图中第二行中间图像现在也无法移动到指定位置

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第17张图片

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第18张图片

第二行最后面的图像也是无法移动到指定位置

void ImgPuzzles::DealStep(vector>& sites, int step)
{
  int row = 0;
  pair sPos;
  pair endPos;
  switch (step)
  {
  case RestoreStep::Num3:
    row = step / sites.size() - 1;
    //1.先将0移动到当前要处理的行的下面格
    endPos = std::pair(row + 1, 0);
    NullMove(sites, endPos, DirectFirst::Left);


    //2.解锁处理行前面的障碍点,用0的位置优先移动到计算点
    for (int i = 0; i < sites[row].size(); ++i) {
      sites[row][i] = 0;
    }
    endPos.first = row;
    endPos.second = 2;
    NullMove(sites, endPos, DirectFirst::Up);


    //3.数字0再和当前要处理的点进行位置互换,将我们3位置移动到对应后锁定
    endPos.first = row + 1;
    endPos.second = 2;
    //防止移动点是锁定的,将改为可移动
    sites[endPos.first][endPos.second] = 0;
    NullMove(sites, endPos, DirectFirst::Right);
    //设置为锁定障碍点
    sites[row][2] = 1;


    //4.将数字0移动到第二步位置后还原当前行前三个数字
    endPos.first = row;
    endPos.second = 1;
    NullMove(sites, endPos);


    //5.将0优先按左移的方式把原来行前面的数字还原回来
    endPos.first = row + 1;
    endPos.second = 0;
    NullMove(sites, endPos, DirectFirst::Left);
    break;
  case RestoreStep::Num5:
    sites[1][0] = 0;


    //获取开始结束的点位置


    GetPos(vtsCutMat, step, sPos, endPos);
    endPos.first = 1;
    endPos.second = 2;
    //获取应到达位置
    RestorePath = FindPath(sites, sPos, endPos, DirectFirst::Up);


    //3.遍历路径每一步处理移动路径
    for (int i = 0; i < RestorePath.size(); ++i) {
      cout << RestorePath[i].first << " " << RestorePath[i].second << endl;
      //3.1数字当前位置不计算
      int front = i - 1;
      if (front < 0) continue;


      //3.3把数字当前位置设置为障碍点,这样0不允许与当前数字交换位置
      //cout << "sites:" << restorepath[front].first << " " << restorepath[front].second << endl;
      sites[RestorePath[front].first][RestorePath[front].second] = 1;


      int stepnum = NullMove(sites, RestorePath[i]);
      if (stepnum != 0) {
        //3.3.3 取消当前地图上的障碍点
        sites[RestorePath[front].first][RestorePath[front].second] = 0;


        int row = RestorePath[front].first;
        int col = RestorePath[front].second;
        int curposition = vtsCutMat[row][col]->curposition;
        int newposition = -1;


        if (ImageMove(row, col, curposition, newposition)) {
          DrawPuzzleMat(curposition, newposition);
          cv::waitKey(SleepTime);
        }
      }
      else {


        //如果没有路径就是遇到特殊情况,进行单独处理
        DealStep(sites, step);
      }
    }
    break;
  case RestoreStep::Num6:
    row = step / sites.size() - 1;
    //1.先将0移动到当前要处理的行的下面格
    endPos = std::pair(row + 1, 0);
    NullMove(sites, endPos, DirectFirst::Left);


    //2.解锁处理行前面的障碍点,用0的位置优先移动到计算点
    for (int i = 0; i < sites[row].size(); ++i) {
      sites[row][i] = 0;
    }
    endPos.first = row;
    endPos.second = 1;
    NullMove(sites, endPos, DirectFirst::Up);


    //3.将4和5锁定
    sites[row][0] = 1;
    sites[row + 1][0] = 1;
    sites[row][2] = 0;
    break;
  case RestoreStep::Step4and5:
    //1.将空白移动到5的位置
    endPos = std::pair(1, 1);
    NullMove(sites, endPos, DirectFirst::Left);


    //2.解锁4和5并还原回去
    sites[1][0] = 0;
    sites[2][0] = 0;
    pair endPos(2, 0);
    NullMove(sites, endPos, DirectFirst::Left);


    //3.锁定4和5
    sites[1][0] = 1;
    sites[1][1] = 1;
    break;
  }




}

处理完前两行后,第三行默认就可以按常规方式还原了,所以相对来说比4X4的数字华容道的处理方法要简单多。

源码地址

https://github.com/Vaccae/OpenCVNumPuzzles.git

码云地址点击文末的原文链接

a8c79441042ac09cdcdcc069cfa1e7bd.png

3c4620ed503cba83f473ab4929a07d85.png

690c88917668632bf0591e373f26c09e.png

往期推荐

e596fdc9e55dee9999e6dd833a1d39b7.png

023e4e6b246d84ca9bd6edf968e1e0f5.png

AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第19张图片

C++ OpenCV制作九宫格拼图游戏


AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第20张图片

C++ OpenCV生成九宫格图像


AI自动还原OpenCV制作的九宫格拼图游戏(附源码)_第21张图片

制作一个Android Sqlite远程运维小工具


bab5fd2017a09d6903da656fa59df86d.png

点个在看你最好看

你可能感兴趣的:(python,java,c++,算法,opencv)