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

锯齿数独 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时超过一定depth就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~
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值