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