/// <summary>
 /// Initializes an instance with the specified information.
 /// </summary>
 /// <param name="conclusions">All conclusions.</param>
 /// <param name="views">All views.</param>
 /// <param name="exocet">The exocet.</param>
 /// <param name="digits">All digits.</param>
 /// <param name="endoTargetCell">The endo target cell.</param>
 /// <param name="targetEliminations">The target eliminations.</param>
 /// <param name="trueBaseEliminations">The true base eliminations.</param>
 /// <param name="mirrorEliminations">The mirror eliminations.</param>
 /// <param name="compatibilityEliminations">The compatibility eliminations.</param>
 public SeniorExocetTechniqueInfo(
     IReadOnlyList <Conclusion> conclusions, IReadOnlyList <View> views, Exocet exocet,
     IEnumerable <int> digits, int endoTargetCell, TargetEliminations targetEliminations,
     TrueBaseEliminations trueBaseEliminations, MirrorEliminations mirrorEliminations,
     CompatibilityTestEliminations compatibilityEliminations)
     : base(
         conclusions, views, exocet, digits, TechniqueCode.Se, null, null,
         targetEliminations, mirrorEliminations, default, default, default,
         trueBaseEliminations, compatibilityEliminations) =>
Esempio n. 2
0
        /// <summary>
        /// Initializes an instance with the specified information.
        /// </summary>
        /// <param name="conclusions">All conclusions.</param>
        /// <param name="views">All views.</param>
        /// <param name="exocet">The exocet.</param>
        /// <param name="digits">All digits.</param>
        /// <param name="techniqueCode">The technique code.</param>
        /// <param name="lockedMemberQ">The locked member Q.</param>
        /// <param name="lockedMemberR">The locked member R.</param>
        /// <param name="targetEliminations">The target eliminations.</param>
        /// <param name="mirrorEliminations">The mirror eliminations.</param>
        /// <param name="bibiEliminations">
        /// The Bi-bi pattern eliminations (only used for junior exocets).
        /// </param>
        /// <param name="targetPairEliminations">
        /// The target pair eliminations (only used for junior exocets).
        /// </param>
        /// <param name="swordfishEliminations">
        /// The swordfish pattern eliminations (only used for junior exocets).
        /// </param>
        /// <param name="trueBaseEliminations">
        /// The true base eliminations (only used for senior exocets).
        /// </param>
        /// <param name="compatibilityEliminations">
        /// The compatibility test eliminations (only used for senior exocets).
        /// </param>
        public ExocetTechniqueInfo(
            IReadOnlyList <Conclusion> conclusions, IReadOnlyList <View> views,
            Exocet exocet, IEnumerable <int> digits, TechniqueCode techniqueCode,
            IEnumerable <int>?lockedMemberQ, IEnumerable <int>?lockedMemberR,
            TargetEliminations targetEliminations, MirrorEliminations mirrorEliminations,
            BibiPatternEliminations bibiEliminations, TargetPairEliminations targetPairEliminations,
            SwordfishEliminations swordfishEliminations, TrueBaseEliminations trueBaseEliminations,
            CompatibilityTestEliminations compatibilityEliminations)
            : base(conclusions, views)
        {
            (Exocet, Digits, TechniqueCode, LockedMemberQ, LockedMemberR) = (exocet, digits, techniqueCode, lockedMemberQ, lockedMemberR);

            var list = (List <Conclusion>)Conclusions;

            if (!((TargetEliminations = targetEliminations).Conclusions is null))
            {
                list.AddRange(TargetEliminations);
            }
            if (!((MirrorEliminations = mirrorEliminations).Conclusions is null))
            {
                list.AddRange(MirrorEliminations);
            }
            if (!((BibiEliminations = bibiEliminations).Conclusions is null))
            {
                list.AddRange(BibiEliminations);
            }
            if (!((TargetPairEliminations = targetPairEliminations).Conclusions is null))
            {
                list.AddRange(TargetPairEliminations);
            }
            if (!((SwordfishEliminations = swordfishEliminations).Conclusions is null))
            {
                list.AddRange(SwordfishEliminations);
            }
            if (!((TrueBaseEliminations = trueBaseEliminations).Conclusions is null))
            {
                list.AddRange(TrueBaseEliminations);
            }
            if (!((CompatibilityTestEliminations = compatibilityEliminations).Conclusions is null))
            {
                list.AddRange(CompatibilityTestEliminations);
            }

            var temp = Conclusions.Distinct().ToList();             // Call 'ToList' to execute the query forcedly.

            list.Clear();
            list.AddRange(temp);
        }
Esempio n. 3
0
        /// <inheritdoc/>
        public override void GetAll(IBag <TechniqueInfo> accumulator, IReadOnlyGrid grid)
        {
            var compatibleCellsPlayground = (Span <int>) stackalloc int[4];
            var cover = (Span <int>) stackalloc int[8];

            foreach (var exocet in Exocets)
            {
                var(baseMap, targetMap, _) = exocet;
                var(b1, b2, tq1, tq2, tr1, tr2, s, mq1, mq2, mr1, mr2) = exocet;
                if (grid.GetCandidatesReversal(b1).CountSet() < 2 ||
                    grid.GetCandidatesReversal(b2).CountSet() < 2)
                {
                    continue;
                }

                var baseCellsMap = new GridMap {
                    b1, b2
                };
                bool isRow            = baseCellsMap.CoveredLine < 18;
                var  tempCrosslineMap = new GridMap(s)
                {
                    tq1, tq2, tr1, tr2
                };
                short baseCandidatesMask = (short)(grid.GetCandidatesReversal(b1) | grid.GetCandidatesReversal(b2));

                int i = 0;
                int r = GetRegion(b1, RegionLabel.Row) - 9, c = GetRegion(b1, RegionLabel.Column) - 18;
                foreach (int pos in ((short)(511 & ~(1 << (isRow ? r : c)))).GetAllSets())
                {
                    cover[i++] = isRow ? pos : pos + 9;
                }

                i = 0;
                var temp = default(GridMap);
                foreach (int digit in baseCandidatesMask.GetAllSets())
                {
                    if (i++ == 0)
                    {
                        temp = ValueMaps[digit];
                    }
                    else
                    {
                        temp |= ValueMaps[digit];
                    }
                }
                temp &= tempCrosslineMap;

                var tempTarget = new List <int>();
                for (i = 0; i < 8; i++)
                {
                    var check = temp & RegionMaps[cover[i] + 9];
                    if (check.Count != 1)
                    {
                        continue;
                    }

                    tempTarget.Add(check.SetAt(0));
                }
                if (tempTarget.Count == 0)
                {
                    continue;
                }

                int borT = isRow ? b1 / 9 / 3 : b1 % 9 / 3;                 // Base or target (B or T).
                foreach (int[] combination in GetCombinationsOfArray(tempTarget.ToArray(), 2))
                {
                    if (isRow
                                                ? combination[0] / 9 / 3 == borT && combination[1] / 9 / 3 == borT
                                                : combination[0] % 9 / 3 == borT && combination[1] % 9 / 3 == borT)
                    {
                        continue;
                    }

                    int row1    = GetRegion(combination[0], RegionLabel.Row);
                    int column1 = GetRegion(combination[0], RegionLabel.Column);
                    int row2    = GetRegion(combination[1], RegionLabel.Row);
                    int column2 = GetRegion(combination[1], RegionLabel.Column);
                    if (isRow ? column1 == column2 : row1 == row2)
                    {
                        continue;
                    }

                    short elimDigits = (short)((
                                                   grid.GetCandidatesReversal(combination[0])
                                                   | grid.GetCandidatesReversal(combination[1])) & ~baseCandidatesMask);
                    if (!CheckCrossline(
                            /*baseCellsMap, */ tempCrosslineMap, ValueMaps, baseCandidatesMask,
                            combination[0], combination[1], isRow, out int extraRegionsMask))
                    {
                        continue;
                    }

                    var   targetElims = new TargetEliminations();
                    short cands       = (short)(elimDigits & grid.GetCandidatesReversal(combination[0]));
                    if (cands != 0)
                    {
                        foreach (int digit in cands.GetAllSets())
                        {
                            targetElims.Add(new Conclusion(Elimination, combination[0], digit));
                        }
                    }
                    cands = (short)(elimDigits & grid.GetCandidatesReversal(combination[1]));
                    if (cands != 0)
                    {
                        foreach (int digit in cands.GetAllSets())
                        {
                            targetElims.Add(new Conclusion(Elimination, combination[1], digit));
                        }
                    }

                    short tbCands = 0;
                    for (int j = 0; j < 2; j++)
                    {
                        if (grid.GetCandidatesReversal(combination[j]).CountSet() == 1)
                        {
                            tbCands |= grid.GetCandidatesReversal(combination[j]);
                        }
                    }

                    var trueBaseElims = new TrueBaseEliminations();
                    if (tbCands != 0 &&
                        (grid.GetStatus(combination[0]) != Empty || grid.GetStatus(combination[1]) != Empty))
                    {
                        for (int j = 0; j < 2; j++)
                        {
                            if (grid.GetStatus(combination[j]) != Empty)
                            {
                                continue;
                            }

                            if ((cands = (short)(grid.GetCandidatesReversal(combination[j]) & tbCands)) == 0)
                            {
                                continue;
                            }

                            foreach (int digit in cands.GetAllSets())
                            {
                                trueBaseElims.Add(new Conclusion(Elimination, combination[j], digit));
                            }
                        }
                    }

                    if (tbCands != 0)
                    {
                        foreach (int digit in tbCands.GetAllSets())
                        {
                            var elimMap = (baseCellsMap & CandMaps[digit]).PeerIntersection & CandMaps[digit];
                            if (elimMap.IsEmpty)
                            {
                                continue;
                            }

                            foreach (int cell in elimMap)
                            {
                                trueBaseElims.Add(new Conclusion(Elimination, cell, digit));
                            }
                        }
                    }

                    var mirrorElims        = new MirrorEliminations();
                    var compatibilityElims = new CompatibilityTestEliminations();
                    int target             = -1;
                    var mir = default(GridMap);

                    var cellOffsets = new List <(int, int)> {
                        (0, b1), (0, b2)
                    };
                    foreach (int cell in tempCrosslineMap)
                    {
                        cellOffsets.Add((cell == combination[0] || cell == combination[1] ? 1 : 2, cell));
                    }
                    var candidateOffsets = new List <(int, int)>();
                    if (_checkAdvanced)
                    {
                        for (int k = 0; k < 2; k++)
                        {
                            if (combination[k] == tq1 && (baseCandidatesMask & grid.GetCandidatesReversal(tr2)) == 0)
                            {
                                target = combination[k];
                                mir    = mq1;
                            }
                            if (combination[k] == tq2 && (baseCandidatesMask & grid.GetCandidatesReversal(tr1)) == 0)
                            {
                                target = combination[k];
                                mir    = mq2;
                            }
                            if (combination[k] == tr1 && (baseCandidatesMask & grid.GetCandidatesReversal(tq2)) == 0)
                            {
                                target = combination[k];
                                mir    = mr1;
                            }
                            if (combination[k] == tr2 && (baseCandidatesMask & grid.GetCandidatesReversal(tq1)) == 0)
                            {
                                target = combination[k];
                                mir    = mr2;
                            }
                        }

                        if (target != -1)
                        {
                            var(tempTargetElims, tempMirrorElims) = CheckMirror(
                                grid, target, combination[target == combination[0] ? 1 : 0], 0,
                                baseCandidatesMask, mir, 0, -1, cellOffsets, candidateOffsets);
                            targetElims = TargetEliminations.MergeAll(targetElims, tempTargetElims);
                            mirrorElims = MirrorEliminations.MergeAll(mirrorElims, tempMirrorElims);
                        }

                        short incompatible = CompatibilityTest(
                            baseCandidatesMask, ValueMaps, tempCrosslineMap, baseCellsMap,
                            combination[0], combination[1]);
                        if (incompatible != 0)
                        {
                            compatibleCellsPlayground[0] = b1;
                            compatibleCellsPlayground[1] = b2;
                            compatibleCellsPlayground[2] = combination[0];
                            compatibleCellsPlayground[3] = combination[1];

                            for (int k = 0; k < 4; k++)
                            {
                                cands = (short)(incompatible & grid.GetCandidatesReversal(compatibleCellsPlayground[k]));
                                if (cands == 0)
                                {
                                    continue;
                                }

                                foreach (int digit in cands.GetAllSets())
                                {
                                    compatibilityElims.Add(
                                        new Conclusion(Elimination, compatibleCellsPlayground[k], digit));
                                }
                            }
                        }

                        CompatibilityTest2(
                            grid, ref compatibilityElims, baseCellsMap, baseCandidatesMask,
                            combination[0], combination[1]);
                    }

                    if (_checkAdvanced
                                                ? mirrorElims.Count == 0 && compatibilityElims.Count == 0 &&
                        targetElims.Count == 0 && trueBaseElims.Count == 0
                                                : mirrorElims.Count == 0 && compatibilityElims.Count == 0)
                    {
                        continue;
                    }

                    int   endoTargetCell = combination[s[combination[0]] ? 0 : 1];
                    short m1             = grid.GetCandidatesReversal(b1);
                    short m2             = grid.GetCandidatesReversal(b2);
                    short m = (short)(m1 | m2);
                    foreach (int digit in m1.GetAllSets())
                    {
                        candidateOffsets.Add((0, b1 * 9 + digit));
                    }
                    foreach (int digit in m2.GetAllSets())
                    {
                        candidateOffsets.Add((0, b2 * 9 + digit));
                    }

                    // Record extra region cells (mutant exocets).
                    foreach (int region in extraRegionsMask.GetAllSets())
                    {
                        foreach (int cell in RegionCells[region])
                        {
                            if (tempCrosslineMap[cell] || b1 == cell || b2 == cell)
                            {
                                continue;
                            }

                            cellOffsets.Add((2, cell));
                        }
                    }

                    accumulator.Add(
                        new SeniorExocetTechniqueInfo(
                            conclusions: new List <Conclusion>(),
                            views: new[]
                    {
                        new View(
                            cellOffsets,
                            candidateOffsets,
                            regionOffsets: null,
                            links: null)
                    },
                            exocet,
                            digits: m.GetAllSets(),
                            endoTargetCell,
                            targetEliminations: targetElims,
                            trueBaseEliminations: trueBaseElims,
                            mirrorEliminations: mirrorElims,
                            compatibilityEliminations: compatibilityElims));
                }
            }
        }