Пример #1
0
        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[]