71 lines
2.1 KiB
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
|
|
}
|