Exemplo n.º 1
0
        public void SellPhase()
        {
            // Get all goods up for sale.
            _productSupply = Populous.SellPhase();

            // Reset Shortfall to zero.
            Shortfall = new ProductAmountCollection();

            // Fill Surplus preemtively, we'll remove bought products later.
            _surplus = ProductSupply.Copy();

            // While we're at it, also get total demand of all products
            _productDemand = Populous.TotalDemand();

            // And the hypothetical total production available.
            _productionCapacity = Populous.TotalProduction();
        }
Exemplo n.º 2
0
        public void ReturnNecissaryMaintenanceCostsAndMaintenanceMetFromRunMaintenanceWhenStorageIsEmpty()
        {
            // Setup storage
            MaintStorage = new ProductAmountCollection();

            // satisfaction Satisfaction
            var sat = 0.0;

            // Get Result
            var result = sut.RunMaintenance(1, MaintStorage, out sat);

            // Assert Satisfaction is correct.
            Assert.That(sat, Is.EqualTo(0));

            // Assert that Result is correct.
            AssertCollectionContains(result, MaintenaceProductMock1, 0);
            AssertCollectionContains(result, MaintenaceProductMock2, 0);
        }
Exemplo n.º 3
0
        public void ReturnEmptyCollectionAndFullSatisfactionWhenMaintenanceIsEmpty()
        {
            // Setup storage
            MaintStorage = new ProductAmountCollection();

            // setup maintenance
            sut.Maintenance = new ProductAmountCollection();

            // satisfaction Satisfaction
            var sat = 0.0;

            // Get Result
            var result = sut.RunMaintenance(1, MaintStorage, out sat);

            // Assert Satisfaction is correct.
            Assert.That(sat, Is.EqualTo(1));

            // Assert that Result is correct.
            Assert.That(result.Count(), Is.EqualTo(0));
        }
        /// <summary>
        /// Consumes the given set of goods.
        /// </summary>
        /// <param name="goods">The goods to attempt to consume.</param>
        /// <param name="satisfaction">The satisfaction we'll be filling out as we go.</param>
        /// <returns>The change in products stored.</returns>
        private IProductAmountCollection ConsumeGoods(IProductAmountCollection goods,
                                                      IProductAmountCollection satisfaction)
        {
            var result = new ProductAmountCollection();

            // for each good to consume.
            foreach (var pair in goods)
            {
                // Get the item and amount of the person.
                var product = pair.Item1;
                var amount  = pair.Item2;

                // Assume All items being consumed are in storage already,
                // if they aren't we have a consistency problem.
                // get the satisfaction, capping it at 1.
                var sat = Math.Min(1, Storage.GetProductValue(product) / amount);

                // If satisfaction can't be met, subtract what you can.
                if (sat < 1)
                {
                    result.SubtractProducts(product,
                                            Storage.GetProductValue(product));

                    Storage.SubtractProducts(product,
                                             Storage.GetProductValue(product));
                }
                else // If greater than 1, then substract everything needed.
                {
                    result.SubtractProducts(product, amount);

                    Storage.SubtractProducts(product, amount);
                }

                // Finally, set it's satisfaction.
                satisfaction.SetProductAmount(product, sat);
            }

            // Return change in products stored.
            return(result);
        }
        public void CompleteTransaction(IProductAmountCollection transaction)
        {
            if (transaction is null)
            {
                throw new ArgumentNullException(nameof(transaction));
            }

            // add and remove the trasaction to storage
            Storage.AddProducts(transaction);
            // Add to for sale, rather than recalculating it entirely
            ForSale.AddProducts(transaction);

            // quickly remove any products from for sale that are 0 or less.
            if (ForSale.Any(x => x.Item2 <= 0))
            {
                var gone = ForSale.Where(x => x.Item2 == 0).ToList();
                foreach (var product in gone)
                {
                    ForSale.DeleteProduct(product.Item1);
                }
            }
        }
        public void Setup()
        {
            other = new Process();

            jobMock = new Mock <IJob>();

            jobInputs  = new ProductAmountCollection();
            jobOutputs = new ProductAmountCollection();

            jobMock.Setup(x => x.Inputs)
            .Returns(jobInputs);
            jobMock.Setup(x => x.Outputs)
            .Returns(jobOutputs);

            var id = Guid.NewGuid();

            ProductMock1 = new Mock <IProduct>();
            ProductMock1.Setup(x => x.Id)
            .Returns(id);

            sut = new Process();
        }
Exemplo n.º 7
0
        public void Setup()
        {
            #region Needs

            LifeNeed = new Mock <IProduct>();
            LifeNeed.Setup(x => x.Id).Returns(LifeNeedId);
            LifeNeed.Setup(x => x.Name).Returns("LifeNeed");
            DailyNeed = new Mock <IProduct>();
            DailyNeed.Setup(x => x.Id).Returns(DailyNeedId);
            DailyNeed.Setup(x => x.Name).Returns("DailyNeed");
            LuxNeed = new Mock <IProduct>();
            LuxNeed.Setup(x => x.Id).Returns(LuxNeedId);
            LuxNeed.Setup(x => x.Name).Returns("LuxNeed");

            LifeNeedsMock = new ProductAmountCollection();
            LifeNeedsMock.AddProducts(LifeNeed.Object, 1);
            DailyNeedsMock = new ProductAmountCollection();
            DailyNeedsMock.AddProducts(DailyNeed.Object, 1);
            LuxuryNeedsMock = new ProductAmountCollection();
            LuxuryNeedsMock.AddProducts(LuxNeed.Object, 1);

            #endregion Needs

            #region JobGoods

            JobInput = new Mock <IProduct>();
            JobInput.Setup(x => x.Id).Returns(JobInputId);
            JobInput.Setup(x => x.Name).Returns("JobInput");
            JobOutput = new Mock <IProduct>();
            JobOutput.Setup(x => x.Id).Returns(JobOutputId);
            JobOutput.Setup(x => x.Name).Returns("JobOutput");
            JobCapital = new Mock <IProduct>();
            JobCapital.Setup(x => x.Id).Returns(JobCapitalId);
            JobCapital.Setup(x => x.Name).Returns("JobCapital");
            ProducedGood = new Mock <IProduct>();
            ProducedGood.Setup(x => x.Id).Returns(ProducedGoodId);

            JobInputs = new ProductAmountCollection();
            JobInputs.AddProducts(JobInput.Object, 1);
            JobOutputs = new ProductAmountCollection();
            JobOutputs.AddProducts(JobOutput.Object, 1);
            JobCapitals = new ProductAmountCollection();
            JobCapitals.AddProducts(JobCapital.Object, 1);
            ProducedGoods = new ProductAmountCollection();
            ProducedGoods.AddProducts(ProducedGood.Object, 1);

            #endregion JobGoods

            #region JobSetup
            JobMock = new Mock <IJob>();
            JobMock.Setup(x => x.Inputs)
            .Returns(JobInputs);
            JobMock.Setup(x => x.Outputs)
            .Returns(JobOutputs);
            JobMock.Setup(x => x.Capital)
            .Returns(JobCapitals);
            JobMock.Setup(x => x.LaborRequirements)
            .Returns(1);
            JobMock.Setup(x => x.Inputs)
            .Returns(JobInputs);
            JobMock.Setup(x => x.Capital)
            .Returns(JobCapitals);
            #endregion JobSetup

            LaborMock = new Mock <IProduct>();
            LaborMock.Setup(x => x.Id).Returns(LaborId);

            currencyValues = new ProductAmountCollection();

            CurrencyMock1 = new Mock <IProduct>();
            CurrencyMock1.Setup(x => x.Id).Returns(Currency1Id);
            CurrencyMock1.Setup(x => x.Name).Returns("Currency1");
            CurrencyMock2 = new Mock <IProduct>();
            CurrencyMock2.Setup(x => x.Id).Returns(Currency2Id);
            CurrencyMock2.Setup(x => x.Name).Returns("Currency2");

            MarketMock = new Mock <IMarket>();
            MarketMock.Setup(x => x.GetPrice(LifeNeed.Object))
            .Returns(100);
            MarketMock.Setup(x => x.GetPrice(DailyNeed.Object))
            .Returns(100);
            MarketMock.Setup(x => x.GetPrice(LuxNeed.Object))
            .Returns(100);
            MarketMock.Setup(x => x.GetPrice(JobInput.Object))
            .Returns(100);
            MarketMock.Setup(x => x.GetPrice(JobOutput.Object))
            .Returns(100);
            MarketMock.Setup(x => x.GetPrice(JobCapital.Object))
            .Returns(100);
            MarketMock.Setup(x => x.GetPrice(ProducedGood.Object))
            .Returns(100);
            MarketMock.Setup(x => x.GetPrice(CurrencyMock1.Object))
            .Returns(100);
            MarketMock.Setup(x => x.GetPrice(CurrencyMock2.Object))
            .Returns(100);

            MarketMock.Setup(x => x.AcceptedCurrencies)
            .Returns(new List <IProduct> {
                CurrencyMock1.Object, CurrencyMock2.Object
            });

            sut = new PopulationGroup
            {
                Id            = TestId,
                Name          = TestName,
                Count         = PopCount,
                JobLabor      = LaborMock.Object,
                DailyNeeds    = DailyNeedsMock,
                LifeNeeds     = LifeNeedsMock,
                LuxuryNeeds   = LuxuryNeedsMock,
                PrimaryJob    = JobMock.Object,
                Priority      = Priority1,
                Storage       = new ProductAmountCollection(),
                ForSale       = new ProductAmountCollection(),
                SecondaryJobs = new List <IJob>(),
                SkillLevel    = SkillLevel,
                SkillName     = SkillName,
            };

            sut.InitializeStorage();
        }
Exemplo n.º 8
0
 // A helper function for avsserting products in the collection are correct.
 private void AssertProductAmountIsEqual(IProductAmountCollection collection, Mock <IProduct> product, double value)
 {
     Assert.That(collection.GetProductValue(product.Object), Is.EqualTo(value));
 }
        /// <summary>
        /// Buys good via barter.
        /// </summary>
        /// <param name="buyerStock">The buyer's goods up for trade.</param>
        /// <param name="good">The good being traded for.</param>
        /// <param name="amount">The amount of the good being bought.</param>
        /// <param name="market">The market that the barter is taking place in.</param>
        /// <returns>The resulting change in goods for the buyer.</returns>
        public IProductAmountCollection BarterGood(IProductAmountCollection buyerStock,
                                                   IProduct good, double amount, IMarket market)
        {
            // TODO, update to use the coincidence of wants,
            // it will discourage barter more than anything.
            if (buyerStock == null)
            {
                throw new ArgumentNullException(nameof(buyerStock));
            }
            if (good == null)
            {
                throw new ArgumentNullException(nameof(good));
            }
            if (market == null)
            {
                throw new ArgumentNullException(nameof(market));
            }
            if (amount <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(amount));
            }

            // the return result of the barter
            var result = new ProductAmountCollection();

            // TODO a barter modifier, to discourage or encourage bartering.
            // This should become more flexible later.
            var BarterMod = 1;

            // Get how much we can or want to get
            amount = Math.Min(amount, ForSale.GetProductValue(good));

            // get the price of the good.
            var totalPrice = GetPrice(good, market.GetPrice(good)) * amount * BarterMod;

            // get the total price of what's offered.
            double barterVal = 0;

            foreach (var product in buyerStock)
            {
                barterVal += market.GetPrice(product.Item1) * product.Item2;
            }

            // the barter we're trading for the goods.
            IProductAmountCollection barter;

            // if the available barter is greater than the price, begin bartering
            if (barterVal >= totalPrice)
            {
                // Use get change for the easiest option.
                barter = market.ChangeForPrice(buyerStock, totalPrice);

                // don't go more accurate, barter isn't supposed to be more accurate to coins,
                // no one would accept change in bits of wheat.

                // Add the goods being bought
                result.AddProducts(good, amount);

                // Remove the goods being traded.
                result.AddProducts(barter.Multiply(-1));
            }
            else
            {
                // if it's not enough, throw it all in, and buy what you can.
                double buyableUnits = 0;

                // if the good is fractional
                if (good.Fractional)
                {
                    // just divide
                    buyableUnits = barterVal / (market.GetPrice(good) * BarterMod);
                }
                else
                {
                    // round down
                    buyableUnits = Math.Floor(barterVal / (market.GetPrice(good) * BarterMod));
                }

                // If we can buy anything, do so.
                if (buyableUnits > 0)
                {
                    // add the goods
                    result.AddProducts(good, buyableUnits);
                    // subtract the goods
                    result.AddProducts(buyerStock.Multiply(-1));
                }
            }

            // No change, this is bartering.

            // We've done what we can, move on.
            return(result);
        }
        public IProductAmountCollection BuyGood(IProductAmountCollection cash,
                                                IProduct good, double amount, IMarket market)
        {
            // Sanity check for nulls.
            if (cash is null)
            {
                throw new ArgumentNullException(nameof(cash));
            }
            if (good is null)
            {
                throw new ArgumentNullException(nameof(good));
            }
            if (market is null)
            {
                throw new ArgumentNullException(nameof(market));
            }
            if (amount <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(amount));
            }

            // The collection we're returning.
            var result = new ProductAmountCollection();

            // get how much to buy, what's available, or what's desired.
            var available = Math.Min(amount, ForSale.GetProductValue(good));

            // get the price of that good
            var totalPrice = GetPrice(good, market.GetPrice(good)) * available;

            // get the cash needed for the goods
            var money = market.ChangeForPrice(cash, totalPrice);

            // get our available money total
            var totalMoney = money.Sum(x => market.GetPrice(x.Item1, x.Item2));

            // if the money is enough, just buy outright
            if (totalMoney >= totalPrice)
            {
                // Add what they're buying.
                result.AddProducts(good, available);
                // remove what they spent
                result.AddProducts(money.Multiply(-1));
            }
            else if (!good.Fractional && totalMoney < market.GetPrice(good))
            {// If the total money is not enough for a single unit, and the good can't be divided
                // we can't actually buy anything, so just return an empty transaction
                return(new ProductAmountCollection());
            }
            else // if it's not enough
            {
                // get the buyable units of the good
                double buyableUnits = 0;

                // if we can buy fractionally
                if (good.Fractional)
                {
                    // just do the math straight.
                    buyableUnits = totalMoney / market.GetPrice(good);
                }
                else // if we can't
                {
                    // take what we can and round down, seller should always make more than the buyer here.
                    buyableUnits = Math.Floor(totalMoney / market.GetPrice(good));
                }

                // if we can buy any units
                if (buyableUnits > 0)
                {
                    // buy them add the units to the results
                    result.AddProducts(good, buyableUnits);
                    // subtract the cash.
                    result.AddProducts(money.Multiply(-1));
                }
            }

            // Get change, if any.
            var change = totalMoney - market.GetPrice(good) * result.GetProductValue(good);

            // get the change, if any
            IProductAmountCollection buyersChange = new ProductAmountCollection();

            // if change is greater than 0.
            if (change > 0) // Make said change.
            {
                buyersChange = market.ChangeForPrice(GetCash(market.AcceptedCurrencies), change);
            }

            // add back the buyer's change
            result.AddProducts(buyersChange);

            // TODO, maybe add check to see if the seller shortchanged the buyer.

            // complete the transaction for the seller, and subtract the result.
            CompleteTransaction(result.Multiply(-1));

            // we're done, return the change in the buyer's goods.
            return(result);
        }
Exemplo n.º 11
0
 public Culture()
 {
     Id         = Guid.NewGuid();
     _needs     = new ProductAmountCollection();
     _needTypes = new Dictionary <Guid, NeedType>();
 }
Exemplo n.º 12
0
 /// <summary>
 /// The external option to buy from the market.
 /// </summary>
 /// <param name="product">The product to buy.</param>
 /// <param name="amount">How many units to buy.</param>
 /// <param name="sellable">The available products to trade for the product.</param>
 /// <returns>The change in <paramref name="sellable"/> items, plus the amount of good bought.</returns>
 /// <remarks>Buying goods prioritizes using currency to buy over barter of goods.</remarks>
 public IProductAmountCollection BuyGood(IProduct product, double amount, IProductAmountCollection cash)
 {
     throw new NotImplementedException();
 }
Exemplo n.º 13
0
        /// <summary>
        /// Given a set of cash and a desired price, get the amount of the cash
        /// to meet the price (rounded up for safety)
        /// </summary>
        /// <param name="AvailableCash">The amount of cash avaliable.</param>
        /// <param name="price">The price to meet (roughly)</param>
        /// <returns>The appropriate cash for the price.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="AvailableCash"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="price"/> is less than or equal to 0.</exception>
        public IProductAmountCollection ChangeForPrice(IProductAmountCollection AvailableCash, double price)
        {
            // ensure cash is not null.
            if (AvailableCash is null)
            {
                throw new ArgumentNullException(nameof(AvailableCash));
            }
            // ensure that the price is greater than 0
            if (price <= 0) // TODO, allow this to savely give change for 0. It's not that hard.
            {
                throw new ArgumentOutOfRangeException("Price must be greater than 0.");
            }

            // first, check that all available cash can meet the price.
            var totalCash = AvailableCash.Sum(x => x.Item2 * ProductPrices.GetProductValue(x.Item1));

            // If the total cash available is less than the price sought, return a copy of the available cash.
            if (totalCash < price)
            {
                return(AvailableCash.Copy());
            }

            // since we have more than we need,
            var result = new ProductAmountCollection();

            // start from the best and start making change, highest to lowest value.
            foreach (var coin in AvailableCash.OrderByDescending(x => ProductPrices.GetProductValue(x.Item1)))
            {
                // if none of that coin exist
                if (coin.Item2 == 0)
                {
                    // add it as zero
                    result.AddProducts(coin.Item1, 0);
                    // and skip to the next loop
                    continue;
                }

                // coin type
                var curr = coin.Item1;
                // coin value
                var val = ProductPrices.GetProductValue(curr);
                // if value is higher then remaining price.
                if (val > price)
                {
                    // add it as zero
                    result.AddProducts(curr, 0);
                    // and skip
                    continue;
                }

                // coin amount
                var amt = coin.Item2;

                // how many whole coins can fit into the price.
                var count = Math.Floor(price / val);

                // select cap coins at the available level.
                count = Math.Min(count, amt);

                // add to our change
                result.AddProducts(curr, count);

                // subtract the value we took out
                price -= val * count;
                // then go to the next coin.
            }

            // if there is a remainder
            if (price > 0)
            {
                // find the smallest coin available
                foreach (var coin in AvailableCash.OrderBy(x => ProductPrices.GetProductValue(x.Item1)))
                {
                    // if we have any available
                    if (result.GetProductValue(coin.Item1) < AvailableCash.GetProductValue(coin.Item1))
                    {
                        // add one
                        result.AddProducts(coin.Item1, 1);

                        // and move on.
                        break;

                        // by logic, only one should be needed as we guaranteed have
                        // more value in coins then the requested price and the
                        // remainder should be smaller than the smallest coin.
                    }
                }
            }

            // return the change.
            return(result);
        }