// [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
}