forge/blade/systems/exchange.py (77 lines of code) (raw):

from collections import defaultdict from queue import PriorityQueue class Offer: def __init__(self, item, quant, itemPrice, coffer=0): self.item = item self.quantLeft = quant self.quantFulfilled = 0 self.itemPrice = itemPrice self.coffer = coffer @property def complete(self): return self.quantLeft == 0 def partialCollect(self): pass def cancel(self): return self.coffer, [self.item() for e in self.quantFulfilled] def __lt__(self, other): return True def __eq__(self, other): return False class BuyOffer(Offer): def buy(self, quant, itemPrice): self.coffer -= itemPrice * quant #Collect only profits thus far def partialCollect(self): ret = [self.item() for e in self.quantFulfilled] self.quantFulfilled = 0 return ret class SellOffer(Offer): def sell(self, quant): self.coffer += self.itemPrice * quant self.quantLeft -= quant assert self.quantLeft >= 0 def partialCollect(self): ret = self.coffer self.coffer = 0 return self.coffer #Why is there no peek fuction... class PQ(PriorityQueue): def peek(self): if len(self.queue) > 0: return self.queue[0] return None class Exchange: def __init__(self): self.buyOffers = defaultdict(PQ) self.sellOffers = defaultdict(PQ) def buy(self, item, quant, maxPrice): offer = BuyOffer(item, quant, maxPrice, coffer=quant*maxPrice) self.buyOffers[item].put(offer, -maxPrice) self.update(item) return offer def sell(self, item, quant, itemPrice): offer = SellOffer(item, quant, itemPrice) self.sellOffers[item].put(offer, itemPrice) self.update(item) return offer def update(self, item): buyOffer = self.buyOffers[item].peek() sellOffer = self.sellOffers[item].peek() if None in (buyOffer, sellOffer): return maxBuy, minSell = buyOffer.itemPrice, sellOffer.itemPrice itemPrice = minSell #Advantage given to buyer arbitrarily if maxBuy >= minSell: if sellOffer.quantLeft < buyOffer.quantLeft: buyOffer.buy(sellOffer.quantLeft, itemPrice) sellOffer.sell(sellOffer.quantLeft) self.sellOffers[item].get() elif sellOffer.quantLeft > buyOffer.quantLeft: buyOffer.buy(buyOffer.quantLeft, itemPrice) sellOffer.sell(buyOffer.quantLeft) self.buyOffers[item].get() elif sellOffer.quantLeft == buyOffer.quantLeft: buyOffers.buy(buyOffer.quantLeft, itemPrice) sellOffer.sell(sellOffer.quantLeft) self.buyOffers[item].get() self.sellOffers[item].get() self.update(item)