一、基础代码逻辑
1.更新所有格子的标记
标记的格式为文本串"123456789",代表这个格子可填的数字
遍历全部81个格子,循环1-9数字,如果所在的行、列、宫都没有该数字,那么就将数字加入文本串
比如"135"代表候选数只有1、3、5
/// <summary>
/// 根据已填的数字更新未填写格子的标记
/// </summary>
private void InitMarks()
{
//遍历81个格子
for (int i = 0; i < 81; i++)
{
//计算行号
int row = i / 9;
//计算列号
int column = i % 9;
//计算所在的宫的编号
int zoomIndex = row / 3 * 3 + column / 3;
//初始化一个mark的文本,格式为"123456789",代表可填哪些数字
string mark = "";
//遍历数字1到9
for (int num = 1; num <= 9; num++)
{
//如果行、列、宫没有这个数字,那么这个数字加入标记中
if (!Rows[row].Contains(num) && !Columns[column].Contains(num) && !Zooms[zoomIndex].Contains(num))
{
//标记
mark = mark + num.ToString();
}
}
//更新标记
//当标记中仅剩一位数字时,填入该数字,并更新相应行、列、宫的标记
//若更新后又出现仅剩一个数字标记的格子,会继续递归这个逻辑
UpdateMark(i, mark);
}
}
2.更新单个格子的标记
这里为更新单个格子的标记单独写一个方法,一个原因是后续需要检测每个解题技巧是否排除了格子中的某些数字标记,另一个原因是,每当格子的标记剩下一个数字时,都需要将这个数字填入格子,然后再更新它所在行列宫的其余格子的标记,需要递归。
/// <summary>
/// 更新标记,并返回标记是否有改变
/// </summary>
/// <param name="index"></param>
/// <param name="mark"></param>
/// <returns></returns>
private bool UpdateMark(int index,string mark)
{
//标记位,是否有实际改变这个格子的标记内容
bool isMarkChanged = false;
//如果这个格子填入了数字,那么将标记置空
if (Map[index] != 0 && MarkMap[index] != null)
{
MarkMap[index] = null;
isMarkChanged = true;
}
//如果这个格子没有填入数字,那么更新标记
//如果标记中的数字只有1位,那么格子填入该数字
if(Map[index] == 0)
{
//如果该单元格没有填数据,那么更新标记
string oriMark = MarkMap[index];
MarkMap[index] = mark;
//如果这个mark只有一位数的话,填入数据
if(mark.Length == 1)
{
//填入数字
//填入后,会更新行、列、宫的标记
FillCell(index, int.Parse(mark));
}
if (oriMark != mark) isMarkChanged = true;
}
//返回标记是否改变
return isMarkChanged;
}
3.填写格子
填入格子,并更新所在行、列、宫的标记,如果标记仅剩1位数字,那么再填入数字...
/// <summary>
/// 填入格子并更新标记并填入一些数据
/// </summary>
/// <param name="index"></param>
/// <param name="number"></param>
private void FillCell(int index, int number)
{
//如果所有都填完了,那么就不需要进入这个逻辑,直接返回
if (generateCompleted) return;
//如果要填的格子是已经有数的,规定不得覆盖,直接返回
if (Map[index] != 0) return;
//行号
int row = index / 9;
//列号
int column = index % 9;
//宫的编号
int zoomIndex = GetZoomIndexWithRowColumn(row,column);
//这个格子在所在宫里的编号,取值0-8
int indexInZoom = GetIndexInZoomWithRowColumn(row, column);
//如果要填的数据跟行列宫有冲突,报错
if (Rows[row].Contains(number) || Columns[column].Contains(number) || Zooms[zoomIndex].Contains(number))
{
GameLogger.LogError($"Conflict: trying to fill {number} to row{row}column{column}, rowConfilict:{Rows[row].Contains(number)}, columnConflict:{ Columns[column].Contains(number)},zoomColift:{ Zooms[zoomIndex].Contains(number)}");
}
else
{
//填入
Map[index] = number;
//更新行列宫信息
Rows[row].AddMember(column, number);
Columns[column].AddMember(row, number);
Zooms[zoomIndex].AddMember(indexInZoom, number);
//更新格子的标记,置空
UpdateMark(index, null);
//检查是否所有格子都填完了
//为了减少遍历次数,先检查所在的行、列、宫三个是否都填满了,如果是,再检查是否所有都填完
if (Rows[row].GetCount() == 9 && Columns[column].GetCount() == 9 && Zooms[zoomIndex].GetCount() == 9)
{
//标记位,记录是否所有格子都填完
bool allCellFilled = true;
//遍历所有格子,如果有发现未填完的格子,那么所有格子没有填完,直接跳出
for (int i = 0; i < 81; i++)
{
if (Map[i] == 0)
{
allCellFilled = false;
break;
}
}
//如果发现所有格子都填完了,触发回调,并更新标记位
if (allCellFilled)
{
OnGenerateCompleted();
generateCompleted = true;
GameLogger.Log(index + " 所有81格可填完");
return;
}
}
//更新行、列、宫的标记
//遍历所在这一行的所有格子
for (int ci = 0; ci < 9; ci++)
{
//根据行、列计算出格子的下标
int index_r = GetCellIndexWithRowColumn(row, ci);
//如果格子没有填数,那么检查里面是否有这个数字的标记,如果有,剔除这个数字的标记
if(Map[index_r] == 0)
{
string mark_r = MarkMap[index_r];
if (mark_r == null) mark_r = "";
mark_r = mark_r.Replace(number.ToString(), "");
UpdateMark(index_r, mark_r);
}
}
//遍历所在这一列的所有格子
for (int ri = 0; ri < 9; ri++)
{
//根据行、列计算出格子的下标
int index_c = GetCellIndexWithRowColumn(ri, column);
//如果格子没有填数,那么检查里面是否有这个数字的标记,如果有,剔除这个数字的标记
if (Map[index_c] == 0)
{
string mark_c = MarkMap[index_c];
if (mark_c == null) mark_c = "";
mark_c = mark_c.Replace(number.ToString(), "");
UpdateMark(index_c, mark_c);
}
}
//遍历所在这一宫的所有格子
for (int zi = 0; zi < 9; zi++)
{
//根据行、列计算出格子的下标
int index_z = GetCellIndexWithZoomInfo(zoomIndex, zi / 3, zi % 3);
//如果格子没有填数,那么检查里面是否有这个数字的标记,如果有,剔除这个数字的标记
if (Map[index_z] == 0)
{
string mark_z = MarkMap[index_z];
if (mark_z == null) mark_z = "";
mark_z = mark_z.Replace(number.ToString(), "");
UpdateMark(index_z, mark_z);
}
}
}
}
4.行号、列号、宫编号、格子下标之类的相互转换
/// <summary>
/// 用行、列号计算格子的下标号
/// </summary>
/// <param name="row"></param>
/// <param name="column"></param>
/// <returns></returns>
private int GetCellIndexWithRowColumn(int row, int column)
{
int index = 9 * row + column;
return index;
}
/// <summary>
/// 用行、列号计算宫的编号
/// </summary>
/// <param name="row"></param>
/// <param name="column"></param>
/// <returns></returns>
private int GetZoomIndexWithRowColumn(int row, int column)
{
int zoomIndex = row / 3 * 3 + column / 3;
return zoomIndex;
}
/// <summary>
/// 用行、列号计算宫里面的格子编号
/// </summary>
/// <param name="row"></param>
/// <param name="column"></param>
/// <returns></returns>
private int GetIndexInZoomWithRowColumn(int row,int column)
{
int indexInZoom = row % 3 * 3 + column % 3;
return indexInZoom;
}
/// <summary>
/// 用宫编号和宫里面的行列计算格子的下标
/// </summary>
/// <param name="zoomIndex"></param>
/// <param name="rowInZoom"></param>
/// <param name="columnInZoom"></param>
/// <returns></returns>
private int GetCellIndexWithZoomInfo(int zoomIndex, int rowInZoom, int columnInZoom)
{
int globalIndex;
int zoomRow = zoomIndex / 3;//这个区域排在9个区域的第几行
int zoomColumn = zoomIndex % 3;//这个区域排在9个区域的第几列
globalIndex = (rowInZoom + zoomRow * 3) * 9 + (columnInZoom + zoomColumn * 3);
return globalIndex;
}
二、解题技巧代码
这里参考的是全民数独app总结的技巧。
1.技巧1,摒除法
/// <summary>
/// 摒除法
/// 如果一个标记只在某个单元的一个格子出现,那么这个格子必定只能填这个数
/// </summary>
/// <returns></returns>
private bool HiddenSingle()
{
//标记位,是否有填写数据或者排除标记
bool anyNumberFilled = false;
//遍历数字1-9
for (int num = 1; num <= 9; num++)
{
//检查是否有某一行中这个数字的标记只存在于一个格子
Dictionary<int, int> rowDic = new Dictionary<int, int>();
//遍历每一行
for (int r = 0; r < 9; r++)
{
//如果这行已经填满了或者已经填过这个数字,那么这一行不会有这个数字的标记,继续下一行
if (Rows[r].GetCount() == 9|| Rows[r].Contains(num)) continue;
//清空字典
rowDic.Clear();
//遍历这一行的每一格
for (int c = 0; c < 9; c++)
{
//计算格子的下标
int index = GetCellIndexWithRowColumn(r, c);
//如果这个格子没有填入数字,并且这个格子的标记里有这个数字,那么将这个格子的下标加入字典
if ((Map[index] == 0) && MarkMap[index].Contains(num.ToString()))
{
if (!rowDic.ContainsKey(index))
{
rowDic.Add(index,num);
}
//如果字典里有两个以上成员,那么不符合,继续下一位数字
if (rowDic.Count >= 2) break;
}
}
//如果字典的成员只有一个,说明这一行中只有一个格子有这个数字的标记
//那么这个格子就应该填入这个数字
if (rowDic.Count == 1)
{
//获取格子的下标,填入数字并设置标记位
foreach (var item in rowDic.Keys)
{
FillCell(item, num);
anyNumberFilled = true;
}
}
}
//检查是否有某一列中这个数字的标记只存在于一个格子
Dictionary<int, int> columnDic = new Dictionary<int, int>();
//遍历每一列
for (int c = 0; c < 9; c++)
{
if (Columns[c].GetCount() == 9|| Columns[c].Contains(num)) continue;
columnDic.Clear();
for (int r = 0; r < 9; r++)
{
int index = GetCellIndexWithRowColumn(r, c);
if ((Map[index] == 0) && MarkMap[index].Contains(num.ToString()))
{
if (!columnDic.ContainsKey(index))
{
columnDic.Add(index, num);
}
if (columnDic.Count >= 2) break;
}
}
if (columnDic.Count == 1)
{
foreach (var item in columnDic.Keys)
{
FillCell(item, num);
anyNumberFilled = true;
}
}
}
//检查是否有某一宫中这个数字的标记只存在于一个格子
Dictionary<int, int> zoomDic = new Dictionary<int, int>();
//遍历每一宫
for (int z = 0; z < 9; z++)
{
if (Zooms[z].GetCount() == 9|| Zooms[z].Contains(num)) continue;
zoomDic.Clear();
for (int zi = 0; zi < 9; zi++)
{
int index = GetCellIndexWithZoomInfo(z, zi / 3, zi % 3);
if ((Map[index] == 0) && MarkMap[index].Contains(num.ToString()))
{
if (!zoomDic.ContainsKey(index))
{
zoomDic.Add(index, num);
}
if (zoomDic.Count >= 2) break;
}
}
if (zoomDic.Count == 1)
{
foreach (var item in zoomDic.Keys)
{
FillCell(item, num);
anyNumberFilled = true;
}
}
}
}
return anyNumberFilled;
}
2.技巧2,宫内区块对行列摒除
/// <summary>
/// 宫内区块对行列摒除
/// 如果一个宫内某个数的标记限制在了某一行或者某一列中,那么这个数字在宫外的这一行或这一列的标记清除
/// </summary>
/// <returns></returns>
private bool Pointing()
{
//标记位,是否填入了数字或者排除了标记
bool anyNumberFilled = false;
//遍历每一个宫
for (int z = 0; z < 9; z++)
{
//如果这个宫未填写的格子少于两个,那么下一个宫
if (Zooms[z].GetCount() > 7) continue;
//遍历数字1-9
for (int num = 1; num <= 9; num++)
{
//如果这个宫已经填过这个数字,那么下一个数字
if (Zooms[z].Contains(num)) continue;
//字典,用来储存含有这个数字标记的格子的行号
Dictionary<int, int> rowIndexDic = new Dictionary<int, int>();
//字典,用来储存含有这个数字标记的格子的列号
Dictionary<int, int> columnIndexDic = new Dictionary<int, int>();
//遍历宫的每一个格子
for (int zi = 0; zi < 9; zi++)
{
//计算格子的下标
int index = GetCellIndexWithZoomInfo(z, zi/3, zi%3);
//行号
int row = index / 9;
//列号
int column = index % 9;
//如果这个格子没有填数并且含有这个数字的标记
if(Map[index]==0 && MarkMap[index].Contains(num.ToString()))
{
//添加到字典
if (!rowIndexDic.ContainsKey(row)) rowIndexDic.Add(row,0);
if (!columnIndexDic.ContainsKey(column)) columnIndexDic.Add(column, 0);
}
}
//如果这个宫里,所有这个数字的标记刚好在同一行,那么排除这一行其他宫这个数字的标记
if (rowIndexDic.Count == 1)
{
//获取行号
int row = 0;
foreach (var item in rowIndexDic.Keys)
{
//只有一个元素,获取行号
row = item;
}
//遍历这一行的每一格
for (int c = 0; c < 9; c++)
{
//如果这个格子在当前宫或者这一列已经填过这个数字,下一个格子
if (columnIndexDic.ContainsKey(c) || Columns[c].Contains(num)) continue;
//计算格子下标
int index = GetCellIndexWithRowColumn(row, c);
//如果格子没有填写过数字
if(Map[index] == 0)
{
//剔除格子中这个数字的标记,并更新标记位
string mark = MarkMap[index];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index, mark) || anyNumberFilled;
}
}
}
//如果这个宫里,所有这个数字的标记刚好在同一列,那么排除这一列其他宫这个数字的标记
if (columnIndexDic.Count == 1)
{
//获取列号
int column = 0;
foreach (var item in columnIndexDic.Keys)
{
//只有一个元素,获取列号
column = item;
}
//遍历这一列的每一格
for (int r = 0; r < 9; r++)
{
//如果这个格子在当前宫或者这一行已经填过这个数字,下一个格子
if (rowIndexDic.ContainsKey(r) || Rows[r].Contains(num)) continue;
//计算格子下标
int index = GetCellIndexWithRowColumn(r, column);
//如果格子没有填写过数字
if (Map[index] == 0)
{
//剔除格子中这个数字的标记,并更新标记位
string mark = MarkMap[index];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index, mark)|| anyNumberFilled ;
}
}
}
}
}
return anyNumberFilled;
}
3.技巧3,行列区块对宫摒除
/// <summary>
/// 行列区块对宫摒除
/// 如果某一行或某一列的这个数字的标记刚好被限制在同一个宫内,那么这个宫除这行或这列以外的标记清除
/// </summary>
/// <returns></returns>
private bool Claiming()
{
//标记位,是否填入数字或者剔除标记
bool anyNumberFilled = false;
//遍历每一行
for (int r = 0; r < 9; r++)
{
//如果这一行未填的格子少于两个,下一行
if (Rows[r].GetCount() > 7) continue;
//遍历数字1-9
for (int num = 1; num <= 9; num++)
{
//如果这一行已经填过这个数字,下一个数字
if (Rows[r].Contains(num)) continue;
//字典,用来比较这一行这个数字的标记是否在同一个宫内
Dictionary<int, int> zoomIndexDic = new Dictionary<int, int>();
//遍历这一行的每一格
for (int c = 0; c < 9; c++)
{
//计算格子下标
int index = GetCellIndexWithRowColumn(r, c);
//计算宫号
int z = GetZoomIndexWithRowColumn(r, c);
//如果这个格子没填数并且标记里面含有这个数字,那么将宫号添加到字典
if (Map[index] == 0 && MarkMap[index].Contains(num.ToString()))
{
if (!zoomIndexDic.ContainsKey(z)) zoomIndexDic.Add(z, 0);
}
}
//如果字典中只有一个成员,说明这一行所有这个数字的标记在同一个宫内
if (zoomIndexDic.Count == 1)
{
int zoomIndex = 0;
//获取宫号
foreach (var item in zoomIndexDic.Keys)
{
zoomIndex = item;
}
//遍历这个宫的9个格子
for (int zi = 0; zi < 9; zi++)
{
//这个格子的行号
int gR = zoomIndex / 3 * 3 + zi / 3;
//如果这个格子不在检查的这行
if (gR != r)
{
//计算格子下标
int gIndex = GetCellIndexWithZoomInfo(zoomIndex, zi / 3, zi % 3);
//如果格子没填数,那么剔除格子的这个数字的标记
if (Map[gIndex] == 0)
{
string mark = MarkMap[gIndex];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(gIndex, mark) || anyNumberFilled;
}
}
}
}
}
}
//遍历每一列
for (int c = 0; c < 9; c++)
{
if (Columns[c].GetCount() > 7) continue;
for (int num = 1; num <= 9; num++)
{
if (Columns[c].Contains(num)) continue;
Dictionary<int, int> zoomIndexDic = new Dictionary<int, int>();
for (int r = 0; r < 9; r++)
{
int index = GetCellIndexWithRowColumn(r, c);
int z = GetZoomIndexWithRowColumn(r, c);
if (Map[index] == 0 && MarkMap[index].Contains(num.ToString()))
{
if (!zoomIndexDic.ContainsKey(z)) zoomIndexDic.Add(z, 0);
}
}
if (zoomIndexDic.Count == 1)
{
int zoomIndex = 0;
foreach (var item in zoomIndexDic.Keys)
{
zoomIndex = item;
}
for (int zi = 0; zi < 9; zi++)
{
int gC = zoomIndex % 3 * 3 + zi % 3;
if (gC != c)
{
int gIndex = GetCellIndexWithZoomInfo(zoomIndex, zi / 3, zi % 3);
if (Map[gIndex] == 0)
{
string mark = MarkMap[gIndex];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(gIndex, mark) || anyNumberFilled;
}
}
}
}
}
}
return anyNumberFilled;
}
4.技巧4,数对摒除
/// <summary>
/// 数对摒除
/// 如果某行、某列或者某个宫内找到这样的两格,有两个候选数只在这两格出现过,这两格只能填这两个数字
/// </summary>
/// <returns></returns>
private bool HiddenPair()
{
//标记位,是否有填入数字或剔除标记
bool anyNumberFilled = false;
//遍历每一行
for (int r = 0; r < 9; r++)
{
//如果这一行未填的格子少于2个,那么下一行
if (Rows[r].GetCount() > 7) continue;
//记录每个数字标记所在的列号
string[] markInIndex = new string[9];
//遍历数字1-9
for (int num = 1; num <= 9; num++)
{
//下标从0开始,初始化为""
markInIndex[num - 1] = "";
//如果这一行已经填过这个数,下一个数字
if (Rows[r].Contains(num)) continue;
string markS = "";
//遍历这一行的每一格
for (int c = 0; c < 9; c++)
{
//计算格子下标
int index = GetCellIndexWithRowColumn(r, c);
//如果这个格子没有填数,并且标记里面含有这个数字,那么记录列号
if ((Map[index] == 0) && (MarkMap[index].Contains(num.ToString())))
{
markS = markS + c;
markInIndex[num - 1] = markS;
}
}
}
//循环所有两个数字的组合
for (int p = 0; p < 8; p++)
{
//如果没有这个数字的标记,下一个数字
if (markInIndex[p] == "") continue;
//如果这个数字标记存在超过3格,下一个数字
if (markInIndex[p].Length >= 3) continue;
//两个数字组合的第二个数字
for (int q = 1; q < 9 - p; q++)
{
//如果这两个数字的标记只存在于相同的两个格子
if (markInIndex[p] == markInIndex[p + q])
{
//数字1
int num1 = p + 1;
//数字2
int num2 = p + q + 1;
//格子1列号
int c1 = int.Parse(markInIndex[p].Substring(0, 1));
//格子2列号
int c2 = int.Parse(markInIndex[p].Substring(1, 1));
//格子1下标
int index1 = GetCellIndexWithRowColumn(r, c1);
//格子2下标
int index2 = GetCellIndexWithRowColumn(r, c2);
//这两个格子的标记只能是这两个数字
string mark = num1.ToString() + num2.ToString();
anyNumberFilled = UpdateMark(index1, mark) || anyNumberFilled;
anyNumberFilled = UpdateMark(index2, mark) || anyNumberFilled;
}
}
}
}
//遍历每一列
for (int c = 0; c < 9; c++)
{
if (Columns[c].GetCount() > 7) continue;
string[] markInIndex = new string[9];
for (int num = 1; num <= 9; num++)
{
markInIndex[num - 1] = "";
if (Columns[c].Contains(num)) continue;
string markS = "";
for (int r = 0; r < 9; r++)
{
int index = GetCellIndexWithRowColumn(r, c);
if ((Map[index] == 0) && (MarkMap[index].Contains(num.ToString())))
{
markS = markS + r;
markInIndex[num - 1] = markS;
}
}
}
for (int p = 0; p < 8; p++)
{
if (markInIndex[p] == "") continue;
if (markInIndex[p].Length >= 3) continue;
for (int q = 1; q < 9 - p; q++)
{
if (markInIndex[p] == markInIndex[p + q])
{
int num1 = p + 1;
int num2 = p + q + 1;
int r1 = int.Parse(markInIndex[p].Substring(0, 1));
int r2 = int.Parse(markInIndex[p].Substring(1, 1));
int index1 = GetCellIndexWithRowColumn(r1, c);
int index2 = GetCellIndexWithRowColumn(r2, c);
string mark = num1.ToString() + num2.ToString();
anyNumberFilled = UpdateMark(index1, mark) || anyNumberFilled;
anyNumberFilled = UpdateMark(index2, mark) || anyNumberFilled;
}
}
}
}
//遍历每一宫
for (int z = 0; z < 9; z++)
{
if (Zooms[z].GetCount() > 7) continue;
string[] markInIndex = new string[9];
for (int num = 1; num <= 9; num++)
{
markInIndex[num - 1] = "";
if (Zooms[z].Contains(num)) continue;
string markS = "";
for (int zi = 0; zi < 9; zi++)
{
int index = GetCellIndexWithZoomInfo(z, zi / 3, zi % 3);
if ((Map[index] == 0) && (MarkMap[index].Contains(num.ToString())))
{
markS = markS + zi;
markInIndex[num - 1] = markS;
}
}
}
for (int p = 0; p < 8; p++)
{
if (markInIndex[p] == "") continue;
if (markInIndex[p].Length >= 3) continue;
for (int q = 1; q < 9 - p; q++)
{
if (markInIndex[p] == markInIndex[p + q])
{
int num1 = p + 1;
int num2 = p + q + 1;
int zi1 = int.Parse(markInIndex[p].Substring(0, 1));
int zi2 = int.Parse(markInIndex[p].Substring(1, 1));
int index1 = GetCellIndexWithZoomInfo(z, zi1 / 3, zi1 % 3);
int index2 = GetCellIndexWithZoomInfo(z, zi2 / 3, zi2 % 3);
string mark = num1.ToString() + num2.ToString();
anyNumberFilled = UpdateMark(index1, mark) || anyNumberFilled;
anyNumberFilled = UpdateMark(index2, mark) || anyNumberFilled;
}
}
}
}
return anyNumberFilled;
}
5.技巧5,三数组摒除
/// <summary>
/// 三数组摒除
/// 如果某行、某列或者某个宫内找到这样的三格,有三个候选数只在这三格出现过,那么这三个候选数一定在这三格中,删除这三个中的其他标记
/// </summary>
/// <returns></returns>
private bool HiddenTripple()
{
//标记位,是否填入数字或者剔除标记
bool anyNumberFilled = false;
//遍历每一行
for (int r = 0; r < 9; r++)
{
//如果这一行未填的格子少于三个,那么下一行
if (Rows[r].GetCount() > 6) continue;
//储存每个数字所在的列号
string[] markInIndex = new string[9];
//遍历数字1-9
for (int num = 1; num <= 9; num++)
{
//下标从0开始,初始化为""
markInIndex[num - 1] = "";
//如果这一行已经填过这个数字,那么下一个数字
if (Rows[r].Contains(num)) continue;
//遍历这一行的每一格
for (int c = 0; c < 9; c++)
{
//计算格子下标
int index = GetCellIndexWithRowColumn(r, c);
//如果这个格子没有填数,并且标记里面含有这个数字,保存列号
if ((Map[index] == 0) && (MarkMap[index].Contains(num.ToString())))
{
markInIndex[num - 1] = markInIndex[num - 1] + c.ToString();
}
}
}
//遍历所有三个数字组合
for (int p = 0; p < 7; p++)
{
//如果这一行不存在这个数字的标记,或者有这个数字标记的格子超过4个,那么下一个数字
if (markInIndex[p] == "" || markInIndex[p].Length >= 4) continue;
for (int q = 1; q < 8 - p; q++)
{
if (markInIndex[p + q] == "" || markInIndex[p + q].Length >= 4) continue;
for (int k = 1; k < 9 - p - q; k++)
{
if (markInIndex[p + q + k] == "" || markInIndex[p + q + k].Length >= 4) continue;
//字典,判断有这三个数字标记的格子是否处在相同的三列
Dictionary<string, int> indexDic = new Dictionary<string, int>();
//将第一个数字标记存在的列号加到字典
for (int m = 0; m < markInIndex[p].Length; m++)
{
string s = markInIndex[p].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
//将第二个数字标记存在的列号加到字典
for (int m = 0; m < markInIndex[p + q].Length; m++)
{
string s = markInIndex[p + q].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
//将第三个数字标记存在的列号加到字典
for (int m = 0; m < markInIndex[p + q + k].Length; m++)
{
string s = markInIndex[p + q + k].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
//如果这三个数字标记正好处于相同的三列里面
if (indexDic.Count <= 3)
{
//数字1
int num1 = p + 1;
//数字2
int num2 = p + q + 1;
//数字3
int num3 = p + q + k + 1;
//数组取出字典里的列号
int[] indexArr = new int[indexDic.Count];
int indexArr_i = 0;
foreach (var item in indexDic.Keys)
{
indexArr[indexArr_i] = int.Parse(item);
indexArr_i++;
}
//格子1下标
int cellIndex1 = 9 * r + indexArr[0];
string s = "";
string mark = MarkMap[cellIndex1];
//剔除格子1里面除了这三个数字以外的其他标记
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex1, s) || anyNumberFilled;
//格子2下标
int cellIndex2 = 9 * r + indexArr[1];
s = "";
mark = MarkMap[cellIndex2];
//剔除格子2里面除了这三个数字以外的其他标记
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex2, s) || anyNumberFilled;
if (indexDic.Count == 3)
{
//格子3下标
int cellIndex3 = 9 * r + indexArr[2];
s = "";
mark = MarkMap[cellIndex3];
//剔除格子3里面除了这三个数字以外的其他标记
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex3, s) || anyNumberFilled;
}
}
}
}
}
}
//遍历每一列
for (int c = 0; c < 9; c++)
{
if (Columns[c].GetCount() > 6) continue;
string[] markOrNot = new string[9];
for (int num = 1; num <= 9; num++)
{
markOrNot[num - 1] = "";
if (Columns[c].Contains(num)) continue;
for (int r = 0; r < 9; r++)
{
int index = GetCellIndexWithRowColumn(r, c);
if ((Map[index] == 0) && (MarkMap[index].Contains(num.ToString())))
{
markOrNot[num - 1] = markOrNot[num - 1] + r.ToString();
}
}
}
for (int p = 0; p < 7; p++)
{
if (markOrNot[p] == "" || markOrNot[p].Length >= 4) continue;
for (int q = 1; q < 8 - p; q++)
{
if (markOrNot[p + q] == "" || markOrNot[p + q].Length >= 4) continue;
for (int k = 1; k < 9 - p - q; k++)
{
if (markOrNot[p + q + k] == "" || markOrNot[p + q + k].Length >= 4) continue;
Dictionary<string, int> indexDic = new Dictionary<string, int>();
for (int m = 0; m < markOrNot[p].Length; m++)
{
string s = markOrNot[p].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
for (int m = 0; m < markOrNot[p + q].Length; m++)
{
string s = markOrNot[p + q].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
for (int m = 0; m < markOrNot[p + q + k].Length; m++)
{
string s = markOrNot[p + q + k].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
if (indexDic.Count <= 3)
{
int num1 = p + 1;
int num2 = p + q + 1;
int num3 = p + q + k + 1;
int[] indexArr = new int[indexDic.Count];
int indexArr_i = 0;
foreach (var item in indexDic.Keys)
{
indexArr[indexArr_i] = int.Parse(item);
indexArr_i++;
}
int cellIndex1 = c + 9 * indexArr[0];
string s = "";
string mark = MarkMap[cellIndex1];
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex1, s) || anyNumberFilled;
int cellIndex2 = c + 9 * indexArr[1];
s = "";
mark = MarkMap[cellIndex2];
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex2, s) || anyNumberFilled;
if (indexDic.Count == 3)
{
int cellIndex3 = c + 9 * indexArr[2];
s = "";
mark = MarkMap[cellIndex3];
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex3, s) || anyNumberFilled;
}
}
}
}
}
}
//遍历每一宫
for (int z = 0; z < 9; z++)
{
if (Zooms[z].GetCount() > 6) continue;
string[] markOrNot = new string[9];
for (int num = 1; num <= 9; num++)
{
markOrNot[num - 1] = "";
if (Zooms[z].Contains(num)) continue;
for (int zi = 0; zi < 9; zi++)
{
int index = GetCellIndexWithZoomInfo(z, zi / 3, zi % 3);
if ((Map[index] == 0) && (MarkMap[index].Contains(num.ToString())))
{
markOrNot[num - 1] = markOrNot[num - 1] + zi.ToString();
}
}
}
for (int p = 0; p < 7; p++)
{
if (markOrNot[p] == "" || markOrNot[p].Length >= 4) continue;
for (int q = 1; q < 8 - p; q++)
{
if (markOrNot[p + q] == "" || markOrNot[p + q].Length >= 4) continue;
for (int k = 1; k < 9 - p - q; k++)
{
if (markOrNot[p + q + k] == "" || markOrNot[p + q + k].Length >= 4) continue;
Dictionary<string, int> indexDic = new Dictionary<string, int>();
for (int m = 0; m < markOrNot[p].Length; m++)
{
string s = markOrNot[p].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
for (int m = 0; m < markOrNot[p + q].Length; m++)
{
string s = markOrNot[p + q].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
for (int m = 0; m < markOrNot[p + q + k].Length; m++)
{
string s = markOrNot[p + q + k].Substring(m, 1);
if (!indexDic.ContainsKey(s))
{
indexDic.Add(s, 0);
}
}
if (indexDic.Count <= 3)
{
int num1 = p + 1;
int num2 = p + q + 1;
int num3 = p + q + k + 1;
int[] indexArr = new int[indexDic.Count];
int indexArr_i = 0;
foreach (var item in indexDic.Keys)
{
indexArr[indexArr_i] = int.Parse(item);
indexArr_i++;
}
int cellIndex1 = GetCellIndexWithZoomInfo(z, indexArr[0] / 3, indexArr[0] % 3);
string s = "";
string mark = MarkMap[cellIndex1];
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex1, s) || anyNumberFilled;
int cellIndex2 = GetCellIndexWithZoomInfo(z, indexArr[1] / 3, indexArr[1] % 3);
s = "";
mark = MarkMap[cellIndex2];
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex2, s) || anyNumberFilled;
if (indexDic.Count == 3)
{
int cellIndex3 = GetCellIndexWithZoomInfo(z, indexArr[2] / 3, indexArr[2] % 3);
s = "";
mark = MarkMap[cellIndex3];
if (mark.Contains(num1.ToString()))
{
s = s + num1.ToString();
}
if (mark.Contains(num2.ToString()))
{
s = s + num2.ToString();
}
if (mark.Contains(num3.ToString()))
{
s = s + num3.ToString();
}
anyNumberFilled = UpdateMark(cellIndex3, s) || anyNumberFilled;
}
}
}
}
}
}
return anyNumberFilled;
}
6.技巧6,显性数对+数对占位
/// <summary>
/// 显性数对+数对占位
/// 如果在一个单元里面找到两个拥有相同两个候选数的格子,那么这个单元的其他格子剔除这两个候选数
/// </summary>
/// <returns></returns>
private bool NakedPair()
{
//标记位,是否填入数字或剔除标记
bool anyNumberFilled = false;
//遍历每一行
for (int r = 0; r < 9; r++)
{
//如果这行未填的格子少于2格,那么下一行
if (Rows[r].GetCount() > 7) continue;
//遍历这一行的所有两格组合,寻找两格有且仅有相同两个候选数的
for (int p = 0; p < 8; p++)
{
//格子1下标
int cellIndex1 = GetCellIndexWithRowColumn(r, p);
//要求这一格未填写且仅有两个候选数
if (Map[cellIndex1] == 0 && MarkMap[cellIndex1].Length == 2)
{
//遍历这一行所有的两格组合
for (int q = 1; q < 9 - p; q++)
{
//格子2下标
int cellIndex2 = GetCellIndexWithRowColumn(r, p + q);
//要求这一格未填写且仅有两个候选数
if (Map[cellIndex2] == 0 && MarkMap[cellIndex2].Length == 2)
{
//如果格子1和格子2的标记是一样的
if (MarkMap[cellIndex1] == MarkMap[cellIndex2])
{
string mark = MarkMap[cellIndex1];
//标记中的第一个数字
int num1 = int.Parse(mark.Substring(0, 1));
//标记中的第二个数字
int num2 = int.Parse(mark.Substring(1, 1));
//遍历这一行的所有格子,除了这两格以外,清除其他格子这两个数字的标记
for (int c = 0; c < 9; c++)
{
//判断不是上述两格
if (c != p && c != (p + q))
{
//格子下标
int cellIndex = GetCellIndexWithRowColumn(r, c);
//清除格子中关于这两个数字的标记
string markOfIndex = MarkMap[cellIndex];
if (Map[cellIndex] == 0)
{
markOfIndex = markOfIndex.Replace(num1.ToString(), "");
markOfIndex = markOfIndex.Replace(num2.ToString(), "");
}
anyNumberFilled = UpdateMark(cellIndex, markOfIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
//遍历每一列
for (int c = 0; c < 9; c++)
{
if (Columns[c].GetCount() > 7) continue;
for (int p = 0; p < 8; p++)
{
int cellIndex1 = GetCellIndexWithRowColumn(p, c);
if (Map[cellIndex1] == 0 && MarkMap[cellIndex1].Length == 2)
{
for (int q = 1; q < 9 - p; q++)
{
int cellIndex2 = GetCellIndexWithRowColumn(p + q, c);
if (Map[cellIndex2] == 0 && MarkMap[cellIndex2].Length == 2)
{
if (MarkMap[cellIndex1] == MarkMap[cellIndex2])
{
string mark = MarkMap[cellIndex1];
int num1 = int.Parse(mark.Substring(0, 1));
int num2 = int.Parse(mark.Substring(1, 1));
for (int r = 0; r < 9; r++)
{
if (r != p && r != (p + q))
{
int cellIndex = GetCellIndexWithRowColumn(r, c);
string markOfIndex = MarkMap[cellIndex];
if (Map[cellIndex] == 0)
{
markOfIndex = markOfIndex.Replace(num1.ToString(), "");
markOfIndex = markOfIndex.Replace(num2.ToString(), "");
}
anyNumberFilled = UpdateMark(cellIndex, markOfIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
//遍历每一宫
for (int z = 0; z < 9; z++)
{
if (Zooms[z].GetCount() > 7) continue;
for (int p = 0; p < 8; p++)
{
int cellIndex1 = GetCellIndexWithZoomInfo(z, p / 3, p % 3);
if (Map[cellIndex1] == 0 && MarkMap[cellIndex1].Length == 2)
{
for (int q = 1; q < 9 - p; q++)
{
int cellIndex2 = GetCellIndexWithZoomInfo(z, (p + q) / 3, (p + q) % 3);
if (Map[cellIndex2] == 0 && MarkMap[cellIndex2].Length == 2)
{
if (MarkMap[cellIndex1] == MarkMap[cellIndex2])
{
string mark = MarkMap[cellIndex1];
int num1 = int.Parse(mark.Substring(0, 1));
int num2 = int.Parse(mark.Substring(1, 1));
for (int i = 0; i < 9; i++)
{
if (i != p && i != (p + q))
{
int cellIndex = GetCellIndexWithZoomInfo(z, i / 3, i % 3);
string markOfIndex = MarkMap[cellIndex];
if (Map[cellIndex] == 0)
{
markOfIndex = markOfIndex.Replace(num1.ToString(), "");
markOfIndex = markOfIndex.Replace(num2.ToString(), "");
}
anyNumberFilled = UpdateMark(cellIndex, markOfIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
return anyNumberFilled;
}
7.技巧7,显性三数组+三元数组占位
/// <summary>
/// 显性三数组+三元数组占位
/// </summary>
/// <returns></returns>
private bool NakedTriple()
{
//标记位,是否填入数字或者清除标记
bool anyNumberFilled = false;
//遍历每一行
for (int r = 0; r < 9; r++)
{
//如果这一行未填的格子最多只有3个,那么无需用这个方法排除其余格子
if (Rows[r].GetCount() > 5) continue;
//遍历所有的三格组合
for (int c = 0; c < 7; c++)
{
//格子1下标
int index1 = GetCellIndexWithRowColumn(r, c);
//如果这个格子已经填了数,那么下一格
if (Map[index1] == 0)
{
//遍历所有的三格组合
for (int j = 1; j < 8 - c; j++)
{
//格子2下标
int index2 = GetCellIndexWithRowColumn(r, c + j);
//如果这个格子已经填了数,那么下一格
if (Map[index2] == 0)
{
//遍历所有的三格组合
for (int k = 1; k < 9 - j - c; k++)
{
//格子3下标
int index3 = GetCellIndexWithRowColumn(r, c + j + k);
//如果这个格子已经填了数,那么下一格
if (Map[index3] == 0)
{
//字典用来判断三个格子里面是否刚好是三个相同的数字标记
Dictionary<int, int> numDic = new Dictionary<int, int>();
//将三个格子里面的标记加到字典中
string mark = MarkMap[index1];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index2];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index3];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
//如果字典的成员为,说明这三个格子里只包含这三个数字的标记,那么这三个格子必定只能填这三个数字
//清除这一行除这三个格子以外其他格子的这三个数字标记
if (numDic.Count == 3)
{
//遍历这一行的所有格子
for (int l = 0; l < 9; l++)
{
//如果是上面的三格之一,那么下一格
if (l != c && l != (c + j) && l != (c + j + k))
{
//计算格子下标
int cellIndex = GetCellIndexWithRowColumn(r, l);
//如果格子没有填数,那么清除格子里面这三个数字的标记
if (Map[cellIndex] == 0)
{
string markofIndex = MarkMap[cellIndex];
foreach (var item in numDic.Keys)
{
markofIndex = markofIndex.Replace(item.ToString(), "");
}
anyNumberFilled = UpdateMark(cellIndex, markofIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
}
}
}
//遍历每一列
for (int c = 0; c < 9; c++)
{
if (Columns[c].GetCount() > 5) continue;
for (int r = 0; r < 7; r++)
{
int index1 = GetCellIndexWithRowColumn(r, c);
if (Map[index1] == 0)
{
for (int j = 1; j < 8 - r; j++)
{
int index2 = GetCellIndexWithRowColumn(r + j, c);
if (Map[index2] == 0)
{
for (int k = 1; k < 9 - j - r; k++)
{
int index3 = GetCellIndexWithRowColumn(r + j + k, c);
if (Map[index3] == 0)
{
Dictionary<int, int> numDic = new Dictionary<int, int>();
string mark = MarkMap[index1];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index2];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index3];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
if (numDic.Count == 3)
{
for (int l = 0; l < 9; l++)
{
if (l != r && l != (r + j) && l != (r + j + k))
{
int cellIndex = GetCellIndexWithRowColumn(l, c);
if (Map[cellIndex] == 0)
{
string markofIndex = MarkMap[cellIndex];
foreach (var item in numDic.Keys)
{
markofIndex = markofIndex.Replace(item.ToString(), "");
}
anyNumberFilled = UpdateMark(cellIndex, markofIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
}
}
}
//遍历每一宫
for (int z = 0; z < 9; z++)
{
if (Zooms[z].GetCount() > 5) continue;
for (int zi = 0; zi < 7; zi++)
{
int index1 = GetCellIndexWithZoomInfo(z, zi / 3, zi % 3);
if (Map[index1] == 0)
{
for (int j = 1; j < 8 - zi; j++)
{
int index2 = GetCellIndexWithZoomInfo(z, (zi + j) / 3, (zi + j) % 3);
if (Map[index2] == 0)
{
for (int k = 1; k < 9 - j - zi; k++)
{
int index3 = GetCellIndexWithZoomInfo(z, (zi + j + k) / 3, (zi + j + k) % 3);
if (Map[index3] == 0)
{
Dictionary<int, int> numDic = new Dictionary<int, int>();
string mark = MarkMap[index1];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index2];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index3];
for (int n = 0; n < mark.Length; n++)
{
int num = int.Parse(mark.Substring(n, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
if (numDic.Count == 3)
{
for (int l = 0; l < 9; l++)
{
if (l != zi && l != (zi + j) && l != (zi + j + k))
{
int cellIndex = GetCellIndexWithZoomInfo(z, l / 3, l % 3);
if (Map[cellIndex] == 0)
{
string markofIndex = MarkMap[cellIndex];
foreach (var item in numDic.Keys)
{
markofIndex = markofIndex.Replace(item.ToString(), "");
}
anyNumberFilled = UpdateMark(cellIndex, markofIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
}
}
}
return anyNumberFilled;
}
8.技巧8,四数组摒除
/// <summary>
/// 四数组摒除
/// 有这么四个候选数,只出现在某个单元的四个格子中,那么这四个格子中的其他候选数排除
/// </summary>
/// <returns></returns>
private bool HiddenQuadruple()
{
//标记位,是否填入数字或者剔除标记
bool anyNumberFilled = false;
//遍历每一行
for (int r = 0; r < 9; r++)
{
//如果未填的格子少于五个,那么没必要用这个方法剔除标记,下一行
if (Rows[r].GetCount() > 4) continue;
//遍历所有四个数字组合
for (int num = 1; num <= 6; num++)
{
//如果这一行已经填过这个数字,下一行
if (Rows[r].Contains(num)) continue;
//遍历所有四个数字组合
for (int j = 1; j <= 7 - num; j++)
{
//如果这一行已经填过这个数字,下一行
if (Rows[r].Contains(num + j)) continue;
//遍历所有四个数字组合
for (int k = 1; k <= 8 - num - j; k++)
{
//如果这一行已经填过这个数字,下一行
if (Rows[r].Contains(num + j + k)) continue;
//遍历所有四个数字组合
for (int l = 1; l <= 9 - num - j - k; l++)
{
//如果这一行已经填过这个数字,下一行
if (Rows[r].Contains(num + j + k + l)) continue;
//字典,用来判断这四个数字是不是只出现在四格中
Dictionary<int, int> indexDic = new Dictionary<int, int>();
//遍历这一行的所有格子
for (int c = 0; c < 9; c++)
{
//格子下标
int index = GetCellIndexWithRowColumn(r, c);
if (Map[index] != 0) continue;
//如果这个格子含有至少一个这四个数字的标记,那么将列号加入字典
if (MarkMap[index].Contains(num.ToString()) ||
MarkMap[index].Contains((num + j).ToString()) ||
MarkMap[index].Contains((num + j + k).ToString()) ||
MarkMap[index].Contains((num + j + k + l).ToString()))
{
indexDic.Add(c, 0);
}
}
//如果有这四个数字标记的格子少于等于4个,那么排除这四个格子里面其余数字的标记
if (indexDic.Count <= 4)
{
//排除这四个格子里面其余数字的标记
foreach (var item in indexDic.Keys)
{
int index = GetCellIndexWithRowColumn(r, item);
string mark = MarkMap[index];
string revMark = "";
if (mark.Contains(num.ToString()))
{
revMark = revMark + num;
}
if (mark.Contains((num + j).ToString()))
{
revMark = revMark + (num + j);
}
if (mark.Contains((num + j + k).ToString()))
{
revMark = revMark + (num + j + k);
}
if (mark.Contains((num + j + k + l).ToString()))
{
revMark = revMark + (num + j + k + l);
}
anyNumberFilled = UpdateMark(index, revMark) || anyNumberFilled;
}
}
}
}
}
}
}
//遍历每一列
for (int c = 0; c < 9; c++)
{
if (Columns[c].GetCount() > 4) continue;
for (int num = 1; num <= 6; num++)
{
if (Columns[c].Contains(num)) continue;
for (int j = 1; j <= 7 - num; j++)
{
if (Columns[c].Contains(num + j)) continue;
for (int k = 1; k <= 8 - num - j; k++)
{
if (Columns[c].Contains(num + j + k)) continue;
for (int l = 1; l <= 9 - num - j - k; l++)
{
if (Columns[c].Contains(num + j + k + l)) continue;
Dictionary<int, int> indexDic = new Dictionary<int, int>();
for (int r = 0; r < 9; r++)
{
int index = GetCellIndexWithRowColumn(r, c);
if (Map[index] != 0) continue;
if (MarkMap[index].Contains(num.ToString()) ||
MarkMap[index].Contains((num + j).ToString()) ||
MarkMap[index].Contains((num + j + k).ToString()) ||
MarkMap[index].Contains((num + j + k + l).ToString()))
{
indexDic.Add(r, 0);
}
}
if (indexDic.Count <= 4)
{
foreach (var item in indexDic.Keys)
{
int index = GetCellIndexWithRowColumn(item, c);
string mark = MarkMap[index];
string revMark = "";
if (mark.Contains(num.ToString()))
{
revMark = revMark + num;
}
if (mark.Contains((num + j).ToString()))
{
revMark = revMark + (num + j);
}
if (mark.Contains((num + j + k).ToString()))
{
revMark = revMark + (num + j + k);
}
if (mark.Contains((num + j + k + l).ToString()))
{
revMark = revMark + (num + j + k + l);
}
anyNumberFilled = UpdateMark(index, revMark) || anyNumberFilled;
}
}
}
}
}
}
}
//遍历每一宫
for (int z = 0; z < 9; z++)
{
if (Zooms[z].GetCount() > 4) continue;
for (int num = 1; num <= 6; num++)
{
if (Zooms[z].Contains(num)) continue;
for (int j = 1; j <= 7 - num; j++)
{
if (Zooms[z].Contains(num + j)) continue;
for (int k = 1; k <= 8 - num - j; k++)
{
if (Zooms[z].Contains(num + j + k)) continue;
for (int l = 1; l <= 9 - num - j - k; l++)
{
if (Zooms[z].Contains(num + j + k + l)) continue;
Dictionary<int, int> indexDic = new Dictionary<int, int>();
for (int zi = 0; zi < 9; zi++)
{
int index = GetCellIndexWithZoomInfo(z, zi / 3, zi % 3);
if (Map[index] != 0) continue;
if (MarkMap[index].Contains(num.ToString()) ||
MarkMap[index].Contains((num + j).ToString()) ||
MarkMap[index].Contains((num + j + k).ToString()) ||
MarkMap[index].Contains((num + j + k + l).ToString()))
{
indexDic.Add(zi, 0);
}
}
if (indexDic.Count <= 4)
{
foreach (var item in indexDic.Keys)
{
int index = GetCellIndexWithZoomInfo(z, item / 3, item % 3);
string mark = MarkMap[index];
string revMark = "";
if (mark.Contains(num.ToString()))
{
revMark = revMark + num;
}
if (mark.Contains((num + j).ToString()))
{
revMark = revMark + (num + j);
}
if (mark.Contains((num + j + k).ToString()))
{
revMark = revMark + (num + j + k);
}
if (mark.Contains((num + j + k + l).ToString()))
{
revMark = revMark + (num + j + k + l);
}
anyNumberFilled = UpdateMark(index, revMark) || anyNumberFilled;
}
}
}
}
}
}
}
return anyNumberFilled;
}
9.技巧9,显性四数组
/// <summary>
/// 显性四数组
/// </summary>
/// <returns></returns>
private bool NakedQuadruple()
{
//标记位,是否填入数字或剔除标记
bool anyNumberFilled = false;
//遍历每一行
for (int r = 0; r < 9; r++)
{
//如果未填的格子少于五个,那么没必要用这个方法剔除标记,下一行
if (Rows[r].GetCount() > 4) continue;
//遍历所有的四格组合
for (int c = 0; c < 6; c++)
{
//格子1下标
int index1 = GetCellIndexWithRowColumn(r, c);
//如果这个格子已经填了数,那么下一格
if (Map[index1] != 0) continue;
//遍历所有的四格组合
for (int j = 1; j < 7 - c; j++)
{
//格子2下标
int index2 = GetCellIndexWithRowColumn(r, c + j);
//如果这个格子已经填了数,那么下一格
if (Map[index2] != 0) continue;
//遍历所有的四格组合
for (int k = 1; k < 8 - c - j; k++)
{
//格子3下标
int index3 = GetCellIndexWithRowColumn(r, c + j + k);
//如果这个格子已经填了数,下一格
if (Map[index3] != 0) continue;
//遍历所有的四格组合
for (int l = 1; l < 9 - c - j - k; l++)
{
//格子4下标
int index4 = GetCellIndexWithRowColumn(r, c + j + k + l);
//如果这个格子已经填了数,下一格
if (Map[index4] != 0) continue;
//字典用来判断这四个格子里面的标记是否少于等于四个
Dictionary<int, int> numDic = new Dictionary<int, int>();
//将这四个格子的标记添加到字典
string mark = MarkMap[index1];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index2];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index3];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index4];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
//如果字典成员少于等于四个,排除这一行其余格子的这四个数字标记
if (numDic.Count <= 4)
{
//遍历这一行的所有格子
for (int ci = 0; ci < 9; ci++)
{
//如果是上面四格之一,那么下一格
if (ci != c && ci != (c + j) && ci != (c + j + k) && ci != (c + j + k + l))
{
//格子下标
int index = GetCellIndexWithRowColumn(r, ci);
//如果格子已经填数,下一格
if (Map[index] != 0) continue;
//剔除格子里面四个数字的标记
string markofIndex = MarkMap[index];
foreach (var item in numDic.Keys)
{
markofIndex = markofIndex.Replace(item.ToString(), "");
}
anyNumberFilled = UpdateMark(index, markofIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
//遍历每一列
for (int c = 0; c < 9; c++)
{
if (Columns[c].GetCount() > 4) continue;
for (int r = 0; r < 6; r++)
{
int index1 = GetCellIndexWithRowColumn(r, c);
if (Map[index1] != 0) continue;
for (int j = 1; j < 7 - r; j++)
{
int index2 = GetCellIndexWithRowColumn(r + j, c);
if (Map[index2] != 0) continue;
for (int k = 1; k < 8 - r - j; k++)
{
int index3 = GetCellIndexWithRowColumn(r + j + k, c);
if (Map[index3] != 0) continue;
for (int l = 1; l < 9 - r - j - k; l++)
{
int index4 = GetCellIndexWithRowColumn(r + j + k + l, c);
if (Map[index4] != 0) continue;
Dictionary<int, int> numDic = new Dictionary<int, int>();
string mark = MarkMap[index1];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index2];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index3];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index4];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
if (numDic.Count <= 4)
{
for (int ri = 0; ri < 9; ri++)
{
if (ri != r && ri != (r + j) && ri != (r + j + k) && ri != (r + j + k + l))
{
int index = GetCellIndexWithRowColumn(ri, c);
if (Map[index] != 0) continue;
string markofIndex = MarkMap[index];
foreach (var item in numDic.Keys)
{
markofIndex = markofIndex.Replace(item.ToString(), "");
}
anyNumberFilled = UpdateMark(index, markofIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
//遍历每一宫
for (int z = 0; z < 9; z++)
{
if (Zooms[z].GetCount() > 4) continue;
for (int zi = 0; zi < 6; zi++)
{
int index1 = GetCellIndexWithZoomInfo(z, zi / 3, zi % 3);
if (Map[index1] != 0) continue;
for (int j = 1; j < 7 - zi; j++)
{
int index2 = GetCellIndexWithZoomInfo(z, (zi+j) / 3, (zi + j) % 3);
if (Map[index2] != 0) continue;
for (int k = 1; k < 8 - zi - j; k++)
{
int index3 = GetCellIndexWithZoomInfo(z, (zi + j + k) / 3, (zi + j + k) % 3);
if (Map[index3] != 0) continue;
for (int l = 1; l < 9 - zi - j - k; l++)
{
int index4 = GetCellIndexWithZoomInfo(z, (zi + j + k + l) / 3, (zi + j + k + l) % 3) ;
if (Map[index4] != 0) continue;
Dictionary<int, int> numDic = new Dictionary<int, int>();
string mark = MarkMap[index1];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index2];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index3];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
mark = MarkMap[index4];
for (int m = 0; m < mark.Length; m++)
{
int num = int.Parse(mark.Substring(m, 1));
if (!numDic.ContainsKey(num)) numDic.Add(num, 0);
}
if (numDic.Count <= 4)
{
for (int zii = 0; zii < 9; zii++)
{
if (zii != zi && zii != (zi + j) && zii != (zi + j + k) && zii != (zi + j + k + l))
{
int index = GetCellIndexWithZoomInfo(z, zii / 3, zii % 3);
if (Map[index] != 0) continue;
string markofIndex = MarkMap[index];
foreach (var item in numDic.Keys)
{
markofIndex = markofIndex.Replace(item.ToString(), "");
}
anyNumberFilled = UpdateMark(index, markofIndex) || anyNumberFilled;
}
}
}
}
}
}
}
}
return anyNumberFilled;
}
10.技巧10,X-Wing
/// <summary>
/// X-Wing
/// 如果有两行的两个候选数刚好除在两列上,那么那两列其他行的这个数排除
/// </summary>
/// <returns></returns>
private bool XWing()
{
//标记位,是否填入数字或剔除标记
bool anyNumberFilled = false;
//遍历数字1-9
for (int num = 1; num <= 9; num++)
{
//遍历所有两行组合
for (int r = 0; r < 8; r++)
{
//如果这一行未填的格子少于2格,下一行
if (Rows[r].GetCount() > 7) continue;
//如果这一行已经包含这个数字,下一行
if (Rows[r].Contains(num)) continue;
//遍历所有两行组合
for (int j = 1; j < 9 - r; j++)
{
//如果这一行未填的格子少于2格,下一行
if (Rows[r + j].GetCount() > 7) continue;
//如果这一行已经包含这个数字,下一行
if (Rows[r + j].Contains(num)) continue;
string indexInRow1 = "";
string indexInRow2 = "";
//遍历这两行的每一格,如果存在这个数字标记,就将列号保存到文本串
for (int c = 0; c < 9; c++)
{
//第一行的格子
int index1 = GetCellIndexWithRowColumn(r, c);
if (Map[index1] == 0 && MarkMap[index1].Contains(num.ToString())) indexInRow1 = indexInRow1 + c;
//第二行的格子
int index2 = GetCellIndexWithRowColumn(r + j, c);
if (Map[index2] == 0 && MarkMap[index2].Contains(num.ToString())) indexInRow2 = indexInRow2 + c;
}
//如果这两行的这个数字标记刚好在相同的两列上,排除这两列其他行的标记
if ((indexInRow1 == indexInRow2) && (indexInRow1.Length == 2))
{
//列1
int col1 = int.Parse(indexInRow1.Substring(0, 1));
//列2
int col2 = int.Parse(indexInRow1.Substring(1, 1));
//遍历除了这两行的其他行
for (int ri = 0; ri < 9; ri++)
{
if (ri != r && ri != (r + j))
{
//格子1,剔除这个数字标记
int index1InCol1 = GetCellIndexWithRowColumn(ri,col1);
if (Map[index1InCol1] == 0)
{
string mark = MarkMap[index1InCol1];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index1InCol1, mark) || anyNumberFilled;
}
//格子2,剔除这个数字标记
int index2InCol2 = GetCellIndexWithRowColumn(ri, col2);
if (Map[index2InCol2] == 0)
{
string mark = MarkMap[index2InCol2];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index2InCol2, mark) || anyNumberFilled;
}
}
}
}
}
}
}
//遍历每一列每一个数字
for (int num = 1; num <= 9; num++)
{
for (int c = 0; c < 1; c++)
{
if (Columns[c].GetCount() > 7) continue;
if (Columns[c].Contains(num)) continue;
for (int j = 1; j < 9 - c; j++)
{
if (Columns[c + j].GetCount() > 7) continue;
if (Columns[c + j].Contains(num)) continue;
string indexInColumn1 = "";
string indexInColumn2 = "";
for (int r = 0; r < 9; r++)
{
int index1 = GetCellIndexWithRowColumn(r, c);
if (Map[index1] == 0 && MarkMap[index1].Contains(num.ToString())) indexInColumn1 = indexInColumn1 + r;
int index2 = GetCellIndexWithRowColumn(r, c + j);
if (Map[index2] == 0 && MarkMap[index2].Contains(num.ToString())) indexInColumn2 = indexInColumn2 + r;
}
if ((indexInColumn1 == indexInColumn2) && (indexInColumn1.Length == 2))
{
int row1 = int.Parse(indexInColumn1.Substring(0, 1));
int row2 = int.Parse(indexInColumn1.Substring(1, 1));
for (int ci = 0; ci < 9; ci++)
{
if (ci != c && ci != (c + j))
{
int index1InRow1 = GetCellIndexWithRowColumn(row1, ci);
if (Map[index1InRow1] == 0)
{
string mark = MarkMap[index1InRow1];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index1InRow1, mark) || anyNumberFilled;
}
int index2InRow2 = GetCellIndexWithRowColumn(row2, ci);
if (Map[index2InRow2] == 0)
{
string mark = MarkMap[index2InRow2];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index2InRow2, mark) || anyNumberFilled;
}
}
}
}
}
}
}
return anyNumberFilled;
}
11.技巧11,剑鱼
/// <summary>
/// 剑鱼
/// 有三行的某个数字刚好落在三列中,那么这三列其他行的这个数字排除
/// </summary>
/// <returns></returns>
private bool Swordfish()
{
//标记位,是否填入数据或者剔除标记
bool anyNumberFilled = false;
//遍历数字1-9
for (int num = 1; num <= 9; num++)
{
//遍历所有三行组合
for (int r = 0; r < 7; r++)
{
//如果这一行未填的格子少于2格,下一行
if (Rows[r].GetCount() > 7) continue;
//如果这一行填过这个数字,下一行
if (Rows[r].Contains(num)) continue;
//遍历所有三行组合
for (int j = 1; j < 8 - r; j++)
{
//如果这一行未填的格子少于2格,下一行
if (Rows[r + j].GetCount() > 7) continue;
//如果这一行填过这个数字,下一行
if (Rows[r + j].Contains(num)) continue;
//遍历所有三行组合
for (int k = 1; k < 9 - r - j; k++)
{
//如果这一行未填的格子少于2格,下一行
if (Rows[r + j + k].GetCount() > 7) continue;
//如果这一行填过这个数字,下一行
if (Rows[r + j + k].Contains(num)) continue;
string indexInRow1 = "";
string indexInRow2 = "";
string indexInRow3 = "";
//遍历这三行的所有列
for (int c = 0; c < 9; c++)
{
//第一行的格子1
int index1 = GetCellIndexWithRowColumn(r, c);
//如果含有这个数字的标记,将列号记录在字符串中
if (Map[index1] == 0 && MarkMap[index1].Contains(num.ToString())) indexInRow1 = indexInRow1 + c;
//第二行的格子2
int index2 = GetCellIndexWithRowColumn(r + j, c);
//如果含有这个数字的标记,将列号记录在字符串中
if (Map[index2] == 0 && MarkMap[index2].Contains(num.ToString())) indexInRow2 = indexInRow2 + c;
//第三行的格子3
int index3 = GetCellIndexWithRowColumn(r + j + k, c);
//如果含有这个数字的标记,将列号记录在字符串中
if (Map[index3] == 0 && MarkMap[index3].Contains(num.ToString())) indexInRow3 = indexInRow3 + c;
}
//字典,用来判断这三行的这个数字标记是否落在相同的三列中
Dictionary<int, int> indexDic = new Dictionary<int, int>();
//将这三行包含这个数字标记的列号加到字典中
string indexStr = indexInRow1;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInRow2;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInRow3;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
//如果落在相同的三列中,那么剔除这三列其他行的这个数字的标记
if (indexDic.Count == 3)
{
//获取三个列号
int[] Cols = new int[3];
int col_i = 0;
foreach (var item in indexDic.Keys)
{
Cols[col_i] = item;
col_i++;
}
//遍历这三列的所有行
for (int ri = 0; ri < 9; ri++)
{
if (ri != r && ri != (r + j) && ri != (r + j + k))
{
//格子下标
int index1InCol1 = GetCellIndexWithRowColumn(ri,Cols[0]);
//剔除这三列中其余行所有这个数字的标记
if (Map[index1InCol1] == 0)
{
string mark = MarkMap[index1InCol1];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index1InCol1, mark) || anyNumberFilled;
}
int index2InCol2 = GetCellIndexWithRowColumn(ri, Cols[1]);
if (Map[index2InCol2] == 0)
{
string mark = MarkMap[index2InCol2];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index2InCol2, mark) || anyNumberFilled;
}
int index3InCol3 = GetCellIndexWithRowColumn(ri, Cols[2]);
if (Map[index3InCol3] == 0)
{
string mark = MarkMap[index3InCol3];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index3InCol3, mark) || anyNumberFilled;
}
}
}
}
}
}
}
}
//遍历每一列每一个数字
for (int num = 1; num <= 9; num++)
{
for (int c = 0; c < 7; c++)
{
if (Columns[c].GetCount() > 7) continue;
if (Columns[c].Contains(num)) continue;
for (int j = 1; j < 8 - c; j++)
{
if (Columns[c + j].GetCount() > 7) continue;
if (Columns[c + j].Contains(num)) continue;
for (int k = 1; k < 9 - c - j; k++)
{
if (Columns[c + j + k].GetCount() > 7) continue;
if (Columns[c + j + k].Contains(num)) continue;
string indexInCol1 = "";
string indexInCol2 = "";
string indexInCol3 = "";
for (int r = 0; r < 9; r++)
{
int index1 = GetCellIndexWithRowColumn(r, c);
if (Map[index1] == 0 && MarkMap[index1].Contains(num.ToString())) indexInCol1 = indexInCol1 + r;
int index2 = GetCellIndexWithRowColumn(r, c + j);
if (Map[index2] == 0 && MarkMap[index2].Contains(num.ToString())) indexInCol2 = indexInCol2 + r;
int index3 = GetCellIndexWithRowColumn(r, c + j + k);
if (Map[index3] == 0 && MarkMap[index3].Contains(num.ToString())) indexInCol3 = indexInCol3 + r;
}
Dictionary<int, int> indexDic = new Dictionary<int, int>();
string indexStr = indexInCol1;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInCol2;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInCol3;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
if (indexDic.Count == 3)
{
int[] rows = new int[3];
int row_i = 0;
foreach (var item in indexDic.Keys)
{
rows[row_i] = item;
row_i++;
}
for (int ci = 0; ci < 9; ci++)
{
if (ci != c && ci != (c + j) && ci != (c + j + k))
{
int index1InCol1 = GetCellIndexWithRowColumn(rows[0],ci);
if (Map[index1InCol1] == 0)
{
string mark = MarkMap[index1InCol1];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index1InCol1, mark) || anyNumberFilled;
}
int index2InCol2 = GetCellIndexWithRowColumn(rows[1], ci);
if (Map[index2InCol2] == 0)
{
string mark = MarkMap[index2InCol2];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index2InCol2, mark) || anyNumberFilled;
}
int index3InCol3 = GetCellIndexWithRowColumn(rows[2], ci);
if (Map[index3InCol3] == 0)
{
string mark = MarkMap[index3InCol3];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index3InCol3, mark) || anyNumberFilled;
}
}
}
}
}
}
}
}
return anyNumberFilled;
}
12.技巧12,水母
/// <summary>
/// 水母
/// 有四行的某个数字刚好落在四列中,那么这四列其他行的这个数字排除
/// </summary>
/// <returns></returns>
private bool Jellyfish()
{
//标记位,是否填入数字或剔除标记
bool anyNumberFilled = false;
//遍历数字1-9
for (int num = 1; num <= 9; num++)
{
//遍历所有的四行组合
for (int r = 0; r < 6; r++)
{
//如果这一行未填的格子少于2个,下一行
if (Rows[r].GetCount() > 7) continue;
//如果这一行已经填过这个数字,下一行
if (Rows[r].Contains(num)) continue;
//遍历所有的四行组合
for (int j = 1; j < 7 - r; j++)
{
//如果这一行未填的格子少于2个,下一行
if (Rows[r + j].GetCount() > 7) continue;
//如果这一行已经填过这个数字,下一行
if (Rows[r + j].Contains(num)) continue;
//遍历所有的四行组合
for (int k = 1; k < 8 - r - j; k++)
{
//如果这一行未填的格子少于2个,下一行
if (Rows[r + j + k].GetCount() > 7) continue;
//如果这一行已经填过这个数字,下一行
if (Rows[r + j + k].Contains(num)) continue;
//遍历所有的四行组合
for (int l = 1; l < 9 - r - j - k; l++)
{
//如果这一行未填的格子少于2个,下一行
if (Rows[r + j + k + l].GetCount() > 7) continue;
//如果这一行已经填过这个数字,下一行
if (Rows[r + j + k + l].Contains(num)) continue;
string indexInRow1 = "";
string indexInRow2 = "";
string indexInRow3 = "";
string indexInRow4 = "";
//遍历这四行的每一列,如果含有这个数字标记,那么将列号记录到字符串
for (int c = 0; c < 9; c++)
{
int index1 = GetCellIndexWithRowColumn(r, c);
if (Map[index1] == 0 && MarkMap[index1].Contains(num.ToString())) indexInRow1 = indexInRow1 + c;
int index2 = GetCellIndexWithRowColumn(r+j, c);
if (Map[index2] == 0 && MarkMap[index2].Contains(num.ToString())) indexInRow2 = indexInRow2 + c;
int index3 = GetCellIndexWithRowColumn(r+j+k, c);
if (Map[index3] == 0 && MarkMap[index3].Contains(num.ToString())) indexInRow3 = indexInRow3 + c;
int index4 = GetCellIndexWithRowColumn(r+j+k+l, c);
if (Map[index4] == 0 && MarkMap[index4].Contains(num.ToString())) indexInRow4 = indexInRow4 + c;
}
//字典,用来判断这四行的这个数字标记是否落在四列中
Dictionary<int, int> indexDic = new Dictionary<int, int>();
//将这四行含有这个数字标记的列号添加到字典
string indexStr = indexInRow1;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInRow2;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInRow3;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInRow4;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
//如果落在四列上
if (indexDic.Count == 4)
{
//获取四个列号
int[] Cols = new int[4];
int col_i = 0;
foreach (var item in indexDic.Keys)
{
Cols[col_i] = item;
col_i++;
}
//遍历每一行
for (int ri = 0; ri < 9; ri++)
{
//除了这四行以外,其余这四列的格子剔除这个数字标记
if (ri != r && ri != (r + j) && ri != (r + j + k) && ri != (r + j + k + l))
{
//格子1下标
int index1InCol1 = GetCellIndexWithRowColumn(ri, Cols[0]);
//剔除这个数字的标记
if (Map[index1InCol1] == 0)
{
string mark = MarkMap[index1InCol1];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index1InCol1, mark) || anyNumberFilled;
}
//格子2下标
int index2InCol2 = GetCellIndexWithRowColumn(ri, Cols[1]);
//剔除这个数字的标记
if (Map[index2InCol2] == 0)
{
string mark = MarkMap[index2InCol2];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index2InCol2, mark) || anyNumberFilled;
}
//格子3下标
int index3InCol3 = GetCellIndexWithRowColumn(ri, Cols[2]);
//剔除这个数字的标记
if (Map[index3InCol3] == 0)
{
string mark = MarkMap[index3InCol3];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index3InCol3, mark) || anyNumberFilled;
}
//格子4下标
int index4InCol4 = GetCellIndexWithRowColumn(ri, Cols[3]);
//剔除这个数字的标记
if (Map[index4InCol4] == 0)
{
string mark = MarkMap[index4InCol4];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index4InCol4, mark) || anyNumberFilled;
}
}
}
}
}
}
}
}
}
//遍历每一列每一个数字
for (int num = 1; num <= 9; num++)
{
for (int c = 0; c < 6; c++)
{
if (Columns[c].GetCount() > 7) continue;
if (Columns[c].Contains(num)) continue;
for (int j = 1; j < 7 - c; j++)
{
if (Columns[c + j].GetCount() > 7) continue;
if (Columns[c + j].Contains(num)) continue;
for (int k = 1; k < 8 - c - j; k++)
{
if (Columns[c + j + k].GetCount() > 7) continue;
if (Columns[c + j + k].Contains(num)) continue;
for (int l = 1; l < 9 - c - j - k; l++)
{
if (Columns[c + j + k + l].GetCount() > 7) continue;
if (Columns[c + j + k + l].Contains(num)) continue;
string indexInCol1 = "";
string indexInCol2 = "";
string indexInCol3 = "";
string indexInCol4 = "";
for (int r = 0; r < 9; r++)
{
int index1 = GetCellIndexWithRowColumn(r, c);
if (Map[index1] == 0 && MarkMap[index1].Contains(num.ToString())) indexInCol1 = indexInCol1 + r;
int index2 = GetCellIndexWithRowColumn(r, c + j);
if (Map[index2] == 0 && MarkMap[index2].Contains(num.ToString())) indexInCol2 = indexInCol2 + r;
int index3 = GetCellIndexWithRowColumn(r, c + j + k);
if (Map[index3] == 0 && MarkMap[index3].Contains(num.ToString())) indexInCol3 = indexInCol3 + r;
int index4 = GetCellIndexWithRowColumn(r, c + j + k + l);
if (Map[index4] == 0 && MarkMap[index4].Contains(num.ToString())) indexInCol4 = indexInCol4 + r;
}
Dictionary<int, int> indexDic = new Dictionary<int, int>();
string indexStr = indexInCol1;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInCol2;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInCol3;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
indexStr = indexInCol4;
for (int m = 0; m < indexStr.Length; m++)
{
int index = int.Parse(indexStr.Substring(m, 1));
if (!indexDic.ContainsKey(index)) indexDic.Add(index, 0);
}
if (indexDic.Count == 4)
{
int[] rows = new int[4];
int row_i = 0;
foreach (var item in indexDic.Keys)
{
rows[row_i] = item;
row_i++;
}
for (int ci = 0; ci < 9; ci++)
{
if (ci != c && ci != (c + j) && ci != (c + j + k) && ci != (c + j + k + l))
{
int index1InCol1 = GetCellIndexWithRowColumn(rows[0], ci);
if (Map[index1InCol1] == 0)
{
string mark = MarkMap[index1InCol1];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index1InCol1, mark) || anyNumberFilled;
}
int index2InCol2 = GetCellIndexWithRowColumn(rows[1], ci);
if (Map[index2InCol2] == 0)
{
string mark = MarkMap[index2InCol2];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index2InCol2, mark) || anyNumberFilled;
}
int index3InCol3 = GetCellIndexWithRowColumn(rows[2], ci);
if (Map[index3InCol3] == 0)
{
string mark = MarkMap[index3InCol3];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index3InCol3, mark) || anyNumberFilled;
}
int index4InCol4 = GetCellIndexWithRowColumn(rows[3], ci);
if (Map[index4InCol4] == 0)
{
string mark = MarkMap[index4InCol4];
mark = mark.Replace(num.ToString(), "");
anyNumberFilled = UpdateMark(index4InCol4, mark) || anyNumberFilled;
}
}
}
}
}
}
}
}
}
return anyNumberFilled;
}
}