wxyz-wing

// [11/17/2010 anning]
// WXYZ-Wing
bool Sudoku::WXYZ_Wing(int n)
{
    struct sdWXYZ
    {
        _Point  p;
        int     candi;
    };

    // W -
    // X -
    // Y -
    // Z- X, Y, W 這樣可以確定共同的數字爲 Z
    // 每個候選數,對應的雙數位置,前4個爲row和box的組合,後4個爲列和box的組合
    sdWXYZ wing[8][3];
    int num[8];
    _Point arrDelPt[2];     // 最多可刪除候選數的位置個數
    _Point arrHouse[20];    // WXYZ位置可以看到的所有數格

    for (int i = 0; i < 81; ++i)
    {
        _Point pt (i);
        ANSudokuCell &cell = m_anCell[pt.r][pt.c];
        // WXYZ 數格要求是4個候選數
        if (cell.n != n) continue;

        // 確定是否可以組成WXYZ,及哪個數字爲Z
        memset(num, 0, sizeof(num));
        int idx;
        int k;
       
        bool bValEqual = false;
        int nTotal = GetInterSection(pt, pt, 20, arrHouse);
        for (int lH = 0; lH < nTotal; ++lH)
        {
            _Point & p = arrHouse[lH];
            ANSudokuCell &c2 = m_anCell[p.r][p.c];
            if (c2.n != 2) continue; // WZ, XZ, YZ都是雙數
            if (!IsInclude(cell, c2)) continue;

            if (pt.r == p.r || pt.BoxNo()==p.BoxNo()) // row or box
            {
                idx = GetIndex(cell, c2.candi[0]);
                for (k = 0; k < num[idx]; ++k) {
                    if (wing[idx][k].candi == c2.candi[1]) {
                        bValEqual = true;
                        break;
                    }
                }
                if (bValEqual) break;
                wing[idx][num[idx]].candi = c2.candi[1];
                wing[idx][num[idx]].p = p;
                ++num[idx];

                idx = GetIndex(cell, c2.candi[1]);
                for (k = 0; k < num[idx]; ++k) {
                    if (wing[idx][k].candi == c2.candi[0]) {
                        bValEqual = true;
                        break;
                    }
                }
                if (bValEqual) break;
                wing[idx][num[idx]].candi = c2.candi[0];
                wing[idx][num[idx]].p = p;
                ++num[idx];
            }
           
            if (pt.c == p.c || pt.BoxNo()==p.BoxNo()) // col or box
            {
                idx = GetIndex(cell, c2.candi[0])+4;
                for (k = 0; k < num[idx]; ++k) {
                    if (wing[idx][k].candi == c2.candi[1]) {
                        bValEqual = true;
                        break;
                    }
                }
                if (bValEqual) break;
                wing[idx][num[idx]].candi = c2.candi[1];
                wing[idx][num[idx]].p = p;
                ++num[idx];
               
                idx = GetIndex(cell, c2.candi[1])+4;
                for (k = 0; k < num[idx]; ++k) {
                    if (wing[idx][k].candi == c2.candi[0]) {
                        bValEqual = true;
                        break;
                    }
                }
                if (bValEqual) break;
                wing[idx][num[idx]].candi = c2.candi[0];
                wing[idx][num[idx]].p = p;
                ++num[idx];
            }
        }
        // 有相等的雙值數格,爲數對 Naked pair ,故查找下一個WXYZ位置
        if (bValEqual) continue;
       
        // row/row & box能否組成WXYZ-Wing
        int j;
        for (int m = 0; m < 8; ++m)
        {
            if (num[m] != n-1) continue;
           
            k = 0;
            // 滿足WXYZ-Wing,再看是否有可消的候選數
            if (m < 4)
            {
                int _colBegin = (pt.c/3) * 3;
                int _colEnd = _colBegin + 3;
                for (int cc = _colBegin; cc < _colEnd; ++cc)
                {
                    if (cc == pt.c) // 過濾 WXYZ 所在位置
                        continue;
                   
                    ANSudokuCell & cDel = m_anCell[pt.r][cc];
                    for (j = 0; j < cDel.n; ++j)
                    {
                        if (cDel.candi[j] == cell.candi[m])
                        {
                            arrDelPt[k].r = pt.r;
                            arrDelPt[k].c = cc;
                            ++k;
                            break;
                        }
                    }
                }
            }
            else
            {
                int _rowBegin = (pt.r/3) * 3;
                int _rowEnd = _rowBegin + 3;
                for (int rr = _rowBegin; rr < _rowEnd; ++rr)
                {
                    if (rr == pt.r) // 過濾 WXYZ 所在位置
                        continue;
                   
                    ANSudokuCell & cDel = m_anCell[rr][pt.c];
                    for (j = 0; j < cDel.n; ++j)
                    {
                        if (cDel.candi[j] == cell.candi[m-4])
                        {
                            arrDelPt[k].r = rr;
                            arrDelPt[k].c = pt.c;
                            ++k;
                            break;
                        }
                    }
                }
            }
            if (k <= 0) continue;
           
            /*
            printf("WXYZ-Wing(n=%d) (%d,%d)  Z:%d", n,
                pt.r, pt.c,
                k < 4 ? cell.candi[m] : cell.candi[m-4] );
           
            for (j = 0; j < num[m]; ++j)
            {
                printf("(%d,%d)",wing[m][j].p.r, wing[m][j].p.c);
            }
           
            printf("Cells to del:");
            for (j = 0; j < k; ++j)
            {
                printf("(%d,%d) ", arrDelPt[j].r, arrDelPt[j].c);
            }
            printf("/n");
            */
        }
    }
   
    return false;
}

// 從c的candi[]中取出相等n的值的索引(0~c.n-1),無則返回-100
int GetIndex(ANSudokuCell & c, int n)
{
    for (int i = 0; i < c.n; ++i)
    {
        if (c.candi[i] == n)
            return i;
    }

    return -100; // error
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章