auctionsim/auctionsim/auction.go

71 lines
2.1 KiB
Go

package auctionsim
import (
"math"
"slices"
)
/**
* RunAuction simulates a single-bid second-price auction with no reserve price
* between all bidders emitted by the provided generator, returning the winning
* bidder and how much they paid (the maximum bid of the second-highest bidder).
*
* To simulate an auction between the first several bidders emitted by some
* generator, use CappedBidderGenerator (in generators.go).
*/
func RunAuction(g BidderGenerator) (float64, Bidder) {
highBidder := Bidder{}
maxBid := math.Inf(-1)
prevBid := math.Inf(-1)
for b, ok := g.Generate(); ok; b, ok = g.Generate() {
if c := b.BidCeiling(); c > maxBid {
prevBid = maxBid
maxBid = c
highBidder = b
}
}
return prevBid, highBidder
}
/**
* RunAuctionVerbosely simulates a single-bid second-price auction with no
* reserve price between all bidders emitted by the provided generator,
* returning all bidders sorted by the order they dropped out and how much the
* winning bidder paid.
*
* Use CappedBidderGenerator to limit the size of the auction and therefore
* the number of bidders on the list.
*/
func RunAuctionVerbosely(g BidderGenerator) float64, []Bidder {
var bidders []Bidder
for b, ok := g.Generate(); ok; b, ok = g.Generate() {
bidders = append(bidders, b)
}
slices.SortFunc(bidders, func(a, b Bidder) int {
// If both bid ceilings are infinite in the same direction, we get NaN here...
d := a.BidCeiling() - b.BidCeiling()
if d < 0 {
return -1
}
if d > 0 {
return 1
}
// ...which is fine, since NaN will fail both comparisons and return 0 here, so these
// (incomparable) infinities get reported as equal, which is good enough.
return 0
})
if len(bidders) <= 1 {
// With one or zero bidders, there's no auction. The bidder (if any) gets it for the
// reserve price, but there is no reserve price, so the auctioneer pays the sole bidder
// an infinite amount of money to go away. Economics!
return math.Inf(-1), bidders
}
// Final price is the second highest bidder's limit.
return bidders[len(bidders)-2].BidCeiling(), bidders
}