锯齿数独 cocos2d-x 开发 (二)

来源:互联网 发布:荼靡 知乎 编辑:程序博客网 时间:2024/05/16 08:36

锯齿数独 cocos2d-x 开发 (一)

二、锯齿的生成
1、9*9的格子划分成9个随机形状的连通块。
这里采用了bfs + 并查集的算法。 在bfs生成连通块的同时,检测整个图所有的联通分量, 一些特殊的情况进行剪枝。
bfs 函数如下:

bool JigsawHelper:: bfs(int i, int j, int groupId){    bool vis[81];    memset(vis, 0, sizeof(vis));    int n = i * 9 + j;    vis[n] = true;    queue<int>q;    q.push(n);    add(i,j,q,vis);    int cnt = 1;//    cout<<"-------------------"<<endl;    while (cnt <= 9 && !q.empty())    {        int tp = q.front();        q.pop();        g[tp] = groupId;        if (!check(n))        {            g[tp] = 0;            continue;        }        cnt ++;        add(tp/9,tp%9,q,vis);//        cout<<"("<<tp/9<<","<<tp%9<<")";    }//    cout<<"-------------------"<<endl;    if (cnt < 10)    {        //        cout<<"cnt: "<<cnt<<endl;        return false;    }    return true;}

check()用于检测当前情况下能否有机会成功划分。
这里有两个重要的判定:
1) 生成过程中不同连通块的个数不得超过九个。
2)生成一个连通块完毕后,剩下的连通块中不能有个数不为9的倍数。

    int cnt[81];    memset(cnt,0,sizeof(cnt));    for (int i = 0; i < 81; i++)    {        int num = FindSet(i);        cnt[num]++;    }    int nParent = FindSet(n);    int ans = 0;    int small = 0;    for (int i = 0; i < 81; i++)    {        if (cnt[i] == 0) continue;        if (cnt[i]%9 != 0) //连通个数不是9的倍数        {            ans ++;        }        if (cnt[i]%9 != 0 && i != nParent) //小于9的连通块        {            small += cnt[i]%9;        }    }    if (cnt[nParent] != 9) //生成过程中小连通块的个数和当前块的和大于9    {        if (small + cnt[nParent] > 9)            return false;    }    if (cnt[nParent] == 9 && ans > 0) //生成结束后仍然有个数不为9的倍数的连通块        return false;    return true;

到这里并没有结束,仍然有一些刁钻的数据会造成无法继续往下生成的情况,好在只有20%左右的几率。
项目不是做题,复杂度不大,rebuild即可。

void JigsawHelper:: build(){    srand(time(NULL));    memset(g,0,sizeof(g));    vector<int>vt;    for (int i = 0; i < 81; i++)        vt.push_back(i);    for (int groupId = 1; groupId <= 9; groupId++)    {        int num = vt[rand()%vt.size()];        if (!bfs(num/9, num%9, groupId))        {            cout<<"fail!!!!!!!!!!! rebuild"<<endl;            build();            return;        }        vt.clear();        for (int i = 0; i < 81; i++)        {            if (g[i] == 0)                vt.push_back(i);        }    }    checkColor();}

2、 染色
由于四色定理的存在,预先准备四种不同的颜色。
将每个连通块看做一个节点,Welch Powel法染色即可。

3、数独的生成及tricks。
获取锯齿数组和颜色数组后就可以重新用DLX解精确覆盖问题了,构造的时候方式略不同而已。
但是最终生成的时候却偶尔会出现卡死的情况!
对于一种锯齿并不是确定有解的。所以这里修改了下生成数独的方式并添加了一些剪枝。
1)选取种子的时候只取一个随机格子随机数。
2)dlx 中dfs时超过一定deep就return false。多次测试取15000。
3)算不出结果继续rebuild, 相信cpu的实力。(实测ipad mini2以上 生成所有难度均在1s之内,完全可以接受的范围)。

4、UI
我只是在简单的背景上添加了81个不同颜色的editbox,限制一下整数。
当然有时间换成用button选择肯定是更好的

void SudokuUI::editBoxTextChanged(EditBox *editBox, const std::string &text){    char buffer[2];    if (text.length() >= 1)    {        char c = text[text.length() - 1];        if (!isdigit(c))        {            editBox->setText("");            return;        }        sprintf(buffer, "%c",c);        editBox->setText(buffer);            }}

由于锯齿形本身限制较多, 所以比较容易挖更多的洞,生成的效果也明显好一些,感受下难度吧XD~
这里写图片描述

0 0