public static (int, List <int[, ]>) Solve(List <PieceQuantity> pieceQuantities)
        {
            var rectangle    = SolvingHelper.GenerateRectangle(pieceQuantities);
            var results      = new List <int[, ]>();
            int cutLength    = 0;
            int resultsCount = 0;

            while (true)
            {
                var currentPiecesCombinations = GeneratePiecesWithCuts(pieceQuantities, cutLength);

                foreach (var currentPieces in currentPiecesCombinations)
                {
                    var currentPiecesCount = currentPieces.Sum(x => x.Quantity);
                    var tempMatrix = new List <int[]>();
                    var repeatedRowsDictionary = new Dictionary <int, int>();
                    int pieceIndex = 0, repeatedRowIndex = 0, disctinctRowIndex = 0;
                    foreach (var pieceQuantity in currentPieces)
                    {
                        int rowsCount = 0;
                        for (int i = 0; i < pieceQuantity.Quantity; i++)
                        {
                            var rows = SolvingHelper.CreateRows(pieceQuantity.Piece, rectangle, currentPiecesCount, pieceIndex++);
                            rowsCount = rows.Count;
                            foreach (var row in rows)
                            {
                                repeatedRowsDictionary[repeatedRowIndex++] = disctinctRowIndex++;
                                tempMatrix.Add(row);
                            }
                            disctinctRowIndex -= rowsCount;
                        }
                        disctinctRowIndex += rowsCount;
                    }

                    var matrix    = SolvingHelper.ConvertToArray(tempMatrix);
                    if (matrix == null)
                    {
                        continue;
                    }

                    var dlx       = new Dlx();
                    var solutions = dlx.Solve(matrix).ToList();
                    var distinctSolutionsHashSet = new HashSet <IEnumerable <int> >(new SequenceComparer <int>());
                    foreach (var solution in solutions)
                    {
                        if (!distinctSolutionsHashSet.Add(solution.RowIndexes.Select(x => repeatedRowsDictionary[x]).OrderBy(x => x)))
                        {
                            continue;
                        }

                        var pieceNumber = 1;
                        foreach (var rowIndex in solution.RowIndexes)
                        {
                            for (int i = currentPiecesCount; i < matrix.GetLength(1); i++)
                            {
                                if (matrix[rowIndex, i] == 1)
                                {
                                    rectangle[(i - currentPiecesCount) / rectangle.GetLength(1), (i - currentPiecesCount) % rectangle.GetLength(1)] = pieceNumber;
                                }
                            }
                            pieceNumber++;
                        }

                        results.Add((int[, ])rectangle.Clone());
                    }

                    var solutionRepetitions = currentPieces
                                              .Select(x => Factorial(x.Quantity))
                                              .Aggregate((x, y) => x * y);

                    if (distinctSolutionsHashSet.Count != solutions.Count / solutionRepetitions)
                    {
                        throw new InvalidOperationException("Internal error. Number of distinct solutions is not proper.");
                    }

                    resultsCount += solutions.Count / solutionRepetitions;
                }

                if (resultsCount > 0)
                {
                    return(cutLength, results);
                }

                cutLength++;
            }
        }
Esempio n. 2
0
        public static (int, int[, ]) Solve(List <PieceQuantity> pieceQuantities)
        {
            cancellationTokenSource = new CancellationTokenSource();
            bestSolutionIndexes     = new List <int>();
            currentIteration        = 0;
            maxIteration            = 0;

            var piecesCount = pieceQuantities.Sum(x => x.Quantity);
            var rectangle   = SolvingHelper.GenerateRectangle(pieceQuantities);

            maxIteration = (ulong)Math.Round(Math.Pow(pieceQuantities.Sum(x => x.Piece.Orientations.Length * x.Quantity), 3));

            var tempMatrix = new List <int[]>();

            for (int i = 0, j = 0; i < pieceQuantities.Count; i++)
            {
                for (int k = 0; k < pieceQuantities[i].Quantity; j++, k++)
                {
                    tempMatrix.AddRange(SolvingHelper.CreateRows(pieceQuantities[i].Piece, rectangle, piecesCount, j));
                }
            }

            var matrix = SolvingHelper.ConvertToArray(tempMatrix);

            if (matrix == null)
            {
                return(0, null);
            }

            var dlx = new Dlx(cancellationTokenSource.Token);

            dlx.SolutionFound += DlxSolutionFound;
            dlx.SearchStep    += DlxSearchStep;
            dlx.Solve(matrix).ToList();

            List <IPiece> pieces = pieceQuantities
                                   .SelectMany(x =>
            {
                var list = new List <IPiece>();
                for (int i = 0; i < x.Quantity; i++)
                {
                    list.Add(x.Piece);
                }
                return(list);
            })
                                   .Cast <IPiece>()
                                   .ToList();
            var pieceNumber = 1;

            foreach (var index in bestSolutionIndexes)
            {
                for (int i = 0; i < piecesCount; i++)
                {
                    if (matrix[index, i] == 1)
                    {
                        if (!pieces.Remove(GetPiece(pieceQuantities, i)))
                        {
                            throw new InvalidOperationException("Internal error. Could not find piece to remove.");
                        }
                        break;
                    }
                }
                for (int i = piecesCount; i < matrix.GetLength(1); i++)
                {
                    if (matrix[index, i] == 1)
                    {
                        rectangle[(i - piecesCount) / rectangle.GetLength(1), (i - piecesCount) % rectangle.GetLength(1)] = pieceNumber;
                    }
                }
                pieceNumber++;
            }

            var cutLength = 0;

            for (int row = 0; row < rectangle.GetLength(0); row++)
            {
                for (int column = 0; column < rectangle.GetLength(1); column++)
                {
                    if (rectangle[row, column] == 0)
                    {
                        cutLength += PutBestPiece(pieces, rectangle, row, column, pieceNumber);
                        pieceNumber++;
                    }
                }
            }

            return(cutLength, rectangle);
        }