static bool FindYWings(Region region) { var points = region.Points.Where(p => puzzle[p].Candidates.Count == 2).ToArray(); if (points.Length > 1) { for (int i = 0; i < points.Length; i++) { SPoint p1 = points[i]; for (int j = i + 1; j < points.Length; j++) { SPoint p2 = points[j]; var inter = puzzle[p1].Candidates.Intersect(puzzle[p2].Candidates); if (inter.Count() != 1) { continue; } int other1 = puzzle[p1].Candidates.Except(inter).ElementAt(0), other2 = puzzle[p2].Candidates.Except(inter).ElementAt(0); SPoint[] a = { p1, p2 }; foreach (SPoint point in a) { var p3a = puzzle[point].GetCanSeePoints().Except(points).Where(p => puzzle[p].Candidates.Count == 2 && puzzle[p].Candidates.Intersect(new int[] { other1, other2 }).Count() == 2); if (p3a.Count() == 1) // Example: p1 and p3 see each other, so remove similarities from p2 and p3 { SPoint p3 = p3a.ElementAt(0); SPoint pOther = a.Single(p => p != point); var common = puzzle[pOther].GetCanSeePoints().Intersect(puzzle[p3].GetCanSeePoints()); var cand = puzzle[pOther].Candidates.Intersect(puzzle[p3].Candidates); // Will just be 1 candidate if (puzzle.ChangeCandidates(common, cand)) { Logger.Log("Y-Wing", new SPoint[] { p1, p2, p3 }, cand); return(true); } } } } } } return(false); }
static bool FindXYZWings(Region region) { bool changed = false; var points2 = region.Points.Where(p => puzzle[p].Candidates.Count == 2).ToArray(); var points3 = region.Points.Where(p => puzzle[p].Candidates.Count == 3).ToArray(); if (points2.Length > 0 && points3.Length > 0) { for (int i = 0; i < points2.Length; i++) { SPoint p2 = points2[i]; for (int j = 0; j < points3.Length; j++) { SPoint p3 = points3[j]; if (puzzle[p2].Candidates.Intersect(puzzle[p3].Candidates).Count() != 2) { continue; } var p3Sees = puzzle[p3].GetCanSeePoints().Except(region.Points) .Where(p => puzzle[p].Candidates.Count == 2 && // If it has 2 candidates puzzle[p].Candidates.Intersect(puzzle[p3].Candidates).Count() == 2 && // Shares them both with p3 puzzle[p].Candidates.Intersect(puzzle[p2].Candidates).Count() == 1); // And shares one with p2 foreach (SPoint p2_2 in p3Sees) { var allSee = puzzle[p2].GetCanSeePoints().Intersect(puzzle[p3].GetCanSeePoints()).Intersect(puzzle[p2_2].GetCanSeePoints()); var allHave = puzzle[p2].Candidates.Intersect(puzzle[p3].Candidates).Intersect(puzzle[p2_2].Candidates); // Will be 1 Length if (puzzle.ChangeCandidates(allSee, allHave)) { Logger.Log("XYZ-Wing", new SPoint[] { p2, p3, p2_2 }, allHave); changed = true; } } } } } return(changed); }
static bool FindLockedCandidates(bool doRows, int rc, int value) { var with = (doRows ? Puzzle.Rows : Puzzle.Columns)[rc].GetPointsWithCandidates(value); // Even if a block only has these candidates for this "k" value, it'd be slower to check that before cancelling "BlacklistCandidates" if (with.Count() == 3 || with.Count() == 2) { var blocks = with.Select(p => puzzle[p].Block).Distinct(); if (blocks.Count() == 1) { if (puzzle.ChangeCandidates(Puzzle.Blocks[blocks.ElementAt(0)].Points.Except(with), new int[] { value })) { Logger.Log("Locked candidate", with, "{4} {0} locks within block {1}: {2}: {3}", doRows ? SPoint.RowL(rc) : (rc + 1).ToString(), blocks.ElementAt(0) + 1, with.Print(), value, doRows ? "Row" : "Column"); return(true); } } } return(false); }
static bool PointingTuple() { for (int i = 0; i < 3; i++) { SPoint[][] blockrow = new SPoint[3][], blockcol = new SPoint[3][]; for (int r = 0; r < 3; r++) { blockrow[r] = Puzzle.Blocks[r + (i * 3)].Points; blockcol[r] = Puzzle.Blocks[i + (r * 3)].Points; } for (int r = 0; r < 3; r++) // 3 blocks in a blockrow/blockcolumn { int[][] rowCand = new int[3][], colCand = new int[3][]; for (int j = 0; j < 3; j++) // 3 rows/columns in block { // The 3 cells' candidates in a block's row/column rowCand[j] = blockrow[r].GetRow(j).Select(p => puzzle[p].Candidates).UniteAll().ToArray(); colCand[j] = blockcol[r].GetColumn(j).Select(p => puzzle[p].Candidates).UniteAll().ToArray(); } // Now check if a row has a distinct candidate var zero_distinct = rowCand[0].Except(rowCand[1]).Except(rowCand[2]); if (zero_distinct.Count() > 0) { if (RemovePointingTuple(blockrow, true, i, r, 0, zero_distinct)) { return(true); } } var one_distinct = rowCand[1].Except(rowCand[0]).Except(rowCand[2]); if (one_distinct.Count() > 0) { if (RemovePointingTuple(blockrow, true, i, r, 1, one_distinct)) { return(true); } } var two_distinct = rowCand[2].Except(rowCand[0]).Except(rowCand[1]); if (two_distinct.Count() > 0) { if (RemovePointingTuple(blockrow, true, i, r, 2, two_distinct)) { return(true); } } // Now check if a column has a distinct candidate zero_distinct = colCand[0].Except(colCand[1]).Except(colCand[2]); if (zero_distinct.Count() > 0) { if (RemovePointingTuple(blockcol, false, i, r, 0, zero_distinct)) { return(true); } } one_distinct = colCand[1].Except(colCand[0]).Except(colCand[2]); if (one_distinct.Count() > 0) { if (RemovePointingTuple(blockcol, false, i, r, 1, one_distinct)) { return(true); } } two_distinct = colCand[2].Except(colCand[0]).Except(colCand[1]); if (two_distinct.Count() > 0) { if (RemovePointingTuple(blockcol, false, i, r, 2, two_distinct)) { return(true); } } } } return(false); }