I'm creating a virtual auction game, and I need more complex NPC behavior than I have now. Basically, every item has a base price (bp), and the starting bid (sb) for that item will be calculated with this range (or something very similar): 0.8bp <= sb <= 1.1bp. The opposing NPC bidders need to judge how reasonable the current bid is, compared to the base price and/or starting value, and, with some outlying behavior (i.e. betting when it seems a little irrational), bid reasonably on the current item. Put simply, it should bid aggressively on the item when the bid is lower or around the base price, and frugally bid on the item if it's high above the base price, or just give up.
The issue is, I really have no idea how to do this. Not only that, this is going to mainly be run on a TI-84 Plus CE calculator, so the external libraries and modules have to be pretty limited (essentially just random). It'd be great if you attach a brief (or long) explanation of any formulas/code you provide, because I'd love to learn more about this.
Here's an answer for you to get started:
import random
from dataclasses import dataclass
@dataclass
class Npc:
i: int
alpha = 2
beta = 0.25
bid_percent_increase_min = 1.01
bid_percent_increase_max = 1.03
percent_thresh_for_mandatory_bid = 0.75
def bet(self, cb, bp):
r = (
random.gammavariate(self.alpha, self.beta)
+ self.percent_thresh_for_mandatory_bid
)
if r >= cb / bp:
return (
random.uniform(
self.bid_percent_increase_min, self.bid_percent_increase_max
)
* cb
)
return 0
@dataclass
class Auction:
item_name: str
bp: float
npcs: int = 5
starting_bid_percent_min = 0.8
starting_bid_percent_max = 1.1
def __call__(self, *args, **kwargs):
# 0.8bp <= sb <= 1.1bp
cb = (
random.uniform(self.starting_bid_percent_min, self.starting_bid_percent_max)
* self.bp
)
print(f"Auction starting for {self.item_name.title()} (BP: ${self.bp:.2f})")
print(f"\tStarting bid: ${cb:.2f}")
bettors = [Npc(i) for i in range(self.npcs)]
random.shuffle(bettors)
while len(bettors) > 1:
for j, bettor in enumerate(bettors):
b = bettor.bet(cb, self.bp)
if b > cb:
print(
f"\t\tCurrent bid: ${cb:.2f} | Bettor {bettor.i} bids ${b:.2f}"
)
cb = b
else:
print(f"\tBettor {bettor.i} left")
bettors.pop(j)
random.shuffle(bettors)
print(
f"Winning bid: ${cb:.2f} | Bettor {bettors[0].i} won the {self.item_name.title()}!"
)
if __name__ == "__main__":
items = [
("apple", 1.30),
("water bottle", 9.99),
("tv", 189.99),
("laptop", 1499.99),
]
for item_name, bp in items:
Auction(item_name, bp)()
print("\n")
Example Output:
Auction starting for Apple (BP: $1.30)
Starting bid: $1.23
Bettor 0 left
Current bid: $1.23 | Bettor 2 bids $1.25
Current bid: $1.25 | Bettor 3 bids $1.28
Current bid: $1.28 | Bettor 4 bids $1.30
Current bid: $1.30 | Bettor 1 bids $1.32
Bettor 2 left
Bettor 4 left
Current bid: $1.32 | Bettor 1 bids $1.34
Current bid: $1.34 | Bettor 3 bids $1.35
Current bid: $1.35 | Bettor 1 bids $1.39
Current bid: $1.39 | Bettor 3 bids $1.43
Current bid: $1.43 | Bettor 1 bids $1.47
Bettor 3 left
Winning bid: $1.47 | Bettor 1 won the Apple!
Auction starting for Water Bottle (BP: $9.99)
Starting bid: $10.63
Bettor 0 left
Current bid: $10.63 | Bettor 2 bids $10.77
Current bid: $10.77 | Bettor 3 bids $11.00
Bettor 4 left
Current bid: $11.00 | Bettor 1 bids $11.27
Current bid: $11.27 | Bettor 2 bids $11.50
Current bid: $11.50 | Bettor 3 bids $11.75
Bettor 1 left
Current bid: $11.75 | Bettor 3 bids $11.92
Current bid: $11.92 | Bettor 2 bids $12.20
Current bid: $12.20 | Bettor 3 bids $12.36
Bettor 2 left
Winning bid: $12.36 | Bettor 3 won the Water Bottle!
Auction starting for Tv (BP: $189.99)
Starting bid: $171.10
Current bid: $171.10 | Bettor 0 bids $174.12
Current bid: $174.12 | Bettor 1 bids $177.67
Current bid: $177.67 | Bettor 2 bids $180.92
Current bid: $180.92 | Bettor 3 bids $183.20
Current bid: $183.20 | Bettor 4 bids $186.78
Bettor 0 left
Current bid: $186.78 | Bettor 2 bids $189.89
Bettor 3 left
Current bid: $189.89 | Bettor 1 bids $192.56
Bettor 2 left
Current bid: $192.56 | Bettor 1 bids $196.38
Current bid: $196.38 | Bettor 4 bids $200.25
Current bid: $200.25 | Bettor 1 bids $206.24
Bettor 4 left
Winning bid: $206.24 | Bettor 1 won the Tv!
Auction starting for Laptop (BP: $1499.99)
Starting bid: $1404.03
Bettor 0 left
Current bid: $1404.03 | Bettor 2 bids $1431.79
Current bid: $1431.79 | Bettor 3 bids $1450.59
Current bid: $1450.59 | Bettor 4 bids $1491.00
Current bid: $1491.00 | Bettor 1 bids $1508.36
Bettor 2 left
Current bid: $1508.36 | Bettor 4 bids $1550.88
Current bid: $1550.88 | Bettor 1 bids $1589.62
Current bid: $1589.62 | Bettor 3 bids $1613.55
Current bid: $1613.55 | Bettor 4 bids $1650.92
Bettor 1 left
Current bid: $1650.92 | Bettor 4 bids $1684.26
Current bid: $1684.26 | Bettor 3 bids $1715.78
Current bid: $1715.78 | Bettor 4 bids $1750.79
Bettor 3 left
Winning bid: $1750.79 | Bettor 4 won the Laptop!
Here I used the gamma distribution, the PDF looks like this (offset by 0.75):
An NPC makes a bet if a random value drawn from this distribution is greater than (current bid / base price). What this means:
You can obviously play with the alpha
and beta
values along with some of the other parameters to better suit your particular situation.