public static bool IsBilocationRegion(this IReadOnlyGrid @this, int digit, int region, out short mask) { if (@this.HasDigitValue(digit, region)) { mask = 0; return(false); } mask = @this.GetDigitAppearingMask(digit, region); return(mask.CountSet() == 2); }
/// <summary> /// Searches all basic fish of the specified size. /// </summary> /// <param name="accumulator">The result accumulator.</param> /// <param name="grid">The grid.</param> /// <param name="size">The size.</param> /// <param name="searchRow"> /// Indicates the solver will searching rows or columns. /// </param> /// <returns>The result.</returns> private static void AccumulateAllBySize( IBag <TechniqueInfo> accumulator, IReadOnlyGrid grid, int size, bool searchRow) { int baseSetStart = searchRow ? 9 : 18; int coverSetStart = searchRow ? 18 : 9; var baseSets2 = (Span <int>) stackalloc int[2]; var coverSets2 = (Span <int>) stackalloc int[2]; var baseSets3 = (Span <int>) stackalloc int[3]; var coverSets3 = (Span <int>) stackalloc int[3]; var baseSets4 = (Span <int>) stackalloc int[4]; var coverSets4 = (Span <int>) stackalloc int[4]; for (int digit = 0; digit < 9; digit++) { for (int bs1 = baseSetStart; bs1 < baseSetStart + 10 - size; bs1++) { // Get the appearing mask of 'digit' in 'bs1'. short baseMask1 = grid.GetDigitAppearingMask(digit, bs1); if (baseMask1.CountSet() < 2) { continue; } for (int bs2 = bs1 + 1; bs2 < baseSetStart + 11 - size; bs2++) { // Get the appearing mask of 'digit' in 'bs2'. short baseMask2 = grid.GetDigitAppearingMask(digit, bs2); if (baseMask2.CountSet() < 2) { continue; } if (size == 2) { short baseMask = (short)(baseMask1 | baseMask2); int finAndBodyCount = baseMask.CountSet(); if (finAndBodyCount >= 5) { continue; } // Search (Finned) (Sashimi) X-Wing. for (int cs1 = coverSetStart, i = 0; cs1 < coverSetStart + 8; cs1++, i++) { // Check whether this cover set has 'digit'. if ((baseMask >> i & 1) == 0) { continue; } for (int cs2 = cs1 + 1, j = i + 1; cs2 < coverSetStart + 9; cs2++, j++) { // Check whether this cover set has 'digit'. if ((baseMask >> j & 1) == 0) { continue; } // Confirm all elimination cells. baseSets2[0] = bs1; baseSets2[1] = bs2; coverSets2[0] = cs1; coverSets2[1] = cs2; var bodyMap = GridMap.Empty; var elimMap = GridMap.Empty; GetGridMap(ref bodyMap, baseSets2, CandMaps[digit]); GetGridMap(ref elimMap, coverSets2, CandMaps[digit]); bodyMap &= elimMap; elimMap -= bodyMap; // Check the existence of fin. var finCellsMap = GridMap.Empty; if (finAndBodyCount == 2) // size == 2 { goto Label_CheckWhetherTheNumberOfIntersectionCellsIsNotZero; } // Confirm all fin cells. short finMask = (short)(baseMask & ~(1 << i | 1 << j) & 511); foreach (int baseSet in baseSets2) { foreach (int x in finMask.GetAllSets()) { int possibleFinCellOffset = RegionCells[baseSet][x]; if (CandMaps[digit][possibleFinCellOffset]) { finCellsMap.Add(possibleFinCellOffset); } } } // Check the number of fins is less than 3. if (finCellsMap.Count > 2) { continue; } // And all fins do not lie on any cover sets. var coverSetsMap = GridMap.Empty; foreach (int coverSet in coverSets2) { coverSetsMap |= RegionMaps[coverSet]; } if (coverSetsMap.Overlaps(finCellsMap)) { continue; } // Get intersection. foreach (int finCell in finCellsMap) { elimMap &= new GridMap(finCell); } Label_CheckWhetherTheNumberOfIntersectionCellsIsNotZero: // Check whether the number of intersection cells is not 0. if (elimMap.IsNotEmpty) { // Finned/Sashimi X-Wing found. // Check eliminations. var conclusions = new List <Conclusion>(); foreach (int offset in elimMap) { conclusions.Add(new Conclusion(Elimination, offset * 9 + digit)); } if (conclusions.Count == 0) { continue; } // Eliminations does exist. // Check all highlight candidates. var candidateOffsets = new List <(int, int)>(); foreach (int cell in bodyMap) { candidateOffsets.Add((0, cell * 9 + digit)); } if (finCellsMap.IsNotEmpty) { foreach (int cell in finCellsMap) { candidateOffsets.Add((1, cell * 9 + digit)); } } // Check the fish is sashimi, normal finned or normal. bool?isSashimi = null; if (finCellsMap.IsNotEmpty) { isSashimi = true; int finCell = finCellsMap.SetAt(0); int block = finCell / 9 / 3 * 3 + finCell % 9 / 3; foreach (int offset in bodyMap) { if (offset / 9 / 3 * 3 + offset % 9 / 3 == block) { isSashimi = false; break; } } } accumulator.Add( new NormalFishTechniqueInfo( conclusions, views: new[]
/// <inheritdoc/> public override void GetAll(IBag <TechniqueInfo> accumulator, IReadOnlyGrid grid) { for (int digit = 0; digit < 9; digit++) { for (int r1 = 0; r1 < 26; r1++) { for (int r2 = r1 + 1; r2 < 27; r2++) { // Get masks. short mask1 = grid.GetDigitAppearingMask(digit, r1); short mask2 = grid.GetDigitAppearingMask(digit, r2); if (mask1.CountSet() != 2 || mask2.CountSet() != 2) { continue; } // Get all cells. var map1 = GridMap.Empty; var map2 = GridMap.Empty; var cells1 = new List <int>(); var cells2 = new List <int>(); foreach (int pos1 in mask1.GetAllSets()) { int cell1 = RegionCells[r1][pos1]; cells1.Add(cell1); map1.Add(cell1); } foreach (int pos2 in mask2.GetAllSets()) { int cell2 = RegionCells[r2][pos2]; cells2.Add(cell2); map2.Add(cell2); } if ((map1 & map2).IsNotEmpty) { continue; } // Check two cells share a same region. int sameRegion; int headIndex, tailIndex, c1Index, c2Index; for (int i = 0; i < 2; i++) { int cell1 = cells1[i]; for (int j = 0; j < 2; j++) { int cell2 = cells2[j]; if (new GridMap { cell1, cell2 }.AllSetsAreInOneRegion(out sameRegion)) { (c1Index, c2Index, headIndex, tailIndex) = (i, j, i == 0 ? 1 : 0, j == 0 ? 1 : 0); goto Label_Checking; } } } // Not same block. continue; Label_Checking: // Two strong link found. // Record all eliminations. int head, tail; head = cells1[headIndex]; tail = cells2[tailIndex]; var conclusions = new List <Conclusion>(); var gridMap = new GridMap(head, false) & new GridMap(tail, false) & CandMaps[digit]; if (gridMap.IsEmpty) { continue; } foreach (int cell in gridMap) { conclusions.Add(new Conclusion(Elimination, cell, digit)); } if (conclusions.Count == 0) { continue; } accumulator.Add( new TwoStrongLinksTechniqueInfo( conclusions, views: new[]