Exemple #1
0
        public async Task <AuctionBid> AddOrUpdateBid(string item, string character, string rank, int bid, IMessage message)
        {
            // First make sure we can make a valid bid out of it.
            if (!ranks.TryGetValue(rank, out RankConfiguration rankConfig))
            {
                throw new ArgumentException($"Rank {rank} does not exist.");
            }

            if (!state.Auctions.TryGetValue(item, out Auction auction))
            {
                throw new AuctionNotFoundException(item);
            }

            int characterId = await dkpProcessor.GetCharacterId(character);

            PlayerPoints points = await dkpProcessor.GetDkp(characterId);

            int pointsAlreadyBid = state.Auctions.Values.SelectMany(x => x.Bids)
                                   .Where(b => b.CharacterId == characterId && // From This character
                                          b.Auction != auction)                  // Don't count this current auction, because we're replacing it.
                                   .Sum(x => x.BidAmount) * rankConfig.PriceMultiplier;
            decimal availableDkp = (points.PointsCurrentWithTwink - pointsAlreadyBid) / rankConfig.PriceMultiplier;

            if (availableDkp < bid)
            {
                throw new InsufficientDkpException($"{character} only has {availableDkp} left to bid with. Cancel some bids, or bid less!");
            }

            AuctionBid newBid = auction.Bids.AddOrUpdate(new AuctionBid(auction, character, characterId, bid, rankConfig, message.Author));

            log.LogInformation($"Created bid: {newBid}");

            await message.Channel.SendMessageAsync($"Bid accepted for **{newBid.Auction}**\n"
                                                   + $"```\"{auction.Name}\" {newBid}```"
                                                   + $"If you win, you could pay up to **{newBid.BidAmount * newBid.Rank.PriceMultiplier}**.\n"
                                                   + $"If you wish to modify your bid before the auction completes, simply enter a new bid in the next **{auction.MinutesRemaining:##.#}** minutes.\n"
                                                   + "If you wish to cancel your bid use the following syntax:\n"
                                                   + $"```\"{newBid.Auction.Name}\" cancel```");

            return(newBid);
        }
Exemple #2
0
        private AuctionBid RemoveWinner(List <AuctionBid> bids)
        {
            bids.Sort();
            log.LogTrace("Finding best winner from: ({0})", string.Join(", ", bids));
            List <int> winningIndexes = new List <int>();

            for (int i = 0; i < bids.Count; i++)
            {
                AuctionBid bid = bids[i];

                if (winningIndexes.None())
                {
                    // First winner
                    winningIndexes.Add(i);
                }
                else if (bids[winningIndexes.Last()].CompareTo(bid) == 0)
                {
                    // Tied for first winner.
                    winningIndexes.Add(i);
                }
                else
                {
                    // Done
                    break;
                }
            }

            log.LogTrace("Found {0} winners.", winningIndexes.Count);

            if (winningIndexes.None())
            {
                return(null);
            }

            int        winningIndex = winningIndexes.OrderBy(x => random.Next()).First();
            AuctionBid winner       = bids[winningIndex];

            bids.RemoveAt(winningIndex);

            return(winner);
        }
Exemple #3
0
        public CompletedAuction CalculateWinners(Auction auction)
        {
            List <AuctionBid> bids = auction.Bids.ToList();

            log.LogTrace("Finding winners for {0} from bids submitted: ({1})", auction.DetailDescription, string.Join("', ", auction.Bids));
            List <AuctionBid> winners = new List <AuctionBid>();

            for (int i = 0; i < auction.Quantity; i++)
            {
                if (bids.Any())
                {
                    // Grab the first winner.
                    AuctionBid winner = RemoveWinner(bids);
                    winners.Add(winner);
                }
            }

            List <WinningBid> winningBids = CalculatePrices(winners, bids);

            log.LogInformation("{0} found {1} winners: {2}", auction.DetailDescription, winners.Count, string.Join(", ", winners));

            return(new CompletedAuction(auction, winningBids));
        }
Exemple #4
0
        private List <WinningBid> CalculatePrices(ICollection <AuctionBid> winners, ICollection <AuctionBid> losers)
        {
            List <WinningBid> winningBids = new List <WinningBid>(winners.Count);

            int winnerNumber = 1;

            foreach (AuctionBid winner in winners.OrderBy(x => x))
            {
                int  applicableLooserBid = 0;
                bool loserTied           = false;
                if (losers.Any())
                {
                    AuctionBid loser = null;

                    // check and see if we won because we out-bid somebody's cap.
                    AuctionBid outbidWinner = winners.OrderBy(x => x).Skip(winners.Count).FirstOrDefault();

                    if (outbidWinner != null && outbidWinner.MaxBid < winner.BidAmount)
                    {
                        // If we outbid their cap, we'll use them to calculate our price instead of the first unsuccessful bid.
                        loser = outbidWinner;
                    }

                    if (loser == null)
                    {
                        // You lose! Good DAY sir!
                        loser = losers.OrderBy(x => x).FirstOrDefault();

                        //If the loser tied a winner, that adjusts the final price.
                        //But only if they didn't outbid their cap'
                        if (loser?.BidAmount == winners.LastOrDefault()?.BidAmount &&
                            loser.BidAmount <= loser.MaxBid)
                        {
                            loserTied = true;
                        }
                    }

                    if (loser != null)
                    {
                        if (winner.Rank.MaxBid > loser.Rank.MaxBid && winner.BidAmount > loser.Rank.MaxBid)
                        {
                            // If our bid cap and is higher than their bid cap, and we bid over their cap. reduce their bid.
                            applicableLooserBid = Math.Min(loser.BidAmount, loser.Rank.MaxBid);
                        }
                        else
                        {
                            // Otherwise
                            applicableLooserBid = loser.BidAmount;
                        }
                    }
                }

                int price;
                if (loserTied)
                {
                    // If the first loser was a tie, everybody pays the tie price.
                    price = applicableLooserBid;
                }
                else
                {
                    // They pay loser+1, but not more than their bid. Aka full price if a tie.
                    price = applicableLooserBid + 1;
                }

                // Never go over their bid amount.
                price = Math.Min(price, winner.BidAmount);
                int finalPrice = price * winner.Rank.PriceMultiplier;

                winningBids.Add(new WinningBid(winner, finalPrice));
                winnerNumber++;
            }
            return
                (winningBids);
        }
 public WinningBid(AuctionBid bid, int price)
 {
     Bid   = bid;
     Price = price;
 }