larsiusprime / bazaarBot

A simple free market simulator engine. Based on "Emergent Economies for Role Playing Games" by Doran and Parberry.
MIT License
377 stars 47 forks source link

Defining the API #4

Closed giang-nghg closed 9 years ago

giang-nghg commented 11 years ago

I think your idea of making an API similar to physics engines' is briliant. Have you started working on that yet?

larsiusprime commented 11 years ago

Haven't done much work with bazaarBot yet other than just implement the research paper. I'm planning on doing a GDC talk for bazaarBot next year, so I'll make sure to spruce it up before then. If you have any suggestions, I'm all ears!

giang-nghg commented 11 years ago

I think thinking about the API will reveal how the engine should be used => what does it misses, etc. driving its completion. Therefore we should do it first. I would like to know if you're already doing it, so I can participate. Or else I would like to suggest some first APIs.

larsiusprime commented 11 years ago

Sure, let's get started!

I haven't really dived into it full-steam just yet, so you're basically getting in on the ground floor. Right now there's a few problems - for instance, it does this half-baked data driven thingy with Agent logic which is really slow. The point was to be flexible, but it's probably best to just let the user create their own production functions in actual code and just extend some base class headers.

giang-nghg commented 11 years ago

I've thought of 6 draft use cases which I think can be useful to many games. All of them are for interacting with a single agent only. The example game is a TBS similar to Heroes 3, where each day/turn is a trading round.

The first 2 is fundamental: player wants to perform immediate transactions within the current trading round, The price is the agent's price, not the avg price (so player can go around looking for the best deal, and the best deal will change everyday): 1/ agent.Sell(quantity, cash) returns the desired quantity of the agent's commodity if cash is enough 2/ agent.Buy(quantity) returns the cash amount for the bought (from player) quantity

The next 2 is when player wants to invest in or sabotage an agent by supply/take from him an amount of his commodity: 3/ agent.Receive(quantity) 4/ agent.Lose(quantity)

The next 2 is when player intimidate/force an agent to buy more expensive/sell cheaper than his willing prices 5/ agent.ForceToSell(quantity, cash) : Like agent.Sell() but won't check for enough cash 6/ agent.ForceToBuy(quantity, price) : Like agent.Buy() but will use the input price

I think a straightfoward way to make a game "fun" is to let players disrupt the market in various ways (like 3-6 above). Further is, like you said, allow developers to create custom market logic & behaviours for different agents.

The best way to test all this ideas is to develop some games as further proof-of-concepts. Also they can attract more contribution, I think.

larsiusprime commented 11 years ago

So, let me look at this.

The commodity will have to be specified in each case. Agents can carry more than one type of commodity in their inventory.

I think "unit_price" should be the price variable in these functions. This way it's clear and unambiguous what it means, and it's consistent with what's used internally by the engine.

Also, I think in your example, agent.Sell() means "the agent sells to the player." It took me a while to understand that, at first I assumed it meant "the agent sell to the market." If you want functions to sell to the player, the player should have their own agent object, and you would call something like agent.SellToAgent().

So, to make things clear, we should probably do something like: agent.SellToAgent() agent.SetllToMarket() agent.BuyFromAgent() agent.BuyFromMarket()

With the current setup of BazaarBot, several unexpected things could happen with a simple market sell order.

The agent could sell all of its stuff at its minimum selling price or higher, it could sell nothing b/c it's price was too high, or it could actually wind up in a negotiated position, where it gets matched with a buyer and compromises on final price. (currently, when BazaarBot matches the highest buying price with the lowest selling price, it creates a negotiated clearing price exactly in the middle).

So, for the research paper implementation this was fine, but the player might not be willing to budge on price in this fashion - they might INSIST that they pay NO MORE than this unit price under any circumstance.

So, we need another variable - flexibility, which represents how far they're willing to negotiate. A float from 0.0-1.0 should do: 0 means "this price only, take it or leave it", whereas 1 means "when I am matched I will accept their asking price if I have to." Even if the agent has a flexibility of 1 (the maximum), that doesn't mean they will pay any price whatsoever - they will still be matched with the best available offer before negotiations happen.

So, with this model, we can understand the current BazaarBot behavior to be implicitly treating all Agents as having a flexibility of 0.5 - each is perfectly willing to meet a matched agent at exactly the middle of the buy and sell price. So, with the new system, trades will be cleared if the sum of the two agent's flexibility is >= 1.0. If not, it fails. If it succeeds, the least flexible agent gets their price.

Example:

Buy orders will need similar flexibility amounts, and should also have a maximum price.

Now, you were talking about direct agent trades. I think they would look like this:

BuyFromAgent(other_agent:Agent,commodity:String, quantity:Float,unit_price:Float,flexibility:Float,force:Bool=false):TradeResult; Call this on your own agent, pass in the npc agent, what you want to buy, your price, and flexibility. Returns a TradeResult structure: {success:Bool, units:Float, unit_price:Float}

SellToAgent(other_agent:Agent,commodity:String,quantity:Float,unit_price:Float,flexibility:Float,force:Bool=false):TradeResult; Call this on your own agent, pass in the npc agent, what you want to sell, your price, and flexibility. Returns a TradeResult structure: {success:Bool, units:Float, unit_price:Float}

Both of these have an optional "force" parameter that is false by default. If you set that to true, you force the trade to go through even if the other agent is unwilling. In this case the other agent takes your price (ignoring flexibilities), and does the trade. The only time the trade fails is if they don't have any money (force buy) or don't have any commodities (force sell).

larsiusprime commented 11 years ago

Also, a simple trade function:

agent.trade(other_agent:Agent,commodity:String,units:Float,unit_price:Float);

Just immediately trades the specified goods at that price, no questions asked. This function is what you use to drive actual transactions after a price has been agreed upon, for instance, or for other purposes, like stealing.

giang-nghg commented 11 years ago

Yes, that is better. And the SellToMarket() & BuyFromMarket() will make the player's agent behaves like an AI one: Declare bids/asks, wait to be matched & auto- buy/sell depending on his flexibility, right?

giang-nghg commented 11 years ago

SellToMarket(commodity:String, quantity:Float, unit_price:Float, flexibility:Float) BuyFromMarket(commodity:String, quantity:Float, unit_price:Float, flexibility:Float) : TradeResult;

No forcing when deal with market. Or should it? Like when a force big enough to subdue an entire market (a bandit group, a warlord,...)?

larsiusprime commented 11 years ago

Hmm... interesting. Well, the "force" parameter will force the other party to accept the trade even if they don't want to. With agent-to-agent that's simple.... but the market is just a collection of other agents, so I'll have to think about it. "Forcing" the market means forcing some agent in the market to do something, and then, how do you decide which agent? And if you have a way of deciding which agent, why not just select that agent and use the agent function to force them?

In real life, when markets are "forced" to do things, it's generally because the government wants to impose a law or something, and they usually accomplish this via their own agents or other means. So, if the government wants to "force" the market to buy some goods at a certain price, usually this means that a government agent does the buying.

So, I think it's best if we leave "force" off the market functions for now.

This does raise the question about how to represent governments and laws. We could probably create a structure called "Regulations" or something that would be the member variable of a market. That would define the laws that market must follow (ie, you have to pay 10% sales tax to the government agent (or 25% tribute to the warlord) whenever you buy something, or whatever).