/// <summary>
        /// Rotate the grid counter-clockwise.
        /// </summary>
        /// <param name="this">(<see langword="this"/> parameter) The grid.</param>
        /// <returns>The result.</returns>
        public static Grid RotateCounterClockwise(this IReadOnlyGrid @this)
        {
            var result = @this.Clone();

            for (int i = 0; i < 81; i++)
            {
                int   z    = CounterClockwiseTable[i];
                short temp = result.GetMask(i);
                result.SetMask(i, result.GetMask(z));
                result.SetMask(z, temp);
            }
            return(result);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Indicates whether the specified grid contains the digit.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <param name="digit">The digit.</param>
        /// <param name="result">(<see langword="out"/> parameter) The result.</param>
        /// <returns>A <see cref="bool"/> value.</returns>
        public bool ContainsDigit(IReadOnlyGrid grid, int digit, out GridMap result)
        {
            result = GridMap.Empty;
            foreach (int cell in Map)
            {
                if ((grid.GetCandidatesReversal(cell) >> digit & 1) != 0)
                {
                    result.Add(cell);
                }
            }

            return(result.IsNotEmpty);
        }
Ejemplo n.º 3
0
 public static IEnumerable <Point2> TilesOfType(this IReadOnlyGrid <TileType> map, TileType type)
 {
     for (var y = 0; y < map.Height; y++)
     {
         for (var x = 0; x < map.Width; x++)
         {
             if (map[x, y] == type)
             {
                 yield return(new Point2(x, y));
             }
         }
     }
 }
Ejemplo n.º 4
0
        /// <inheritdoc/>
        public override void GetAll(IBag <TechniqueInfo> accumulator, IReadOnlyGrid grid)
        {
            if (EmptyMap.Count < 4)
            {
                // SdC needs at least 4 cells like:
                // abc abd | ab
                // cd      |
                return;
            }

            var list = new List <GridMap>(4);

            foreach (bool cannibalMode in stackalloc[] { false, true })
Ejemplo n.º 5
0
 /// <summary>
 /// To check if the puzzle is diamond or not.
 /// </summary>
 /// <param name="this">(<see langword="this"/> parameter) The puzzle to check.</param>
 /// <returns>A <see cref="bool"/> value indicating that.</returns>
 public static bool IsDiamond(this IReadOnlyGrid @this)
 {
     // Using a faster solver to check the grid is unique or not.
     if (@this.IsValid(out _))
     {
         var result = new ManualSolver().Solve(@this);
         var(er, pr, dr) = (result.MaxDifficulty, result.PearlDifficulty, result.DiamondDifficulty);
         return(er == pr && er == dr);
     }
     else
     {
         // The puzzle does not have unique solution, neither pearl nor diamond one.
         return(false);
     }
 }
Ejemplo n.º 6
0
        /// <summary>
        /// To check if a puzzle has only one solution or not.
        /// </summary>
        /// <param name="this">(<see langword="this"/> parameter) The puzzle to check.</param>
        /// <param name="solutionIfValid">
        /// (<see langword="out"/> parameter) The solution if the puzzle is valid;
        /// otherwise, <see langword="null"/>.
        /// </param>
        /// <returns>A <see cref="bool"/> value indicating that.</returns>
        public static bool IsValid(this IReadOnlyGrid @this, [NotNullWhen(true)] out IReadOnlyGrid?solutionIfValid)
        {
            solutionIfValid = null;

            if (new BitwiseSolver().CheckValidity(@this.ToString(), out string?solution) ||
                new SukakuBitwiseSolver().CheckValidity(@this.ToString("~"), out solution))
            {
                solutionIfValid = Grid.Parse(solution);
                return(true);
            }
            else
            {
                return(false);
            }
        }
Ejemplo n.º 7
0
        /// <inheritdoc/>
        public override void GetAll(IBag <TechniqueInfo> accumulator, IReadOnlyGrid grid)
        {
            var r = (Span <int>) stackalloc int[2];

            foreach (var((baseSet, coverSet), (a, b, c)) in IntersectionMaps)
            {
                if (!EmptyMap.Overlaps(c))
                {
                    continue;
                }

                short m1 = BitwiseOrMasks(grid, a);
                short m2 = BitwiseOrMasks(grid, b);
                short m3 = BitwiseOrMasks(grid, c);
                short m  = (short)(m3 & (m1 ^ m2));
                if (m == 0)
                {
                    continue;
                }

                foreach (int digit in m.GetAllSets())
                {
                    GridMap elimMap;
                    (r[0], r[1], elimMap) =
                        a.Overlaps(CandMaps[digit])
                                                        ? (coverSet, baseSet, a & CandMaps[digit])
                                                        : (baseSet, coverSet, b & CandMaps[digit]);
                    if (elimMap.IsEmpty)
                    {
                        continue;
                    }

                    var conclusions = new List <Conclusion>();
                    foreach (int cell in elimMap)
                    {
                        conclusions.Add(new Conclusion(Elimination, cell, digit));
                    }

                    var candidateOffsets = new List <(int, int)>();
                    foreach (int cell in c& CandMaps[digit])
                    {
                        candidateOffsets.Add((0, cell * 9 + digit));
                    }

                    accumulator.Add(
                        new LcTechniqueInfo(
                            conclusions,
                            views: new[]
        /// <summary>
        /// Mirror top-bottom the grid.
        /// </summary>
        /// <param name="this">(<see langword="this"/> parameter) The grid.</param>
        /// <returns>The result grid.</returns>
        public static Grid MirrorTopBottom(this IReadOnlyGrid @this)
        {
            var result = @this.Clone();

            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    short temp = result.GetMask(i * 9 + j);
                    result.SetMask(i * 9 + j, result.GetMask((8 - i) * 9 + j));
                    result.SetMask((8 - i) * 9 + j, temp);
                }
            }

            return(result);
        }
        /// <summary>
        /// Mirror diagonal the grid.
        /// </summary>
        /// <param name="this">(<see langword="this"/> parameter) The grid.</param>
        /// <returns>The result grid.</returns>
        public static Grid MirrorDiagonal(this IReadOnlyGrid @this)
        {
            var result = @this.Clone();

            for (int i = 1; i < 9; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    short temp = result.GetMask(i * 9 + j);
                    result.SetMask(i * 9 + j, result.GetMask(j * 9 + i));
                    result.SetMask(j * 9 + i, temp);
                }
            }

            return(result);
        }
Ejemplo n.º 10
0
        public void Test_Set_BusinessObjectCollectionOnGrid_NoOfRows()
        {
            //---------------Set up test pack-------------------
            MyBO.LoadDefaultClassDef();
            BusinessObjectCollection <MyBO> col = CreateCollectionWith_4_Objects();
            IReadOnlyGrid readOnlyGrid          = GetControlFactory().CreateReadOnlyGrid();

            DisposeOnTearDown(readOnlyGrid);
            AddControlToForm(readOnlyGrid);
            SetupGridColumnsForMyBo(readOnlyGrid);
            //---------------Execute Test ----------------------
            readOnlyGrid.BusinessObjectCollection = col;
            //---------------Test Result -----------------------
            Assert.AreEqual(4, readOnlyGrid.Rows.Count);
            //---------------Tear Down -------------------------
        }
        /// <summary>
        /// Mirror anti-diagonal the grid.
        /// </summary>
        /// <param name="this">(<see langword="this"/> parameter) The grid.</param>
        /// <returns>The result grid.</returns>
        public static Grid MirrorAntidiagonal(this IReadOnlyGrid @this)
        {
            var result = @this.Clone();

            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 8 - i; j++)
                {
                    short temp = result.GetMask(i * 9 + j);
                    result.SetMask(i * 9 + j, result.GetMask((8 - j) * 9 + (8 - i)));
                    result.SetMask((8 - j) * 9 + (8 - i), temp);
                }
            }

            return(result);
        }
        /// <summary>
        /// Mirror left-right the grid.
        /// </summary>
        /// <param name="this">(<see langword="this"/> parameter) The grid.</param>
        /// <returns>The result grid.</returns>
        public static Grid MirrorLeftRight(this IReadOnlyGrid @this)
        {
            var result = @this.Clone();

            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    short temp = result.GetMask(i * 9 + j);
                    result.SetMask(i * 9 + j, result.GetMask(i * 9 + (8 - j)));
                    result.SetMask(i * 9 + (8 - j), temp);
                }
            }

            return(result);
        }
Ejemplo n.º 13
0
        private bool RecordTechnique(
            List <TechniqueInfo> steps, TechniqueInfo step, IReadOnlyGrid grid,
            Grid cloneation, Stopwatch stopwatch, IBag <IReadOnlyGrid> stepGrids,
            [NotNullWhen(true)] out AnalysisResult?result)
        {
            bool needAdd = false;

            foreach (var(t, c, d) in step.Conclusions)
            {
                switch (t)
                {
                case Assignment when cloneation.GetStatus(c) == CellStatus.Empty:
                case Elimination when cloneation.Exists(c, d) is true:
                {
                    needAdd = true;

                    goto Label_Determine;
                }
                }
            }

Label_Determine:
            if (needAdd)
            {
                stepGrids.Add(cloneation.Clone());
                step.ApplyTo(cloneation);
                steps.Add(step);

                if (cloneation.HasSolved)
                {
                    result = new AnalysisResult(
                        puzzle: grid,
                        solverName: SolverName,
                        hasSolved: true,
                        solution: cloneation,
                        elapsedTime: stopwatch.Elapsed,
                        solvingList: steps,
                        additional: null,
                        stepGrids);
                    return(true);
                }
            }

            result = null;
            return(false);
        }
Ejemplo n.º 14
0
        protected override int SelectedIndex(IBOColSelectorControl colSelector)
        {
            IReadOnlyGrid    gridSelector = ((IReadOnlyGridControl)colSelector).Grid;
            IDataGridViewRow currentRow   = null;

            if (gridSelector.SelectedRows.Count > 0)
            {
                currentRow = gridSelector.SelectedRows[0];
            }

            if (currentRow == null)
            {
                return(-1);
            }

            return(gridSelector.Rows.IndexOf(currentRow));
        }
Ejemplo n.º 15
0
        /// <summary>
        /// To check the validity of all conclusions.
        /// </summary>
        /// <param name="solution">The solution.</param>
        /// <param name="conclusions">The conclusions.</param>
        /// <returns>A <see cref="bool"/> indicating that.</returns>
        private static bool CheckConclusionsValidity(IReadOnlyGrid solution, IEnumerable <Conclusion> conclusions)
        {
            foreach (var(t, c, d) in conclusions)
            {
                int digit = solution[c];
                switch (t)
                {
                case Assignment when digit != d:
                case Elimination when digit == d:
                {
                    return(false);
                }
                }
            }

            return(true);
        }
Ejemplo n.º 16
0
 public static IEnumerable <Point2> NeighboursOfType(this IReadOnlyGrid <TileType> map, Point2 middle, TileType type, bool cornersIncluded = false)
 {
     for (var y = -1; y <= 1; y++)
     {
         for (var x = -1; x <= 1; x++)
         {
             if (!cornersIncluded && Math.Abs(x) == Math.Abs(y))
             {
                 continue;
             }
             if (map.At(x, y) == type)
             {
                 yield return(new Point2(middle.X + x, middle.Y + y));
             }
         }
     }
 }
        /// <summary>
        /// Search for all W-Wings.
        /// </summary>
        /// <param name="result">The result accumulator.</param>
        /// <param name="grid">The grid.</param>
        /// <returns>All technique information instances.</returns>
        public static void TakeAllWWings(IBag <TechniqueInfo> result, IReadOnlyGrid grid)
        {
            if (BivalueMap.Count < 2)
            {
                return;
            }

            // Iterate on each cells.
            for (int c1 = 0; c1 < 72; c1++)
            {
                if (!BivalueMap[c1] || !EmptyMap[c1])
                {
                    continue;
                }

                // Iterate on each cells which are not peers in 'c1'.
                int[] digits = grid.GetCandidatesReversal(c1).GetAllSets().ToArray();
                foreach (int c2 in BivalueMap - new GridMap(c1))
                {
                    if (c2 < c1 || grid.GetCandidatesReversal(c1) != grid.GetCandidatesReversal(c2))
                    {
                        continue;
                    }

                    var intersection = new GridMap(c1, false) & new GridMap(c2, false);
                    if (!EmptyMap.Overlaps(intersection))
                    {
                        continue;
                    }

                    for (int region = 9; region < 27; region++)
                    {
                        if (region < 18 && (
                                GetRegion(c1, RegionLabel.Row) == region || GetRegion(c2, RegionLabel.Row) == region) ||
                            region >= 18 && (
                                GetRegion(c1, RegionLabel.Column) == region || GetRegion(c2, RegionLabel.Column) == region))
                        {
                            continue;
                        }

                        SearchWWingByRegions(result, grid, digits, region, c1, c2, intersection);
                    }
                }
            }
        }
        /// <summary>
        /// Searches W-Wing technique by region.
        /// </summary>
        /// <param name="result">The result.</param>
        /// <param name="grid">The grid.</param>
        /// <param name="digits">The digits.</param>
        /// <param name="region">The region.</param>
        /// <param name="c1">Cell 1.</param>
        /// <param name="c2">Cell 2.</param>
        /// <param name="intersection">The intersection.</param>
        private static void SearchWWingByRegions(
            IBag <TechniqueInfo> result, IReadOnlyGrid grid, int[] digits, int region,
            int c1, int c2, GridMap intersection)
        {
            for (int i = 0; i < 2; i++)
            {
                int digit = digits[i];
                if (!grid.IsBilocationRegion(digit, region, out short mask))
                {
                    continue;
                }

                int pos1 = mask.FindFirstSet(), pos2 = mask.GetNextSet(pos1);
                int bridgeStart = RegionCells[region][pos1], bridgeEnd = RegionCells[region][pos2];
                if (c1 == bridgeStart || c2 == bridgeStart || c1 == bridgeEnd || c2 == bridgeEnd)
                {
                    continue;
                }
Ejemplo n.º 19
0
        public void TestCreateGridBase()
        {
            //---------------Set up test pack-------------------
            //---------------Execute Test ----------------------
            IControlHabanero grid = GetControlFactory().CreateReadOnlyGrid();

            DisposeOnTearDown(grid);
            ////---------------Test Result -----------------------
            Assert.IsNotNull(grid);
            Assert.IsTrue(grid is IReadOnlyGrid);
            IReadOnlyGrid readOnlyGrid = (IReadOnlyGrid)grid;

            readOnlyGrid.ReadOnly              = true;
            readOnlyGrid.AllowUserToAddRows    = false;
            readOnlyGrid.AllowUserToDeleteRows = false;
            //Need interfact to test selectionMode not sure if worth it.
            //see when implementing for windows.
            //  readOnlyGrid.SelectionMode = Gizmox.WebGUI.Forms.DataGridViewSelectionMode.FullRowSelect;
        }
Ejemplo n.º 20
0
        /// <inheritdoc/>
        public override void GetAll(IBag <TechniqueInfo> accumulator, IReadOnlyGrid grid)
        {
            var templates = GetInvalidPos(grid);

            for (int digit = 0; digit < 9; digit++)
            {
                var template = templates[digit];
                if (template.IsEmpty)
                {
                    continue;
                }

                accumulator.Add(
                    new PomTechniqueInfo(
                        conclusions:
                        new List <Conclusion>(from cell in template select new Conclusion(Elimination, cell, digit)),
                        views: View.DefaultViews));
            }
        }
Ejemplo n.º 21
0
        public void Test_GetBusinessObjectAtRow_WhenSetViaCustomLoad_ShouldRetBO()
        {
            //---------------Set up test pack-------------------
            MyBO.LoadDefaultClassDef();
            BusinessObjectCollection <MyBO> col = CreateCollectionWith_4_Objects();
            IReadOnlyGrid readOnlyGrid          = GetControlFactory().CreateReadOnlyGrid();

            DisposeOnTearDown(readOnlyGrid);
            AddControlToForm(readOnlyGrid);
            SetupGridColumnsForMyBo(readOnlyGrid);
            readOnlyGrid.BusinessObjectCollection = col;
            //---------------Assert Precondition----------------
            Assert.AreEqual(4, readOnlyGrid.Rows.Count);
            //---------------Execute Test ----------------------
            var actualBO = readOnlyGrid.GetBusinessObjectAtRow(1);

            //---------------Test Result -----------------------
            Assert.AreSame(col[1], actualBO);
        }
Ejemplo n.º 22
0
        protected override void SetSelectedIndex(IBOColSelectorControl colSelector, int index)
        {
            int count = 0;

            IReadOnlyGrid readOnlyGrid = ((IReadOnlyGridControl)colSelector).Grid;

            foreach (IDataGridViewRow row in readOnlyGrid.Rows)
            {
                if (row == null)
                {
                    continue;             //This is done to stop the Pragma warning.
                }
                if (count == index)
                {
                    IBusinessObject businessObjectAtRow = readOnlyGrid.GetBusinessObjectAtRow(count);
                    colSelector.SelectedBusinessObject = businessObjectAtRow;
                }
                count++;
            }
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Search all backdoors whose level is lower or equals than the
        /// specified depth.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <param name="depth">
        /// The depth you want to search for. The depth value must be between 0 and 3.
        /// where value 0 is for searching for assignments.
        /// </param>
        /// <returns>All backdoors.</returns>
        /// <exception cref="SudokuRuntimeException">
        /// Throws when the specified grid is invalid.
        /// </exception>
        public IEnumerable <IReadOnlyList <Conclusion> > SearchForBackdoors(IReadOnlyGrid grid, int depth)
        {
            if (depth < 0 || depth > 3)
            {
                return(Array.Empty <IReadOnlyList <Conclusion> >());
            }

            if (!grid.IsValid(out _))
            {
                throw new SudokuRuntimeException();
            }

            var result = new List <IReadOnlyList <Conclusion> >();

            for (int dep = 0; dep <= depth; dep++)
            {
                SearchForBackdoors(result, grid, dep);
            }

            return(result);
        }
Ejemplo n.º 24
0
        void DrawInternal(TextWriter stream, IReadOnlyGrid <TCell> grid, IEnumerable <Point> possibleMovePoints, TCell owner)
        {
            var possibleMovePointSet = new HashSet <Point>(possibleMovePoints);

            for (int y = 0; y < grid.Height; y++)
            {
                for (int x = 0; x < grid.Width; x++)
                {
                    if (possibleMovePointSet.Contains(new Point(x, y)))
                    {
                        stream.Write(possibleMovePointCharacter);
                    }
                    else
                    {
                        var cell = grid.GetCell(x, y);
                        stream.Write(cellCharacterMap[cell]);
                    }
                }
                stream.WriteLine();
            }
        }
Ejemplo n.º 25
0
        /// <inheritdoc/>
        public override AnalysisResult Solve(IReadOnlyGrid grid)
        {
            _grid = grid;

            int[] gridValues = grid.ToArray();
            int[]? result = null;
            int solutionsCount = 0;
            var stopwatch      = new Stopwatch();

            try
            {
                stopwatch.Start();
                BacktrackinglySolve(ref solutionsCount, ref result, gridValues, 0);
                stopwatch.Stop();

                return(new AnalysisResult(
                           puzzle: grid,
                           solverName: SolverName,
                           hasSolved: true,
                           solution: Grid.CreateInstance(result ?? throw new NoSolutionException(grid)),
                           elapsedTime: stopwatch.Elapsed,
                           solvingList: null,
                           additional: null,
                           stepGrids: null));
            }
            catch (Exception ex)
            {
                stopwatch.Stop();

                return(new AnalysisResult(
                           puzzle: grid,
                           solverName: SolverName,
                           hasSolved: false,
                           solution: null,
                           elapsedTime: stopwatch.Elapsed,
                           solvingList: null,
                           additional: ex.Message,
                           stepGrids: null));
            }
        }
Ejemplo n.º 26
0
 /// <inheritdoc/>
 public override AnalysisResult Solve(IReadOnlyGrid grid)
 {
     if (grid.IsValid(out var solution, out bool?sukaku))
     {
         // Solve the puzzle.
         try
         {
             return(AnalyzeDifficultyStrictly
                                         ? SolveWithStrictDifficultyRating(
                        grid, grid.Clone(), new List <TechniqueInfo>(), solution, sukaku.Value)
                                         : SolveNaively(grid, grid.Clone(), new List <TechniqueInfo>(), solution, sukaku.Value));
         }
         catch (WrongHandlingException ex)
         {
             return(new AnalysisResult(
                        puzzle: grid,
                        solverName: SolverName,
                        hasSolved: false,
                        solution: null,
                        elapsedTime: TimeSpan.Zero,
                        solvingList: null,
                        additional: ex.Message,
                        stepGrids: null));
         }
     }
     else
     {
         return(new AnalysisResult(
                    puzzle: grid,
                    solverName: SolverName,
                    hasSolved: false,
                    solution: null,
                    elapsedTime: TimeSpan.Zero,
                    solvingList: null,
                    additional: "The puzzle does not have a unique solution (multiple solutions or no solution).",
                    stepGrids: null));
     }
 }
Ejemplo n.º 27
0
        /// <summary>
        /// Get all invalid positions.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <returns>The 9 maps for invalid positions of each digit.</returns>
        private static GridMap[] GetInvalidPos(IReadOnlyGrid grid)
        {
            var result     = new GridMap[9];
            var invalidPos = new GridMap[9];
            var mustPos    = new GridMap[9];

            for (int digit = 0; digit < 9; digit++)
            {
                for (int cell = 0; cell < 81; cell++)
                {
                    if ((grid.GetCandidatesReversal(cell) >> digit & 1) == 0)
                    {
                        invalidPos[digit].Add(cell);
                    }
                    else if (grid[cell] == digit)
                    {
                        mustPos[digit].Add(cell);
                    }
                }
            }

            for (int digit = 0; digit < 9; digit++)
            {
                foreach (var map in GetTemplates())
                {
                    if ((mustPos[digit] - map).IsNotEmpty || invalidPos[digit].Overlaps(map))
                    {
                        continue;
                    }

                    result[digit] |= map;
                }

                result[digit] = CandMaps[digit] - result[digit];
            }

            return(result);
        }
Ejemplo n.º 28
0
        /// <inheritdoc/>
        public override AnalysisResult Solve(IReadOnlyGrid grid)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var results = SolveStrings(grid.ToString("0"));

            stopwatch.Stop();

            return(results.Count switch
            {
                0 => throw new NoSolutionException(grid),
                1 =>
                new AnalysisResult(
                    puzzle: grid,
                    solverName: SolverName,
                    hasSolved: true,
                    solution: Grid.Parse(results[0]),
                    elapsedTime: stopwatch.Elapsed,
                    solvingList: null,
                    additional: null,
                    stepGrids: null),
                _ => throw new MultipleSolutionsException(grid)
            });
        public MultipleRelationshipReadOnlyGridMapper(IReadOnlyGrid readOnlyGrid, string relationshipName)
            : this(readOnlyGrid, relationshipName, false, GlobalUIRegistry.ControlFactory)
        {

        }
 private ReadOnlyGridMapper CreateReadOnlyGridMapper(IReadOnlyGrid readOnlyGrid, string propName)
 {
     return new ReadOnlyGridMapper(readOnlyGrid, propName, false, GetControlFactory());
 }
 public static Grid Transpose(this IReadOnlyGrid @this) => @this.MirrorDiagonal();
Ejemplo n.º 32
0
        partial void CheckType1(
            IList <UrTechniqueInfo> accumulator, IReadOnlyGrid grid, int[] urCells, bool arMode,
            short comparer, int d1, int d2, int cornerCell, GridMap otherCellsMap)
        {
            //   ↓ cornerCell
            // (abc) ab
            //  ab   ab

            // Get the summary mask.
            short mask = 0;

            foreach (int cell in otherCellsMap)
            {
                mask |= grid.GetCandidatesReversal(cell);
            }

            if (mask != comparer)
            {
                return;
            }

            // Type 1 found. Now check elimination.
            var conclusions = new List <Conclusion>();

            if (grid.Exists(cornerCell, d1) is true)
            {
                conclusions.Add(new Conclusion(Elimination, cornerCell, d1));
            }
            if (grid.Exists(cornerCell, d2) is true)
            {
                conclusions.Add(new Conclusion(Elimination, cornerCell, d2));
            }
            if (conclusions.Count == 0)
            {
                return;
            }

            var candidateOffsets = new List <(int, int)>();

            foreach (int cell in otherCellsMap)
            {
                foreach (int digit in grid.GetCandidatesReversal(cell).GetAllSets())
                {
                    candidateOffsets.Add((0, cell * 9 + digit));
                }
            }
            if (!_allowIncompletedUr && (candidateOffsets.Count != 6 || conclusions.Count != 2))
            {
                return;
            }

            accumulator.Add(
                new UrType1TechniqueInfo(
                    conclusions,
                    views: new[]
            {
                new View(
                    cellOffsets: arMode ? GetHighlightCells(urCells) : null,
                    candidateOffsets: arMode ? null : candidateOffsets,
                    regionOffsets: null,
                    links: null)
            },
                    digit1: d1,
                    digit2: d2,
                    cells: urCells,
                    isAr: arMode));
        }
Ejemplo n.º 33
0
 /// <summary>
 /// Constructor for the mapper.
 /// </summary>
 /// <param name="ctl">The IEditableGridControl</param>
 /// <param name="relationshipName">This is the relationship name to use - this relationship must be a multiple relationship and exist on the BusinessObject</param>
 /// <param name="isReadOnly">Whether the editable grid should be read only or not. Ignored</param>
 /// <param name="factory">The control factory to use</param>
 public ReadOnlyGridMapper(IReadOnlyGrid ctl, string relationshipName, bool isReadOnly, IControlFactory factory)
     : base(ctl, relationshipName, isReadOnly, factory)
 {
     _readOnlyGrid = ctl;
     _gridInitialiser = new GridBaseInitialiser(ctl, factory);
 }
 private static MultipleRelationshipReadOnlyGridMapper CreateMultipleRelationshipReadOnlyGridMapper(IReadOnlyGrid grid, string propName)
 {
     return new MultipleRelationshipReadOnlyGridMapper(grid, propName, false, GetControlFactory());
 }
 public MultipleRelationshipReadOnlyGridMapper(IReadOnlyGrid readOnlyGrid, string relationshipName, bool isReadOnly, IControlFactory factory)
     : base(readOnlyGrid, relationshipName, isReadOnly, factory)
 {
     Grid = readOnlyGrid;
 }
Ejemplo n.º 36
0
        private static void DrawTileHighlights(Canvas canvas, ICmpTilemapRenderer renderer, Point2 origin, IReadOnlyGrid<bool> highlight, ColorRgba fillTint, ColorRgba outlineTint, TileHighlightMode mode, List<Vector2[]> outlineCache = null)
        {
            if (highlight.Width == 0 || highlight.Height == 0) return;

            // Generate strippled line texture if not available yet
            if (strippledLineTex == null)
            {
                PixelData pixels = new PixelData(8, 1);
                for (int i = 0; i < pixels.Width / 2; i++)
                    pixels[i, 0] = ColorRgba.White;
                for (int i = pixels.Width / 2; i < pixels.Width; i++)
                    pixels[i, 0] = ColorRgba.TransparentWhite;

                using (Pixmap pixmap = new Pixmap(pixels))
                {
                    strippledLineTex = new Texture(pixmap,
                        TextureSizeMode.Default,
                        TextureMagFilter.Nearest,
                        TextureMinFilter.Nearest,
                        TextureWrapMode.Repeat,
                        TextureWrapMode.Repeat,
                        TexturePixelFormat.Rgba);
                }
            }

            BatchInfo defaultMaterial = new BatchInfo(DrawTechnique.Alpha, canvas.State.Material.MainColor);
            BatchInfo strippleMaterial = new BatchInfo(DrawTechnique.Alpha, canvas.State.Material.MainColor, strippledLineTex);
            bool uncertain = (mode & TileHighlightMode.Uncertain) != 0;
            bool selection = (mode & TileHighlightMode.Selection) != 0;

            Component component = renderer as Component;
            Transform transform = component.GameObj.Transform;
            Tilemap tilemap = renderer.ActiveTilemap;
            Tileset tileset = tilemap != null ? tilemap.Tileset.Res : null;
            Vector2 tileSize = tileset != null ? tileset.TileSize : Tileset.DefaultTileSize;
            Rect localRect = renderer.LocalTilemapRect;

            // Determine the object's local coordinate system (rotated, scaled) in world space
            Vector2 worldAxisX = Vector2.UnitX;
            Vector2 worldAxisY = Vector2.UnitY;
            MathF.TransformCoord(ref worldAxisX.X, ref worldAxisX.Y, transform.Angle, transform.Scale);
            MathF.TransformCoord(ref worldAxisY.X, ref worldAxisY.Y, transform.Angle, transform.Scale);

            Vector2 localOriginPos = tileSize * origin;
            Vector2 worldOriginPos = localOriginPos.X * worldAxisX + localOriginPos.Y * worldAxisY;

            canvas.PushState();
            {
                // Configure the canvas so our shapes are properly rotated and scaled
                canvas.State.TransformHandle = -localRect.TopLeft;
                canvas.State.TransformAngle = transform.Angle;
                canvas.State.TransformScale = new Vector2(transform.Scale);

                // Fill all highlighted tiles that are currently visible
                {
                    canvas.State.SetMaterial(defaultMaterial);
                    canvas.State.ColorTint = fillTint * ColorRgba.White.WithAlpha(selection ? 0.2f : 0.375f);

                    // Determine tile visibility
                    Vector2 worldTilemapOriginPos = localRect.TopLeft;
                    MathF.TransformCoord(ref worldTilemapOriginPos.X, ref worldTilemapOriginPos.Y, transform.Angle, transform.Scale);
                    TilemapCulling.TileInput cullingIn = new TilemapCulling.TileInput
                    {
                        // Remember: All these transform values are in world space
                        TilemapPos = transform.Pos + new Vector3(worldTilemapOriginPos) + new Vector3(worldOriginPos),
                        TilemapScale = transform.Scale,
                        TilemapAngle = transform.Angle,
                        TileCount = new Point2(highlight.Width, highlight.Height),
                        TileSize = tileSize
                    };
                    TilemapCulling.TileOutput cullingOut = TilemapCulling.GetVisibleTileRect(canvas.DrawDevice, cullingIn);
                    int renderedTileCount = cullingOut.VisibleTileCount.X * cullingOut.VisibleTileCount.Y;

                    // Draw all visible highlighted tiles
                    {
                        Point2 tileGridPos = cullingOut.VisibleTileStart;
                        Vector2 renderStartPos = worldOriginPos + tileGridPos.X * tileSize.X * worldAxisX + tileGridPos.Y * tileSize.Y * worldAxisY;;
                        Vector2 renderPos = renderStartPos;
                        Vector2 tileXStep = worldAxisX * tileSize.X;
                        Vector2 tileYStep = worldAxisY * tileSize.Y;
                        int lineMergeCount = 0;
                        int totalRects = 0;
                        for (int tileIndex = 0; tileIndex < renderedTileCount; tileIndex++)
                        {
                            bool current = highlight[tileGridPos.X, tileGridPos.Y];
                            if (current)
                            {
                                // Try to merge consecutive rects in the same line to reduce drawcalls / CPU load
                                bool hasNext = (tileGridPos.X + 1 < highlight.Width) && ((tileGridPos.X + 1 - cullingOut.VisibleTileStart.X) < cullingOut.VisibleTileCount.X);
                                bool next = hasNext ? highlight[tileGridPos.X + 1, tileGridPos.Y] : false;
                                if (next)
                                {
                                    lineMergeCount++;
                                }
                                else
                                {
                                    totalRects++;
                                    canvas.FillRect(
                                        transform.Pos.X + renderPos.X - lineMergeCount * tileXStep.X,
                                        transform.Pos.Y + renderPos.Y - lineMergeCount * tileXStep.Y,
                                        transform.Pos.Z,
                                        tileSize.X * (1 + lineMergeCount),
                                        tileSize.Y);
                                    lineMergeCount = 0;
                                }
                            }

                            tileGridPos.X++;
                            renderPos += tileXStep;
                            if ((tileGridPos.X - cullingOut.VisibleTileStart.X) >= cullingOut.VisibleTileCount.X)
                            {
                                tileGridPos.X = cullingOut.VisibleTileStart.X;
                                tileGridPos.Y++;
                                renderPos = renderStartPos;
                                renderPos += tileYStep * (tileGridPos.Y - cullingOut.VisibleTileStart.Y);
                            }
                        }
                    }
                }

                // Draw highlight area outlines, unless flagged as uncertain
                if (!uncertain)
                {
                    // Determine the outlines of individual highlighted tile patches
                    if (outlineCache == null) outlineCache = new List<Vector2[]>();
                    if (outlineCache.Count == 0)
                    {
                        GetTileAreaOutlines(highlight, tileSize, ref outlineCache);
                    }

                    // Draw outlines around all highlighted tile patches
                    canvas.State.SetMaterial(selection ? strippleMaterial : defaultMaterial);
                    canvas.State.ColorTint = outlineTint;
                    foreach (Vector2[] outline in outlineCache)
                    {
                        // For strippled-line display, determine total length of outline
                        if (selection)
                        {
                            float totalLength = 0.0f;
                            for (int i = 1; i < outline.Length; i++)
                            {
                                totalLength += (outline[i - 1] - outline[i]).Length;
                            }
                            canvas.State.TextureCoordinateRect = new Rect(totalLength / strippledLineTex.PixelWidth, 1.0f);
                        }

                        // Draw the outline
                        canvas.DrawPolygon(
                            outline,
                            transform.Pos.X + worldOriginPos.X,
                            transform.Pos.Y + worldOriginPos.Y,
                            transform.Pos.Z);
                    }
                }

                // If this is an uncertain highlight, i.e. not actually reflecting the represented action,
                // draw a gizmo to indicate this for the user.
                if (uncertain)
                {
                    Vector2 highlightSize = new Vector2(highlight.Width * tileSize.X, highlight.Height * tileSize.Y);
                    Vector2 highlightCenter = highlightSize * 0.5f;

                    Vector3 circlePos = transform.Pos + new Vector3(worldOriginPos + worldAxisX * highlightCenter + worldAxisY * highlightCenter);
                    float circleRadius = MathF.Min(tileSize.X, tileSize.Y) * 0.2f;

                    canvas.State.SetMaterial(defaultMaterial);
                    canvas.State.ColorTint = outlineTint;
                    canvas.FillCircle(
                        circlePos.X,
                        circlePos.Y,
                        circlePos.Z,
                        circleRadius);
                }
            }
            canvas.PopState();
        }
Ejemplo n.º 37
0
        private static void GetTileAreaOutlines(IReadOnlyGrid<bool> tileArea, Vector2 tileSize, ref List<Vector2[]> outlines)
        {
            // Initialize the container we'll put our outlines into
            if (outlines == null)
                outlines = new List<Vector2[]>();
            else
                outlines.Clear();

            // Generate a data structure containing all visible edges
            TileEdgeMap edgeMap = new TileEdgeMap(tileArea.Width + 1, tileArea.Height + 1);
            for (int y = 0; y < edgeMap.Height; y++)
            {
                for (int x = 0; x < edgeMap.Width; x++)
                {
                    // Determine highlight state of the four tiles around this node
                    bool topLeft     = x > 0              && y > 0               && tileArea[x - 1, y - 1];
                    bool topRight    = x < tileArea.Width && y > 0               && tileArea[x    , y - 1];
                    bool bottomLeft  = x > 0              && y < tileArea.Height && tileArea[x - 1, y    ];
                    bool bottomRight = x < tileArea.Width && y < tileArea.Height && tileArea[x    , y    ];

                    // Determine which edges are visible
                    if (topLeft     != topRight   ) edgeMap.AddEdge(new Point2(x, y), new Point2(x    , y - 1));
                    if (topRight    != bottomRight) edgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y    ));
                    if (bottomRight != bottomLeft ) edgeMap.AddEdge(new Point2(x, y), new Point2(x    , y + 1));
                    if (bottomLeft  != topLeft    ) edgeMap.AddEdge(new Point2(x, y), new Point2(x - 1, y    ));
                }
            }

            // Traverse edges to form outlines until no more edges are left
            RawList<Vector2> outlineBuilder = new RawList<Vector2>();
            while (true)
            {
                // Find the beginning of an outline
                Point2 current = edgeMap.FindNonEmpty();
                if (current.X == -1 || current.Y == -1) break;

                // Traverse it until no more edges are left
                while (true)
                {
                    Point2 next = edgeMap.GetClockwiseNextFrom(current);
                    if (next.X == -1 || next.Y == -1) break;

                    outlineBuilder.Add(next * tileSize);
                    edgeMap.RemoveEdge(current, next);
                    current = next;
                }

                // Close the loop by adding the first element again
                if (outlineBuilder.Count > 0)
                    outlineBuilder.Add(outlineBuilder[0]);

                // If we have enough vertices, keep the outline for drawing
                Vector2[] outline = new Vector2[outlineBuilder.Count];
                outlineBuilder.CopyTo(outline, 0);
                outlines.Add(outline);

                // Reset the outline builder to an empty state
                outlineBuilder.Clear();
            }
        }