Пример #1
0
        /// <summary>
        /// check if a specific case is ok
        /// </summary>
        /// <param name="x_Data">base element in the tree</param>
        /// <param name="y_Data">height element in the sub tree</param>
        /// <param name="count">quantity</param>
        /// <param name="yTemp">temporary height</param>
        /// <param name="splitsLeft">number of splits that are alowd</param>
        /// <returns>if case succeed</returns>
        private bool CheckCases(X_Data x_Data, Y_Data y_Data, int count, ref double yTemp, ref int splitsLeft)
        {
            if (_configurationParameters.MaxSplits == 0)
            {
                if (y_Data.Quantity >= count)
                {
                    return(true);                           //comrpomise (not exact sizes and no splits)
                }
            }
            else if (splitsLeft >= 0)
            {
                if (_sumOfPotentialQuantities == 0 && y_Data.Quantity >= count)
                {
                    return(true);                                                            //still the first item
                }
                if (_sumOfPotentialQuantities > 0 && _sumOfPotentialQuantities + y_Data.Quantity >= count)
                {
                    return(true);                                                                                       //not the first
                }
                if (_potentialItems.Count < _configurationParameters.MaxSplits)
                {
                    PartialMatch(y_Data, x_Data.Base); //splits are aloud
                    splitsLeft--;                      //lower the splits
                }
            }

            yTemp = y_Data.Height + _configurationParameters.Delta; //keep searching with a bigger height
            return(false);
        }
Пример #2
0
 /// <summary>
 /// tell the user if a specific case is ok
 /// </summary>
 /// <param name="x_Data">base element in the tree</param>
 /// <param name="y_Data">height element in the sub tree</param>
 /// <param name="count">quantity</param>
 /// <param name="yTemp">temporary height</param>
 /// <param name="splitsLeft">number of splits that are alowd</param>
 /// <param name="userAproved">indication if user confirm or not</param>
 /// <returns>if case succeed (and update user choice if he aproves it or not)</returns>
 private bool IsPositive(X_Data x_Data, Y_Data y_Data, int count, ref double yTemp, ref int splitsLeft, ref bool userAproved)
 {
     if (CheckCases(x_Data, y_Data, count, ref yTemp, ref splitsLeft)) //if enter- return true anyway
     {
         if (_configurationParameters.MaxSplits == 0 || splitsLeft == _configurationParameters.MaxSplits)
         {                                   //match with no splits (first item). if user confirm- buy. Else-cancel
             userAproved = UserConfirmation(x_Data.Base, y_Data.Height) ? Succeed(x_Data.Base, y_Data, count) : false;
         }
         else if (_sumOfPotentialQuantities > 0) //splits have been maid
         {
             if (UserConfirmation(_potentialItems, x_Data.Base, y_Data, count))
             {
                 if (!_splitsPreference)
                 {
                     userAproved = Succeed(x_Data.Base, y_Data, count);                     //the user prefered to avoid spilts
                 }
                 //and buy only from one category. found Match without splits (the last item)
                 else //user prefers splits
                 {
                     count -= _sumOfPotentialQuantities;
                     for (int i = 0; i < _potentialItems.Count; i++)
                     {
                         _potentialItems[i].YData.Quantity = 0;
                         SuccessfulReduceOperation(_potentialItems[i]);
                     }
                     userAproved = Succeed(x_Data.Base, y_Data, count); //found Match with splits
                 }
             }
         }
         InitData();
         return(true); // case lead to a match (true is returned regardless the user accept it or not (it will be checked later)
     }
     return(false);    // the case didn't lead to a match- keep searching
 }
Пример #3
0
        /// <summary>
        /// Insert new items or add more if category exist
        /// </summary>
        /// <param name="x">base</param>
        /// <param name="y">height</param>
        /// <param name="count">quantity</param>
        /// <returns>A massage to the user about the order details</returns>
        public string Insert(double x, double y, int count)
        {
            if (count <= 0 || x <= 0 || y <= 0)
            {
                throw new Exception("Action failed!\nQuantity & sizes must be a positive number.\n");
            }
            X_Data xRoot;
            Y_Data yRoot;
            Y_Data yData = new Y_Data(y, count);
            X_Data xData = new X_Data(x, yData);

            string addDetails    = $"boxes have beed added to the category {x} X {y}.\n";                 // add to exist
            string insertDetails = $"items of a new category ({x} X {y}) were inserted to the system.\n"; // insert a new category
            string extraMeassage = "extra boxes have been returned to the factory.\n";                    // insert more than the capacity accepted
            int    extraQuantity;

            if (_baseTree.InsertIfNotFinding(xData, out xRoot))       //xRoot isn't null
            {
                if (xRoot.HTree.InsertIfNotFinding(yData, out yRoot)) // yRoot isn't null- this box is exist. add the count
                {
                    if (yRoot.Quantity == _configurationParameters.MaxQuantity)
                    {
                        return($"\nCategory is full.\n{count} {extraMeassage}");
                    }

                    else if (yRoot.Quantity + count > _configurationParameters.MaxQuantity)
                    {
                        int leftToMax = _configurationParameters.MaxQuantity - yRoot.Quantity;
                        extraQuantity  = count - leftToMax;
                        yRoot.Quantity = _configurationParameters.MaxQuantity;
                        return($"\n{leftToMax} {addDetails}{extraQuantity} {extraMeassage}");
                    }

                    yRoot.Quantity += count;
                    return($"\n{count} {addDetails}");
                }
            }

            _listByTime.AddLast(new TimeData(x, y));
            yData.timeRef = _listByTime.End;
            if (count > _configurationParameters.MaxQuantity)
            {
                extraQuantity  = count - _configurationParameters.MaxQuantity;
                yData.Quantity = _configurationParameters.MaxQuantity;
                return($"\n{_configurationParameters.MaxQuantity} {insertDetails}{extraQuantity} {extraMeassage}");
            }
            return($"\n{yData.Quantity} {insertDetails}");
        }
Пример #4
0
        /// <summary>
        /// get details of a given category (if it's in the system)
        /// </summary>
        /// <param name="x">base</param>
        /// <param name="y">height</param>
        /// <returns>data of a category if found</returns>
        public string GetData(double x, double y)
        {
            if (x <= 0 || y <= 0)
            {
                throw new Exception("Action failed!\nSizes must be a positive number.\n");
            }

            X_Data xRoot;
            X_Data xData = new X_Data(x);

            if (_baseTree.Search(xData, out xRoot))
            {
                Y_Data yData = new Y_Data(y);
                Y_Data yRoot;
                if (xRoot.HTree.Search(yData, out yRoot))
                {
                    return($"\nBox Details:\n\nBase area: {x} m^2\nHeight: {y} m\nVolume: {x * y} m^3\n" +
                           $"Quantity in stock: {yRoot.Quantity} items\nLast date purchase: {yRoot.timeRef._data._lastPurchaseDate}\n");
                }
            }
            return("\nThe current box wasn't found\n");
        }
Пример #5
0
 /// <summary>
 /// when there are splits, save the previous data of an element
 /// </summary>
 /// <param name="y_Data"></param>
 /// <param name="x"></param>
 private void PartialMatch(Y_Data y_Data, double x)
 {
     _sumOfPotentialQuantities += y_Data.Quantity;
     _potentialItems.Add(new BoxCategory(y_Data, x));
 }
Пример #6
0
 /// <summary>
 /// update dates of boxes that were purchased
 /// </summary>
 /// <param name="y_Data">height element on the sub tree</param>
 private void UpdateDate(Y_Data y_Data)
 {
     y_Data.timeRef._data._lastPurchaseDate = DateTime.Now;
     _listByTime.ReplaceByNode(y_Data.timeRef);
 }
Пример #7
0
 /// <summary>
 /// update data when match is conmfirmed
 /// </summary>
 /// <param name="closestBiggerBase">current base</param>
 /// <param name="closestBiggerHeight">current height</param>
 /// <param name="count">quantity</param>
 /// <returns>always true. match was already aproved</returns>
 private bool Succeed(double Base, Y_Data closestBiggerHeight, int count)
 {
     closestBiggerHeight.Quantity -= count;
     SuccessfulReduceOperation(new BoxCategory(closestBiggerHeight, Base));
     return(true);
 }
Пример #8
0
        /// <summary>
        /// ask the user if he is intrested with the match (with splits)
        /// </summary>
        /// <param name="potentialItems">sum of all items before</param>
        /// <param name="bases">list of previous bases</param>
        /// <param name="currentBase">list of previous yData</param>
        /// <param name="currentYData">the cureent element</param>
        /// <param name="count">quantity</param>
        /// <returns>user answer</returns>
        private bool UserConfirmation(List <BoxCategory> potentialItems, double currentBase, Y_Data currentYData, int count)
        {
            int           categories = potentialItems.Count;
            StringBuilder sb         = new StringBuilder($"\nThe system has found a match but not in the exact sizes.\nThe match has" +
                                                         $" {categories} splits ({categories + 1} categories):\n\n");

            int originCount = count;

            for (int i = 0; i < categories; i++)
            {
                sb.AppendLine($"{i + 1}) category {potentialItems[i].Base} X {potentialItems[i].YData.Height}:   " +
                              $"{potentialItems[i].YData.Quantity} items");

                count -= potentialItems[i].YData.Quantity;
            }
            sb.AppendLine($"{categories + 1}) category {currentBase} X {currentYData.Height}:   {count} items");

            if (currentYData.Quantity >= originCount)
            {
                sb.Append($"\nThe system suggest another option (without splits):\nBase area {currentBase} m^2\nHeiht: " +
                          $"{currentYData.Height} m\n\nChoose your option:\n\nPress 1 to cancel.\nPress 2 for the first option" +
                          $" (with splits).\nPress 3 for the second option.\n\nUser choice: ");

                Results userAnswer = (Results)_comunicate.MultiChoiceRespond(out Results multyChoiceAnswer, sb.ToString());
                if (userAnswer == Results.cancel)
                {
                    return(false);
                }
                else if (userAnswer == Results.noSplits)
                {
                    _splitsPreference = false;
                }
                return(true);
            }
            return(_comunicate.GetRespondWithSplits(out string answer, sb.ToString()));
        }
Пример #9
0
        /// <summary>
        /// find the best category (or combination of categories) for the purchase
        /// </summary>
        /// <param name="x">base</param>
        /// <param name="y">height</param>
        /// <param name="count">quantity</param>
        /// <returns>answer to the user if found or not</returns>
        public bool FindBestMatch(double x, double y, int count)   //still in progres
        {
            if (count <= 0 || x <= 0 || y <= 0)
            {
                throw new Exception("Action failed!\nQuantity & sizes must be a positive number\n");
            }
            double xTemp = x, yTemp = y;
            X_Data requestedBase = new X_Data(xTemp); //criterion for searching a base
            X_Data closestBiggerBase;
            Y_Data requestedHeight;                   //criterion for searching an height
            Y_Data closestBiggerHeight;
            double upperBoundX = x * _configurationParameters.AcceptableExceeding;
            double upperBoundY = y * _configurationParameters.AcceptableExceeding;
            int    splitsLeft  = _configurationParameters.MaxSplits; //indicate how many splits were left
            bool   userAproved = false;

            while (xTemp <= upperBoundX)                                          //must be <= in oreder to enter. assume the case that AcceptableExceeding=1
            {
                _baseTree.FindClosestUpper(requestedBase, out closestBiggerBase); //closestBiggerBase is always >= requestedBase
                if (closestBiggerBase == null || closestBiggerBase.Base > upperBoundX)
                {
                    break;
                }

                requestedHeight = new Y_Data(yTemp);

                while (yTemp <= upperBoundY) //yTemp can exceeds its bounderies in a specific x but maybe in other x not
                {
                    closestBiggerBase.HTree.FindClosestUpper(requestedHeight, out closestBiggerHeight);
                    if (closestBiggerHeight == null || closestBiggerHeight.Height > upperBoundY) // find a bigger base
                    {
                        if (_exactMatchSizes)
                        {
                            NegateExactMatch();
                        }
                        break;
                    }
                    if (_exactMatchSizes && closestBiggerBase.Base == x && closestBiggerHeight.Height == y) //best case: don't ask
                    {                                                                                       // the user (it's what he wants)
                        if (closestBiggerHeight.Quantity >= count)
                        {
                            return(Succeed(closestBiggerBase.Base, closestBiggerHeight, count));
                        }
                    }
                    if (_exactMatchSizes)
                    {
                        NegateExactMatch();
                    }

                    if (IsPositive(closestBiggerBase, closestBiggerHeight, count, ref yTemp, ref splitsLeft, ref userAproved))
                    {
                        return(userAproved); // return the user answer
                    }
                    if (splitsLeft < 0)      //no splits- don't continue the searching
                    {
                        InitData();
                        return(false);
                    }
                    requestedHeight = new Y_Data(yTemp); //the request must be changed according to height (yTemp was updated)
                                                         //continue with the bigger height (new yTemp is old yTemp+delta)
                }
                NewBaseInit(closestBiggerBase.Base, ref requestedBase, ref xTemp, ref yTemp, y);
            } //all the heights were over in the current base. Base must been changed
            InitData();
            return(false); //x wasn't found
        }