Exemplo n.º 1
0
 /// <summary>
 /// Generates the output of change due or various errors
 /// If no violations have been tripped - figure out currency denominations for return
 /// If change due is divisible by 3 Mod3ChangeGeneration will be called.
 /// Otherwise change is given as optimally as possible.
 /// </summary>
 /// <param name="regionCurrency">The region currency.</param>
 /// <param name="r">random seed</param>
 /// <param name="randomizeAllChange">if set to <c>true</c> [randomize all change]. otherwise randomizes decimal value only</param>
 internal void GenerateChange(IRegionCurrency regionCurrency, Random r, bool randomizeAllChange)
 {
     if (violation == null)
     {
         Change.Clear();
         decimal  changeValue = Math.Round(tendered - cost, 2, MidpointRounding.AwayFromZero);
         string[] stringSplit = changeValue.ToString().Split('.');
         int      x           = stringSplit.Length > 1 ? int.Parse(stringSplit[1]) : 0;
         if (x % 3 == 0)
         {
             //wasn't sure if all money due back should be subject to random behavior
             //or just the decimal value - I implemented both;
             if (randomizeAllChange)
             {
                 Change = Mod3ChangeGeneration(changeValue, regionCurrency, r);
             }
             else                    //randomizes decimal value only.
             {
                 Change = OptimizedChangeReturned(decimal.Parse(stringSplit[0]), regionCurrency);
                 Change.AddRange(Mod3ChangeGeneration(decimal.Parse(string.Format("0.{0}", x)), regionCurrency, r));
             }
         }
         else
         {
             Change = OptimizedChangeReturned(changeValue, regionCurrency);
         }
     }
     else
     {
         Change.Add(string.Format("Error with input ({0}):", RawInput));
         Change.Add(violation.Value);
     }
 }
Exemplo n.º 2
0
        /// <summary>
        /// Optimizes the change returned.
        /// Gives the most efficient change back possible.
        /// </summary>
        /// <param name="changeValue">The change value.</param>
        /// <param name="regionCurrency">The region currency.</param>
        /// <returns></returns>
        private List <string> OptimizedChangeReturned(decimal changeValue, IRegionCurrency regionCurrency)
        {
            List <string> toReturn = new List <string>();

            foreach (var c in regionCurrency.GetDescendingOrderedCurrencies())
            {
                if (c.Value <= changeValue)
                {
                    int times = (int)(changeValue / c.Value);
                    toReturn.Add(string.Format("{0} {1}", times, times > 1 ? c.PluralName : c.Name));
                    changeValue -= (times * c.Value);
                }
            }
            return(toReturn);
        }
Exemplo n.º 3
0
        /// <summary>
        /// If the change due is divisible by 3, give random denominations
        /// these random denominations must equal the appropriate total amount
        /// of change due
        /// </summary>
        /// <param name="changeValue">The change value.</param>
        /// <param name="regionCurrency">The region currency.</param>
        /// <param name="r">The random seed</param>
        /// <returns></returns>
        private List <string> Mod3ChangeGeneration(decimal changeValue, IRegionCurrency regionCurrency, Random r)
        {
            Dictionary <Currency, int> changeDue = new Dictionary <Currency, int>();
            List <string> toReturn = new List <string>();

            foreach (Currency c in regionCurrency.Denominations)
            {
                changeDue.Add(c, 0);
            }
            while (changeValue > 0)
            {
                Currency tmp = regionCurrency.Denominations[r.Next(regionCurrency.Denominations.Count)];

                if (changeValue >= tmp.Value)
                {
                    try
                    {
                        int maxNumberOfTimes = (int)(changeValue / tmp.Value) + 1;                         //adding 1 because random max is exclusive
                        int actualTimes      = r.Next(maxNumberOfTimes);
                        changeDue[tmp] += actualTimes;
                        changeValue    -= (actualTimes * tmp.Value);
                    }
                    catch (OverflowException)
                    {
                        //eat the overflow exception and try again
                        //this happens when the initial change amount due is at or near the limit for Int32
                        //and we try to generate change using something less than 1 ex: a nickel.
                        //allow the system to try larger denominations to reduce the total change due being tracked
                    }
                }
            }
            //populate the change denominations to return
            foreach (Currency c in regionCurrency.GetDescendingOrderedCurrencies())
            {
                if (changeDue[c] > 0)
                {
                    toReturn.Add(string.Format("{0} {1}", changeDue[c], changeDue[c] > 1 ? c.PluralName : c.Name));
                }
            }
            return(toReturn);
        }
        /// <summary>
        /// Processes the transactions.
        /// </summary>
        /// <param name="inputFile">The input file.</param>
        /// <param name="outputFile">The output file.</param>
        /// <param name="dataDumpThreshold">The data dump threshold.</param>
        /// <param name="randomizeAllChange">if set to <c>true</c> [randomize all change].</param>
        /// <param name="regionCurrency">The region currency.</param>
        /// <returns></returns>
        public static bool ProcessTransactions(string inputFile, string outputFile, int dataDumpThreshold, bool randomizeAllChange, IRegionCurrency regionCurrency)
        {
            if (regionCurrency == null)
            {
                return(false);
            }
            //book-keeping
            int start          = 0;
            int dataDumpOffset = 0;
            //number of lines to read at once
            int   take = 50000;
            Mutex _m   = new Mutex();
            Dictionary <int, Transaction> transactions = new Dictionary <int, Transaction>();

            while (true)
            {
                string[] v = null;
                try
                {
                    v = File.ReadLines(inputFile).Skip(start).Take(take).ToArray();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    return(false);
                }
                //using Parallel.ForEach for increased performance when calculating change
                Parallel.ForEach(v, (s, x, i) =>
                {
                    Transaction tmp = new Transaction(s);
                    tmp.GenerateChange(regionCurrency, new Random(Guid.NewGuid().GetHashCode()), randomizeAllChange);
                    int index = (int)i + start;
                    _m.WaitOne();
                    transactions.Add(index, tmp);
                    _m.ReleaseMutex();
                });
                //section to write transaction data to disk - preventing out of memory issues
                if (transactions.Count % dataDumpThreshold == 0)
                {
                    try
                    {
                        using (StreamWriter writer = new StreamWriter(outputFile, append: true))
                        {
                            int offset = dataDumpThreshold * dataDumpOffset;
                            for (int i = 0; i < transactions.Count; i++)
                            {
                                writer.WriteLine(transactions[i + offset].ToString());
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                        return(false);
                    }
                    transactions.Clear();
                    dataDumpOffset++;
                }
                start += take;
                if (v.Length < take)
                {
                    break;
                }
            }
            if (transactions.Count > 0)            //write the remaining transactions
            {
                try
                {
                    using (StreamWriter writer = new StreamWriter(outputFile, append: true))
                    {
                        int offset = dataDumpThreshold * dataDumpOffset;
                        for (int i = 0; i < transactions.Count; i++)
                        {
                            writer.WriteLine(transactions[i + offset].ToString());
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    return(false);
                }
            }
            return(true);
        }