├── EconomySim ├── EconomySim.suo ├── EconomySim │ ├── Properties │ │ ├── licenses.licx │ │ ├── Settings.settings │ │ ├── Settings.Designer.cs │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── EconomySim.csproj.user │ ├── Good.cs │ ├── Program.cs │ ├── MarketReport.cs │ ├── Offer.cs │ ├── Economy.cs │ ├── TradeBook.cs │ ├── settings.txt │ ├── InventoryData.cs │ ├── Form1.cs │ ├── History.cs │ ├── MarketData.cs │ ├── Agent.cs │ ├── Form1.resx │ ├── Form1.Designer.cs │ ├── Quick.cs │ ├── EconomySim.csproj │ ├── Inventory.cs │ ├── BasicAgent.cs │ ├── MyEconomy.cs │ ├── Logic.cs │ └── Market.cs └── EconomySim.sln ├── README.md └── LICENSE /EconomySim/EconomySim.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vibr8gKiwi/bazaarBot2/HEAD/EconomySim/EconomySim.suo -------------------------------------------------------------------------------- /EconomySim/EconomySim/Properties/licenses.licx: -------------------------------------------------------------------------------- 1 | DevExpress.XtraGrid.GridControl, DevExpress.XtraGrid.v13.2, Version=13.2.5.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a 2 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bazaarBot2 2 | This is a C# port of bazaarBot by @larsiusprime with several modifications to fix issues I think existed. See this discussion for background: 3 | 4 | https://github.com/larsiusprime/bazaarBot/issues/17 5 | 6 | 7 | It should run but is somewhat incomplete compared to the original in its output, json processing, etc. If anyone wants to clean it up you have my thanks. 8 | 9 | Note that I changed the name to EconomySim because I'm always stumbling over the spelling of "bazaar." 10 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/EconomySim.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | publish\ 5 | 6 | 7 | 8 | 9 | 10 | en-US 11 | false 12 | 13 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Good.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | 9 | class Good 10 | { 11 | public String id = ""; //string id of good 12 | public double size = 1.0; //inventory size taken up 13 | 14 | public Good (String id_, double size_) 15 | { 16 | id = id_; 17 | size = size_; 18 | } 19 | 20 | public Good copy() 21 | { 22 | return new Good(id, size); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | 6 | namespace EconomySim 7 | { 8 | static class Program 9 | { 10 | /// 11 | /// The main entry point for the application. 12 | /// 13 | [STAThread] 14 | static void Main() 15 | { 16 | Application.EnableVisualStyles(); 17 | Application.SetCompatibleTextRenderingDefault(false); 18 | Application.Run(new Form1()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/MarketReport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace EconomySim 8 | { 9 | class MarketReport 10 | { 11 | public String strListGood = ""; 12 | public String strListGoodPrices= ""; 13 | public String strListGoodTrades = ""; 14 | public String strListGoodAsks = ""; 15 | public String strListGoodBids = ""; 16 | 17 | public String strListAgent = ""; 18 | public String strListAgentCount = ""; 19 | public String strListAgentMoney = ""; 20 | public String strListAgentProfit = ""; 21 | 22 | public List arrStrListInventory { get; set; } 23 | 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Offer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | class Offer 9 | { 10 | public String good; //the thing offered 11 | public double units; //how many units 12 | public double unit_price; //price per unit 13 | public int agent_id; //who offered this 14 | 15 | public Offer(int agent_id_=-1,String commodity_="",double units_=1.0,double unit_price_=1.0) 16 | { 17 | agent_id = agent_id_; 18 | good = commodity_; 19 | units = units_; 20 | unit_price = unit_price_; 21 | } 22 | 23 | public String toString() 24 | { 25 | return "("+agent_id + "): " + good + "x " + units + " @ " + unit_price; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /EconomySim/EconomySim.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EconomySim", "EconomySim\EconomySim.csproj", "{0AF795D6-768F-4E1E-957D-79F7F1F09747}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {0AF795D6-768F-4E1E-957D-79F7F1F09747}.Debug|x86.ActiveCfg = Debug|x86 13 | {0AF795D6-768F-4E1E-957D-79F7F1F09747}.Debug|x86.Build.0 = Debug|x86 14 | {0AF795D6-768F-4E1E-957D-79F7F1F09747}.Release|x86.ActiveCfg = Release|x86 15 | {0AF795D6-768F-4E1E-957D-79F7F1F09747}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Economy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | class Economy : ISignalBankrupt 9 | { 10 | private List _markets; 11 | 12 | public Economy() 13 | { 14 | _markets = new List(); 15 | } 16 | 17 | public void addMarket(Market m) 18 | { 19 | if (_markets.IndexOf(m) == -1) 20 | { 21 | _markets.Add(m); 22 | } 23 | } 24 | 25 | public Market getMarket(String name) 26 | { 27 | foreach (var m in _markets) 28 | { 29 | if (m.name == name) return m; 30 | } 31 | return null; 32 | } 33 | 34 | public void simulate(int rounds) 35 | { 36 | foreach (var m in _markets) 37 | { 38 | m.simulate(rounds); 39 | } 40 | } 41 | 42 | 43 | public virtual void signalBankrupt(Market m, BasicAgent a) 44 | { 45 | //no implemenation -- provide your own in a subclass 46 | } 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace EconomySim.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/TradeBook.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace EconomySim 8 | { 9 | class TradeBook 10 | { 11 | public Dictionary> bids; 12 | public Dictionary> asks; 13 | 14 | public DataTable dbook { get; set; } 15 | 16 | public TradeBook() 17 | { 18 | bids = new Dictionary>(); 19 | asks = new Dictionary>(); 20 | dbook = new DataTable("Book"); 21 | dbook.Columns.Add(new DataColumn("bid")); 22 | dbook.Columns.Add(new DataColumn("ask")); 23 | dbook.Rows.Add(1.0,2.0); 24 | } 25 | 26 | public void register(String name) 27 | { 28 | asks[name] = new List(); 29 | bids[name] = new List(); 30 | } 31 | 32 | public bool bid(Offer offer) 33 | { 34 | if (!bids.ContainsKey(offer.good)) 35 | return false; 36 | 37 | bids[offer.good].Add(offer); 38 | return true; 39 | } 40 | 41 | public bool ask(Offer offer) 42 | { 43 | if (!bids.ContainsKey(offer.good)) 44 | return false; 45 | 46 | asks[offer.good].Add(offer); 47 | return true; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("EconomySim")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Hewlett-Packard Company")] 12 | [assembly: AssemblyProduct("EconomySim")] 13 | [assembly: AssemblyCopyright("Copyright © Hewlett-Packard Company 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5548d7fc-307f-4a48-90ee-6f23cba4adaa")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/settings.txt: -------------------------------------------------------------------------------- 1 | { 2 | "start_conditions":{ 3 | "agents":{ 4 | "farmer":10, 5 | "miner":10, 6 | "woodcutter":10, 7 | "refiner":10, 8 | "blacksmith":10 9 | } 10 | }, 11 | "goods":[ 12 | {"id":"food" ,"size":"0.5"}, 13 | {"id":"wood" ,"size":"1.0"}, 14 | {"id":"ore" ,"size":"1.0"}, 15 | {"id":"metal","size":"1.0"}, 16 | {"id":"tools","size":"1.0"} 17 | ], 18 | "agents":[ 19 | { 20 | "id":"farmer", 21 | "money":100, 22 | "inventory":{ 23 | "start":{"food":0,"tools":1,"wood":0}, 24 | "ideal":{"food":0,"tools":1,"wood":3}, 25 | "max_size":20 26 | }, 27 | "logic":"farmer" 28 | }, 29 | { 30 | "id":"miner", 31 | "money":100, 32 | "inventory":{ 33 | "start":{"food":1,"tools":1,"ore":0}, 34 | "ideal":{"food":3,"tools":1,"ore":0}, 35 | "max_size":20 36 | }, 37 | "logic":"miner" 38 | }, 39 | { 40 | "id":"refiner", 41 | "money":100, 42 | "inventory":{ 43 | "start":{"food":1,"tools":1,"metal":0,"ore":0}, 44 | "ideal":{"food":3,"tools":1,"metal":0,"ore":5}, 45 | "max_size":20 46 | }, 47 | "logic":"refiner" 48 | }, 49 | { 50 | "id":"woodcutter", 51 | "money":100, 52 | "inventory":{ 53 | "start":{"food":1,"tools":1,"wood":0}, 54 | "ideal":{"food":3,"tools":1,"wood":0}, 55 | "max_size":20 56 | }, 57 | "logic":"woodcutter" 58 | }, 59 | { 60 | "id":"blacksmith", 61 | "money":100, 62 | "inventory":{ 63 | "start":{"food":1,"tools":0,"metal":0,"ore":0}, 64 | "ideal":{"food":3,"tools":1,"metal":5,"ore":0}, 65 | "max_size":20 66 | }, 67 | "logic":"blacksmith" 68 | } 69 | ] 70 | } -------------------------------------------------------------------------------- /EconomySim/EconomySim/InventoryData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | 9 | /** 10 | */ 11 | class InventoryData 12 | { 13 | public double maxSize; 14 | public Dictionary ideal; 15 | public Dictionary start; 16 | public Dictionary size; 17 | 18 | public InventoryData(double maxSize, Dictionaryideal, Dictionarystart, Dictionarysize) 19 | { 20 | this.maxSize = maxSize; 21 | this.ideal = ideal; 22 | this.start = start; 23 | this.size = size; 24 | if (this.size == null) 25 | { 26 | this.size = new Dictionary(); 27 | foreach (KeyValuePair entry in start) 28 | { 29 | this.size[entry.Key] = 1; 30 | } 31 | } 32 | } 33 | 34 | public InventoryData(string data) 35 | { 36 | //var maxSize:Int = data.max_size; 37 | //var ideal = new Map(); 38 | //var start = new Map(); 39 | //var size = new Map(); 40 | 41 | //var startArray = Reflect.fields(data.start); 42 | //if (startArray != null) 43 | //{ 44 | // for (s in startArray) 45 | // { 46 | // start.set(s, cast Reflect.field(data.start, s)); 47 | // size.set(s, 1); //initialize size of every item to 1 by default 48 | // } 49 | //} 50 | //var idealArray = Reflect.fields(data.ideal); 51 | //if (idealArray != null) 52 | //{ 53 | // for (i in idealArray) 54 | // { 55 | // ideal.set(i, cast Reflect.field(data.ideal, i)); 56 | // } 57 | //} 58 | 59 | //return new InventoryData(maxSize, ideal, start, size); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | 10 | namespace EconomySim 11 | { 12 | public partial class Form1 : Form 13 | { 14 | 15 | private Economy economy; 16 | private Market market; 17 | // private MarketDisplay display; 18 | // private TextField txt_benchmark; 19 | 20 | public Form1() 21 | { 22 | InitializeComponent(); 23 | } 24 | 25 | private void button1_Click(object sender, EventArgs e) 26 | { 27 | economy = new DoranAndParberryEconomy(); 28 | 29 | market = economy.getMarket("default"); 30 | 31 | dataGridView1.DataSource = market._agents; 32 | //dataGridView2.DataSource = market._book.dbook; 33 | 34 | } 35 | 36 | private void run(int rounds) 37 | { 38 | market.simulate(rounds); 39 | var res = market.get_marketReport(rounds); 40 | dataGridView1.Refresh(); 41 | //dataGridView2.DataSource = res.arrStrListInventory; 42 | textBox1.Clear(); 43 | textBox1.Text = res.strListGood.Replace("\n", " ") + Environment.NewLine; 44 | textBox1.Text += res.strListGoodPrices.Replace("\n", " ") + Environment.NewLine; 45 | textBox1.Text += res.strListGoodTrades.Replace("\n", " ") + Environment.NewLine; 46 | textBox1.Text += res.strListGoodBids.Replace("\n", " ") + Environment.NewLine; 47 | textBox1.Text += res.strListGoodAsks.Replace("\n", " ") + Environment.NewLine; 48 | //textBox1.Lines = res.arrStrListInventory.ToArray(); 49 | //dataGridView1.DataSource = market._agents; 50 | } 51 | 52 | private void button2_Click(object sender, EventArgs e) 53 | { 54 | run(1); 55 | } 56 | 57 | private void button3_Click(object sender, EventArgs e) 58 | { 59 | run(20); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/History.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | enum EconNoun 9 | { 10 | Price, 11 | Ask, 12 | Bid, 13 | Trade, 14 | Profit 15 | } 16 | 17 | class HistoryLog 18 | { 19 | EconNoun type; 20 | Dictionary>log; 21 | 22 | public HistoryLog(EconNoun type) 23 | { 24 | this.type = type; 25 | log = new Dictionary>(); 26 | } 27 | 28 | /** 29 | * Add a new entry to this log 30 | * @param name 31 | * @param amount 32 | */ 33 | public void add(String name, double amount) 34 | { 35 | if (log.ContainsKey(name)) 36 | { 37 | var list = log[name]; 38 | list.Add(amount); 39 | } 40 | } 41 | 42 | /** 43 | * Register a new category list in this log 44 | * @param name 45 | */ 46 | public void register(String name) 47 | { 48 | if (!log.ContainsKey(name)) 49 | { 50 | log[name] = new List(); 51 | } 52 | } 53 | 54 | /** 55 | * Returns the average amount of the given category, looking backwards over a specified range 56 | * @param name the category of thing 57 | * @param range how far to look back 58 | * @return 59 | */ 60 | public double average(String name, int range) 61 | { 62 | if (log.ContainsKey(name)) 63 | { 64 | var list = log[name]; 65 | double amt = 0.0; 66 | var length = list.Count; 67 | if (length < range) 68 | { 69 | range = length; 70 | } 71 | for (int i=0; i goods; 11 | public ListagentTypes; 12 | public List agents; 13 | 14 | public MarketData(Listgoods, ListagentTypes, List agents) 15 | { 16 | this.goods = goods; 17 | this.agentTypes = agentTypes; 18 | this.agents = agents; 19 | } 20 | 21 | /** 22 | * Parse a market settings file to construct everything 23 | * @param data the JSON file definition for your Market 24 | * @param getAgent a function to create agents 25 | */ 26 | 27 | public static MarketData fromJSON(string json, BasicAgent getAgent) 28 | { 29 | //var goods:Array = []; 30 | 31 | ////Create goods index 32 | //var jsonGoods:Array = json.goods; 33 | //for (g in jsonGoods) 34 | //{ 35 | // goods.push(new Good(g.id, g.size)); 36 | //} 37 | 38 | //var agentTypes:Array = []; 39 | 40 | ////Create agent classes 41 | //var jsonAgents:Array = json.agents; 42 | 43 | //for (a in jsonAgents) 44 | //{ 45 | // var agentData:AgentData = 46 | // { 47 | // className:a.id, 48 | // money:a.money, 49 | // inventory:InventoryData.fromJson(a.inventory), 50 | // logicName:a.id, 51 | // logic:null 52 | // } 53 | 54 | // for (g in goods) 55 | // { 56 | // agentData.inventory.size.set(g.id, g.size); 57 | // } 58 | 59 | // agentTypes.push(agentData); 60 | //} 61 | 62 | ////Make the agent list 63 | //var agents:Array = []; 64 | 65 | ////Get start conditions 66 | //var startConditions:Dynamic = json.start_conditions; 67 | //var starts = Reflect.fields(startConditions.agents); 68 | 69 | //var agentIndex:Int = 0; 70 | ////Make given number of each agent type 71 | 72 | //for (classStr in starts) 73 | //{ 74 | // var val:Int = Reflect.field(startConditions.agents, classStr); 75 | // var agentData = null; 76 | // for (i in 0...agentTypes.length) { 77 | // if (agentTypes[i].className == classStr) 78 | // { 79 | // agentData = agentTypes[i]; 80 | // break; 81 | // } 82 | // } 83 | 84 | // for (i in 0...val) 85 | // { 86 | // var a:BasicAgent = getAgent(agentData); 87 | // a.id = agentIndex; 88 | // agentIndex++; 89 | // agents.push(a); 90 | // } 91 | //} 92 | 93 | //return new MarketData(goods, agentTypes, agents); 94 | return null; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Agent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | 9 | /** 10 | * An agent that performs the basic logic from the Doran & Parberry article 11 | * @author 12 | */ 13 | class Agent : BasicAgent 14 | { 15 | 16 | public static double MIN_PRICE = 0.01; //lowest possible price 17 | 18 | public Agent(int id, AgentData data) : base(id,data) 19 | { 20 | } 21 | 22 | 23 | override public Offer createBid(Market bazaar, String good, double limit) 24 | { 25 | var bidPrice = 0;// determinePriceOf(good); bids are now made "at market", no price determination needed 26 | var ideal = determinePurchaseQuantity(bazaar, good); 27 | 28 | //can't buy more than limit 29 | double quantityToBuy = ideal > limit ? limit : ideal; 30 | if (quantityToBuy > 0) 31 | { 32 | return new Offer(id, good, quantityToBuy, bidPrice); 33 | } 34 | return null; 35 | } 36 | 37 | override public Offer createAsk(Market bazaar, String commodity_, double limit_) 38 | { 39 | var ask_price = _inventory.query_cost(commodity_) * 1.02; //asks are fair prices: costs + small profit 40 | 41 | var quantity_to_sell = _inventory.query(commodity_);//put asks out for all inventory 42 | nProduct = quantity_to_sell; 43 | 44 | if (quantity_to_sell > 0) 45 | { 46 | return new Offer(id, commodity_, quantity_to_sell, ask_price); 47 | } 48 | return null; 49 | } 50 | 51 | override public void generateOffers(Market bazaar, String commodity) 52 | { 53 | Offer offer; 54 | double surplus = _inventory.surplus(commodity); 55 | if (surplus >= 1) 56 | { 57 | offer = createAsk(bazaar, commodity, 1); 58 | if (offer != null) 59 | { 60 | bazaar.ask(offer); 61 | } 62 | } 63 | else 64 | { 65 | var shortage = _inventory.shortage(commodity); 66 | var space = _inventory.getEmptySpace(); 67 | var unit_size = _inventory.getCapacityFor(commodity); 68 | 69 | if (shortage > 0 && space >= unit_size) 70 | { 71 | double limit = 0; 72 | if ((shortage * unit_size) <= space) //enough space for ideal order 73 | { 74 | limit = shortage; 75 | } 76 | else //not enough space for ideal order 77 | { 78 | limit = space; // Math.Floor(space / shortage); 79 | } 80 | 81 | if (limit > 0) 82 | { 83 | offer = createBid(bazaar, commodity, limit); 84 | if (offer != null) 85 | { 86 | bazaar.bid(offer); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | override public void updatePriceModel(Market bazaar, String act, String good, bool success, double unitPrice= 0) 94 | { 95 | List observed_trades; 96 | 97 | if (success) 98 | { 99 | //Add this to my list of observed trades 100 | observed_trades = _observedTradingRange[good]; 101 | observed_trades.Add(unitPrice); 102 | } 103 | 104 | var public_mean_price = bazaar.getAverageHistoricalPrice(good, 1); 105 | 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace EconomySim.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | public class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | public static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("EconomySim.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | public static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to { 65 | /// "start_conditions":{ 66 | /// "agents":{ 67 | /// "farmer":10, 68 | /// "miner":10, 69 | /// "woodcutter":10, 70 | /// "refiner":10, 71 | /// "blacksmith":10 72 | /// } 73 | /// }, 74 | /// "goods":[ 75 | /// {"id":"food" ,"size":"0.5"}, 76 | /// {"id":"wood" ,"size":"1.0"}, 77 | /// {"id":"ore" ,"size":"1.0"}, 78 | /// {"id":"metal","size":"1.0"}, 79 | /// {"id":"tools","size":"1.0"} 80 | /// ], 81 | /// "agents":[ 82 | /// { 83 | /// "id":"farmer", 84 | /// "money":100, 85 | /// "inventory":{ 86 | /// "start":{"food":0,"tools":1,"wood":0}, 87 | /// "ideal":{"food":0,"tools":1,"wood":3}, 88 | /// "max_size":20 89 | /// }, 90 | /// "logi [rest of string was truncated]";. 91 | /// 92 | public static string settings_json { 93 | get { 94 | return ResourceManager.GetString("settings_json", resourceCulture); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Form1.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace EconomySim 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.button1 = new System.Windows.Forms.Button(); 32 | this.button2 = new System.Windows.Forms.Button(); 33 | this.dataGridView1 = new System.Windows.Forms.DataGridView(); 34 | this.dataGridView2 = new System.Windows.Forms.DataGridView(); 35 | this.textBox1 = new System.Windows.Forms.TextBox(); 36 | this.button3 = new System.Windows.Forms.Button(); 37 | this.tbLog = new System.Windows.Forms.TextBox(); 38 | ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); 39 | ((System.ComponentModel.ISupportInitialize)(this.dataGridView2)).BeginInit(); 40 | this.SuspendLayout(); 41 | // 42 | // button1 43 | // 44 | this.button1.Location = new System.Drawing.Point(12, 23); 45 | this.button1.Name = "button1"; 46 | this.button1.Size = new System.Drawing.Size(75, 23); 47 | this.button1.TabIndex = 0; 48 | this.button1.Text = "Init"; 49 | this.button1.UseVisualStyleBackColor = true; 50 | this.button1.Click += new System.EventHandler(this.button1_Click); 51 | // 52 | // button2 53 | // 54 | this.button2.Location = new System.Drawing.Point(12, 63); 55 | this.button2.Name = "button2"; 56 | this.button2.Size = new System.Drawing.Size(42, 23); 57 | this.button2.TabIndex = 1; 58 | this.button2.Text = "Step"; 59 | this.button2.UseVisualStyleBackColor = true; 60 | this.button2.Click += new System.EventHandler(this.button2_Click); 61 | // 62 | // dataGridView1 63 | // 64 | this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; 65 | this.dataGridView1.Location = new System.Drawing.Point(0, 123); 66 | this.dataGridView1.Name = "dataGridView1"; 67 | this.dataGridView1.Size = new System.Drawing.Size(604, 487); 68 | this.dataGridView1.TabIndex = 3; 69 | // 70 | // dataGridView2 71 | // 72 | this.dataGridView2.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; 73 | this.dataGridView2.Location = new System.Drawing.Point(325, 123); 74 | this.dataGridView2.Name = "dataGridView2"; 75 | this.dataGridView2.Size = new System.Drawing.Size(328, 487); 76 | this.dataGridView2.TabIndex = 4; 77 | // 78 | // textBox1 79 | // 80 | this.textBox1.Location = new System.Drawing.Point(130, 23); 81 | this.textBox1.Multiline = true; 82 | this.textBox1.Name = "textBox1"; 83 | this.textBox1.Size = new System.Drawing.Size(512, 94); 84 | this.textBox1.TabIndex = 5; 85 | // 86 | // button3 87 | // 88 | this.button3.Location = new System.Drawing.Point(60, 63); 89 | this.button3.Name = "button3"; 90 | this.button3.Size = new System.Drawing.Size(64, 23); 91 | this.button3.TabIndex = 6; 92 | this.button3.Text = "Step 20"; 93 | this.button3.UseVisualStyleBackColor = true; 94 | this.button3.Click += new System.EventHandler(this.button3_Click); 95 | // 96 | // tbLog 97 | // 98 | this.tbLog.Location = new System.Drawing.Point(0, 616); 99 | this.tbLog.Multiline = true; 100 | this.tbLog.Name = "tbLog"; 101 | this.tbLog.Size = new System.Drawing.Size(653, 80); 102 | this.tbLog.TabIndex = 7; 103 | // 104 | // Form1 105 | // 106 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 107 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 108 | this.ClientSize = new System.Drawing.Size(687, 697); 109 | this.Controls.Add(this.tbLog); 110 | this.Controls.Add(this.button3); 111 | this.Controls.Add(this.textBox1); 112 | this.Controls.Add(this.dataGridView1); 113 | this.Controls.Add(this.button2); 114 | this.Controls.Add(this.button1); 115 | this.Controls.Add(this.dataGridView2); 116 | this.Name = "Form1"; 117 | this.Text = "Form1"; 118 | ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); 119 | ((System.ComponentModel.ISupportInitialize)(this.dataGridView2)).EndInit(); 120 | this.ResumeLayout(false); 121 | this.PerformLayout(); 122 | 123 | } 124 | 125 | #endregion 126 | 127 | private System.Windows.Forms.Button button1; 128 | private System.Windows.Forms.Button button2; 129 | private System.Windows.Forms.DataGridView dataGridView1; 130 | private System.Windows.Forms.DataGridView dataGridView2; 131 | private System.Windows.Forms.TextBox textBox1; 132 | private System.Windows.Forms.Button button3; 133 | private System.Windows.Forms.TextBox tbLog; 134 | } 135 | } 136 | 137 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\settings.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 123 | 124 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Quick.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | class Quick 9 | { 10 | public static Random rnd = new Random(); 11 | 12 | 13 | public static double avgf(double a, double b) 14 | { 15 | return (a + b) / 2; 16 | } 17 | 18 | public static double listAvgf(List list) 19 | { 20 | double avg=0; 21 | for (int j = 0; j < list.Count; j++) 22 | { 23 | avg += list[j]; 24 | } 25 | avg /= list.Count; 26 | return avg; 27 | } 28 | 29 | public static double minArr(List a, int window) 30 | { 31 | double min = 99999999;//Math.POSITIVE_INFINITY; 32 | if (window > a.Count) window = a.Count; 33 | for (int i = 0; i < window-1; i++) 34 | { 35 | var f = a[a.Count-1 - i]; 36 | if (f < min) { min = f; } 37 | } 38 | 39 | return min; 40 | } 41 | 42 | public static double maxArr(List a, int window) 43 | { 44 | double max = -9999999;///Math.NEGATIVE_INFINITY; 45 | if (window > a.Count) window = a.Count; 46 | for (int i = 0; i < window - 1; i++) 47 | { 48 | var f = a[a.Count - 1 - i]; 49 | if (f > max) { max = f; } 50 | } 51 | return max; 52 | } 53 | 54 | /** 55 | * Turns a number into a string with the specified number of decimal points 56 | * @param num 57 | * @param decimals 58 | * @return 59 | */ 60 | public static String numStr(double num, int decimals) 61 | { 62 | string s = string.Format("{0:N"+decimals.ToString()+"}", num); 63 | return s; 64 | } 65 | // num = Math.floor(num * tens) / tens; 66 | // var str:String = Std.string(num); 67 | // var split = str.split("."); 68 | // if (split.length == 2) 69 | // { 70 | // if (split[1].length < decimals) 71 | // { 72 | // var diff:Int = decimals - split[1].length; 73 | // for (i in 0...diff) 74 | // { 75 | // str += "0"; 76 | // } 77 | // } 78 | // if (decimals > 0) 79 | // { 80 | // str = split[0] + "." + split[1].substr(0, decimals); 81 | // } 82 | // else 83 | // { 84 | // str = split[0]; 85 | // } 86 | // } 87 | // else 88 | // { 89 | // if (decimals > 0) 90 | // { 91 | // str += "."; 92 | // for (i in 0...decimals) 93 | // { 94 | // str += "0"; 95 | // } 96 | // } 97 | // } 98 | // return str; 99 | // } 100 | 101 | public static double positionInRange(double value, double min, double max, bool clamp = true) 102 | { 103 | value -= min; 104 | max -= min; 105 | min = 0; 106 | value = (value / (max - min)); 107 | if (clamp) { 108 | if (value < 0) { value = 0; } 109 | if (value > 1) { value = 1; } 110 | } 111 | return value; 112 | } 113 | 114 | // public static inline function randomInteger(min:Int, max:Int):Int 115 | // { 116 | // return Std.int(Math.random() * cast(1 + max - min, Float)) + min; 117 | // } 118 | 119 | public static double randomRange(double a, double b) 120 | { 121 | double r = rnd.NextDouble(); 122 | double min = a < b ? a : b; 123 | double max = a < b ? b : a; 124 | double range = max - min; 125 | return r * range + min; 126 | } 127 | 128 | public static List shuffle(Listlist) 129 | { 130 | /* 131 | To shuffle an array a of n elements (indices 0..n-1): 132 | for i from n − 1 downto 1 do 133 | j ← random integer with 0 ≤ j ≤ i 134 | exchange a[j] and a[i] 135 | */ 136 | for (int i=0; i 1) 140 | { 141 | int j = rnd.Next(ii); 142 | var temp = list[j]; 143 | list[j] = list[ii]; 144 | list[ii] = temp; 145 | } 146 | } 147 | return list; 148 | } 149 | 150 | public static int sortAgentAlpha(BasicAgent a, BasicAgent b) 151 | { 152 | return String.Compare(a.className,b.className); 153 | } 154 | 155 | public static int sortAgentId(BasicAgent a, BasicAgent b) 156 | { 157 | if (a.id < b.id) return -1; 158 | if (a.id > b.id) return 1; 159 | return 0; 160 | } 161 | 162 | public static int sortOfferAcending(Offer a, Offer b) 163 | { 164 | if (a.unit_price < b.unit_price) return -1; 165 | if (a.unit_price > b.unit_price) return 1; 166 | return 0; 167 | } 168 | public static int sortOfferDecending(Offer a, Offer b) 169 | { 170 | if (a.unit_price > b.unit_price) return -1; 171 | if (a.unit_price < b.unit_price) return 1; 172 | return 0; 173 | } 174 | 175 | 176 | // public static function sortDecreasingPrice(a:Offer, b:Offer):Int 177 | // { 178 | // //Decreasing means: highest first 179 | // if (a.unit_price < b.unit_price) return 1; 180 | // if (a.unit_price > b.unit_price) return -1; 181 | // return 0; 182 | // } 183 | 184 | // public static function sortIncreasingPrice(a:Offer, b:Offer):Int 185 | // { 186 | // //Increasing means: lowest first 187 | // if (a.unit_price > b.unit_price) return 1; 188 | // if (a.unit_price < b.unit_price) return -1; 189 | // return 0; 190 | // } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/EconomySim.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {0AF795D6-768F-4E1E-957D-79F7F1F09747} 9 | WinExe 10 | Properties 11 | EconomySim 12 | EconomySim 13 | v4.0 14 | Client 15 | 512 16 | publish\ 17 | true 18 | Disk 19 | false 20 | Foreground 21 | 7 22 | Days 23 | false 24 | false 25 | true 26 | 0 27 | 1.0.0.%2a 28 | false 29 | false 30 | true 31 | 32 | 33 | x86 34 | true 35 | full 36 | false 37 | bin\Debug\ 38 | DEBUG;TRACE 39 | prompt 40 | 4 41 | 42 | 43 | x86 44 | pdbonly 45 | true 46 | bin\Release\ 47 | TRACE 48 | prompt 49 | 4 50 | 51 | 52 | 53 | False 54 | ..\..\Json.NET\Newtonsoft.Json.dll 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Form 73 | 74 | 75 | Form1.cs 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | Form1.cs 93 | 94 | 95 | 96 | PublicResXFileCodeGenerator 97 | Resources.Designer.cs 98 | Designer 99 | 100 | 101 | True 102 | Resources.resx 103 | True 104 | 105 | 106 | SettingsSingleFileGenerator 107 | Settings.Designer.cs 108 | 109 | 110 | True 111 | Settings.settings 112 | True 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | False 121 | Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 122 | true 123 | 124 | 125 | False 126 | .NET Framework 3.5 SP1 Client Profile 127 | false 128 | 129 | 130 | False 131 | .NET Framework 3.5 SP1 132 | false 133 | 134 | 135 | False 136 | Windows Installer 3.1 137 | true 138 | 139 | 140 | 141 | 148 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Inventory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | class Inventory 9 | { 10 | public double maxSize = 0; 11 | 12 | //private static var _index:Map; 13 | 14 | private Dictionary_stuff; // key:commodity_id, val:amount, original_cost 15 | private Dictionary_ideal; // ideal counts for each thing 16 | private Dictionary_sizes; // how much space each thing takes up 17 | 18 | 19 | public Inventory() 20 | { 21 | _sizes = new Dictionary(); 22 | _stuff = new Dictionary(); 23 | _ideal = new Dictionary(); 24 | maxSize = 0; 25 | } 26 | 27 | public void fromData(InventoryData data) 28 | { 29 | var sizes = new List(); 30 | var amountsp = new List(); 31 | foreach (string key in data.start.Keys) 32 | { 33 | sizes.Add(key); 34 | amountsp.Add(new Point(data.start[key],0)); 35 | } 36 | setStuff(sizes, amountsp); 37 | sizes = new List(); 38 | var amounts = new List(); 39 | foreach (string key in data.size.Keys) 40 | { 41 | sizes.Add(key); 42 | amounts.Add(data.size[key]); 43 | } 44 | setSizes(sizes, amounts); 45 | sizes = new List(); 46 | amounts = new List(); 47 | foreach (string key in data.ideal.Keys) 48 | { 49 | sizes.Add(key); 50 | amounts.Add(data.ideal[key]); 51 | setIdeal(sizes, amounts); 52 | } 53 | maxSize = data.maxSize; 54 | } 55 | 56 | public Inventory copy() 57 | { 58 | var i = new Inventory(); 59 | var stufff = new List(); 60 | var stuffi = new List(); 61 | var idealf = new List(); 62 | var ideali = new List(); 63 | var sizesf = new List(); 64 | var sizesi = new List(); 65 | foreach (string key in _stuff.Keys) 66 | { 67 | stufff.Add(_stuff[key]); 68 | stuffi.Add(key); 69 | } 70 | foreach (string key in _ideal.Keys) 71 | { 72 | idealf.Add(_ideal[key]); 73 | ideali.Add(key); 74 | } 75 | foreach (string key in _sizes.Keys) 76 | { 77 | sizesf.Add(_sizes[key]); 78 | sizesi.Add(key); 79 | } 80 | i.setStuff(stuffi, stufff); 81 | i.setIdeal(ideali, idealf); 82 | i.setSizes(sizesi, sizesf); 83 | i.maxSize = maxSize; 84 | return i; 85 | } 86 | 87 | public void destroy() 88 | { 89 | _stuff.Clear(); 90 | _ideal.Clear(); 91 | _sizes.Clear(); 92 | _stuff = null; 93 | _ideal = null; 94 | _sizes = null; 95 | } 96 | 97 | /** 98 | * Set amounts of various commodities 99 | * @param stuff_ 100 | * @param amounts_ 101 | */ 102 | 103 | public void setStuff(Liststuff, Listamounts) 104 | { 105 | for (int i=0; iideal, Listamounts) 118 | { 119 | for (int i=0; isizes, Listamounts) 126 | { 127 | for(int i=0; i 0) 204 | { 205 | if (amount.x <= 0) 206 | { 207 | result.x = delta; 208 | result.y = unit_cost; 209 | } 210 | else 211 | { 212 | result.y = (amount.x * amount.y + delta * unit_cost) / (amount.x + delta); 213 | result.x = amount.x + delta; 214 | } 215 | } 216 | else 217 | { 218 | result.x = amount.x + delta; 219 | result.y = amount.y; //just copy from old value? 220 | } 221 | } 222 | else 223 | { 224 | result.x = delta; 225 | result.y = unit_cost; 226 | } 227 | 228 | if (result.x < 0) 229 | { 230 | result.x = 0; 231 | result.y = 0; 232 | } 233 | 234 | _stuff[good] = result; 235 | return result.y; //return current unit cost 236 | } 237 | 238 | /** 239 | * Returns # of units above the desired inventory level, or 0 if @ or below 240 | * @param commodity_ string id of commodity 241 | * @return 242 | */ 243 | 244 | public double surplus(string good) 245 | { 246 | var amt = query(good); 247 | double ideal = 0; 248 | if (_ideal.ContainsKey(good)) 249 | ideal = _ideal[good]; 250 | if (amt > ideal) 251 | { 252 | return (amt - ideal); 253 | } 254 | return 0; 255 | } 256 | 257 | /** 258 | * Returns # of units below the desired inventory level, or 0 if @ or above 259 | * @param commodity_ 260 | * @return 261 | */ 262 | 263 | public double shortage(string good) 264 | { 265 | if (!_stuff.ContainsKey(good)) 266 | { 267 | return 0; 268 | } 269 | var amt = query(good); 270 | double ideal = 0; 271 | if (_ideal.ContainsKey(good)) 272 | ideal = _ideal[good]; 273 | if (amt < ideal) 274 | { 275 | return (ideal - amt); 276 | } 277 | return 0; 278 | } 279 | 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/BasicAgent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | /** 9 | * The most fundamental agent class, and has as little implementation as possible. 10 | * In most cases you should start by extending Agent instead of this. 11 | * @author larsiusprime 12 | */ 13 | 14 | class AgentData { 15 | public string className { get; set;} 16 | public double money; 17 | public InventoryData inventory; 18 | public string logicName; 19 | public Logic logic; 20 | public int? lookBack; 21 | 22 | public AgentData(string className, double money, string logicName) 23 | { 24 | this.className = className; 25 | this.money = money; 26 | this.logicName = logicName; 27 | } 28 | 29 | } 30 | 31 | class Point 32 | { 33 | public double x; 34 | public double y; 35 | public Point(double x,double y) 36 | { 37 | this.x = x; 38 | this.y = y; 39 | } 40 | } 41 | 42 | 43 | class BasicAgent 44 | { 45 | public int id; //unique integer identifier 46 | public string className { get; set; } //string identifier, "famer", "woodcutter", etc. 47 | public double money { get; set; } 48 | public double Space { get { return _inventory.getEmptySpace(); } } 49 | public double nProduct { get; set; } 50 | 51 | //public var moneyLastRound(default, null):double; 52 | //public var profit(get, null):double; 53 | //public var inventorySpace(get, null):double; 54 | //public var inventoryFull(get, null):Bool; 55 | //public var destroyed(default, null):Bool; 56 | public bool destroyed; //dfs stub needed? 57 | public double moneyLastRound; //dfs stub needed? 58 | public double profit; //dfs stub needed? 59 | 60 | public double trackcosts; 61 | 62 | /********PRIVATE************/ 63 | 64 | private Logic _logic; 65 | protected Inventory _inventory; 66 | protected Dictionary> _observedTradingRange; 67 | private double _profit = 0; //profit from last round 68 | private int _lookback = 15; 69 | 70 | 71 | public BasicAgent(int id, AgentData data) 72 | { 73 | this.id = id; 74 | className = data.className; 75 | money = data.money; 76 | _inventory = new Inventory(); 77 | _inventory.fromData(data.inventory); 78 | _logic = data.logic; 79 | 80 | if (data.lookBack == null) 81 | { 82 | _lookback = 15; 83 | } 84 | else 85 | { 86 | _lookback = (int)data.lookBack; 87 | } 88 | 89 | _observedTradingRange = new Dictionary>(); 90 | 91 | trackcosts = 0; 92 | } 93 | 94 | public void destroy() 95 | { 96 | destroyed = true; 97 | _inventory.destroy(); 98 | foreach (string key in _observedTradingRange.Keys) 99 | { 100 | var list = _observedTradingRange[key]; 101 | list.Clear(); 102 | } 103 | _observedTradingRange.Clear(); 104 | _observedTradingRange = null; 105 | _logic = null; 106 | } 107 | 108 | public void init(Market market) 109 | { 110 | var listGoods = market.getGoods_unsafe();//List 111 | foreach (string str in listGoods) 112 | { 113 | var trades = new List(); 114 | 115 | var price = 2;// market.getAverageHistoricalPrice(str, _lookback); 116 | trades.Add(price * 1.0); 117 | trades.Add(price * 3.0); //push two fake trades to generate a range 118 | 119 | //set initial price belief & observed trading range 120 | _observedTradingRange[str]=trades; 121 | } 122 | } 123 | 124 | public void simulate(Market market) 125 | { 126 | _logic.perform(this, market); 127 | } 128 | 129 | public virtual void generateOffers(Market bazaar, string good) 130 | { 131 | //no implemenation -- provide your own in a subclass 132 | } 133 | 134 | public virtual void updatePriceModel(Market bazaar, String act, String good, bool success, double unitPrice = 0) 135 | { 136 | //no implementation -- provide your own in a subclass 137 | } 138 | 139 | public virtual Offer createBid(Market bazaar, String good, double limit) 140 | { 141 | //no implementation -- provide your own in a subclass 142 | return null; 143 | } 144 | 145 | public virtual Offer createAsk(Market bazaar, String commodity_, double limit_) 146 | { 147 | //no implementation -- provide your own in a subclass 148 | return null; 149 | } 150 | 151 | public double queryInventory(String good) 152 | { 153 | return _inventory.query(good); 154 | } 155 | 156 | public void produceInventory(String good, double delta) 157 | { 158 | if (trackcosts < 1) trackcosts = 1; 159 | double curunitcost = _inventory.change(good, delta, trackcosts / delta); 160 | trackcosts = 0; 161 | } 162 | 163 | public void consumeInventory(String good, double delta) 164 | { 165 | if (good == "money") 166 | { 167 | money += delta; 168 | if (delta < 0) 169 | trackcosts += (-delta); 170 | } 171 | else 172 | { 173 | double curunitcost = _inventory.change(good, delta, 0); 174 | if (delta < 0) 175 | trackcosts += (-delta) * curunitcost; 176 | } 177 | } 178 | 179 | public void changeInventory(String good, double delta, double unit_cost) 180 | { 181 | if (good == "money") 182 | { 183 | money += delta; 184 | } 185 | else 186 | { 187 | _inventory.change(good, delta, unit_cost); 188 | } 189 | } 190 | 191 | /********PRIVATE************/ 192 | 193 | 194 | private double get_inventorySpace() 195 | { 196 | return _inventory.getEmptySpace(); 197 | } 198 | 199 | public bool get_inventoryFull() 200 | { 201 | return _inventory.getEmptySpace() == 0; 202 | } 203 | 204 | public double get_profit() 205 | { 206 | return money - moneyLastRound; 207 | } 208 | 209 | protected double determineSaleQuantity(Market bazaar, String commodity_) 210 | { 211 | var mean = bazaar.getAverageHistoricalPrice(commodity_,_lookback); //double 212 | var trading_range = observeTradingRange(commodity_,10);//point 213 | if (trading_range != null && mean>0) 214 | { 215 | var favorability= Quick.positionInRange(mean, trading_range.x, trading_range.y);//double 216 | //position_in_range: high means price is at a high point 217 | 218 | double amount_to_sell = Math.Round(favorability * _inventory.surplus(commodity_)); //double 219 | amount_to_sell = _inventory.query(commodity_); 220 | if (amount_to_sell < 1) 221 | { 222 | amount_to_sell = 1; 223 | } 224 | return amount_to_sell; 225 | } 226 | return 0; 227 | } 228 | 229 | protected double determinePurchaseQuantity(Market bazaar, String commodity_) 230 | { 231 | var mean = bazaar.getAverageHistoricalPrice(commodity_,_lookback);//double 232 | var trading_range = observeTradingRange(commodity_,10); //Point 233 | if (trading_range != null) 234 | { 235 | var favorability = Quick.positionInRange(mean, trading_range.x, trading_range.y);//double 236 | favorability = 1 - favorability; 237 | //do 1 - favorability to see how close we are to the low end 238 | 239 | double amount_to_buy = Math.Round(favorability * _inventory.shortage(commodity_));//double 240 | if (amount_to_buy < 1) 241 | { 242 | amount_to_buy = 1; 243 | } 244 | return amount_to_buy; 245 | } 246 | return 0; 247 | } 248 | 249 | private Point observeTradingRange(String good, int window) 250 | { 251 | var a = _observedTradingRange[good]; //List 252 | var pt = new Point(Quick.minArr(a,window), Quick.maxArr(a,window)); 253 | return pt; 254 | } 255 | } 256 | 257 | } 258 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/MyEconomy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | using System.Reflection; 7 | using Newtonsoft.Json; 8 | 9 | namespace EconomySim 10 | { 11 | class DoranAndParberryEconomy : Economy 12 | { 13 | 14 | public DoranAndParberryEconomy() 15 | { 16 | var market = new Market("default",this); 17 | 18 | MarketData data = GetMarketData(); 19 | market.init(data); // market.init(MarketData.fromJSON(Json.parse(Assets.getText("assets/settings.json")), getAgent)); 20 | addMarket(market); 21 | } 22 | 23 | private MarketData GetMarketData() 24 | { 25 | List goods = new List(); 26 | ListagentTypes = new List(); 27 | List agents = new List(); 28 | 29 | goods.Add(new Good("food", 0.5)); 30 | goods.Add(new Good("wood", 1.0)); 31 | goods.Add(new Good("ore", 1.0)); 32 | goods.Add(new Good("metal", 1.0)); 33 | goods.Add(new Good("tools", 1.0)); 34 | goods.Add(new Good("work", 0.1)); 35 | 36 | agentTypes.Add(new AgentData("farmer",100,"farmer")); 37 | agentTypes.Add(new AgentData("miner",100,"miner")); 38 | agentTypes.Add(new AgentData("refiner",100,"refiner")); 39 | agentTypes.Add(new AgentData("woodcutter",100,"woodcutter")); 40 | agentTypes.Add(new AgentData("blacksmith", 100, "blacksmith")); 41 | agentTypes.Add(new AgentData("worker", 10, "worker")); 42 | 43 | InventoryData ii; 44 | ii = new InventoryData(20, //farmer 45 | new Dictionary{{"food",0},{"tools",1},{"wood",3},{"work",3}}, 46 | new Dictionary{{"food",1},{"tools",1},{"wood",0},{"work",0}}, 47 | null 48 | ); 49 | agentTypes[0].inventory = ii; 50 | ii = new InventoryData(20, //miner 51 | new Dictionary { { "food", 3 }, { "tools", 1 }, { "ore", 0 } }, 52 | new Dictionary { { "food", 1 }, { "tools", 1 }, { "ore", 0 } }, 53 | null 54 | ); 55 | agentTypes[1].inventory = ii; 56 | ii = new InventoryData(20, //refiner 57 | new Dictionary { { "food", 3 }, { "tools", 1 }, { "ore", 5 } }, 58 | new Dictionary { { "food", 1 }, { "tools", 1 }, { "ore", 0 } }, 59 | null 60 | ); 61 | agentTypes[2].inventory = ii; 62 | ii = new InventoryData(20, //woodcutter 63 | new Dictionary { { "food", 3 }, { "tools", 1 }, { "wood", 0 } }, 64 | new Dictionary { { "food", 1 }, { "tools", 1 }, { "wood", 0 } }, 65 | null 66 | ); 67 | agentTypes[3].inventory = ii; 68 | ii = new InventoryData(20, //blacksmith 69 | new Dictionary { { "food", 3 }, { "tools", 1 }, { "metal", 5 }, { "ore", 0 } }, 70 | new Dictionary { { "food", 1 }, { "tools", 0 }, { "metal", 0 }, { "ore", 0 } }, 71 | null 72 | ); 73 | agentTypes[4].inventory = ii; 74 | ii = new InventoryData(20, //worker 75 | new Dictionary { { "food", 3 } }, 76 | new Dictionary { { "food", 1 } }, 77 | null 78 | ); 79 | agentTypes[5].inventory = ii; 80 | 81 | 82 | int idc = 0; 83 | for (int iagent = 0; iagent < agentTypes.Count; iagent++) 84 | { 85 | for (int i = 0; i < 5; i++) 86 | { 87 | agents.Add(getAgent(agentTypes[iagent])); 88 | agents[agents.Count - 1].id = idc++; 89 | } 90 | } 91 | 92 | 93 | MarketData data = new MarketData(goods, agentTypes, agents); 94 | 95 | return data; 96 | 97 | //var assembly = Assembly.GetExecutingAssembly(); 98 | //var resourceName = "EconomySim.settings.txt"; 99 | 100 | //string[] names = assembly.GetManifestResourceNames(); 101 | 102 | 103 | //using (Stream stream = assembly.GetManifestResourceStream(resourceName)) 104 | //using (StreamReader reader = new StreamReader(stream)) 105 | //{ 106 | // string result = reader.ReadToEnd(); 107 | // MarketData data = JsonConvert.DeserializeObject(result); 108 | // return data; 109 | //} 110 | //return null; 111 | } 112 | 113 | 114 | public override void signalBankrupt(Market m, BasicAgent a) 115 | { 116 | replaceAgent(m, a); 117 | } 118 | 119 | private void replaceAgent(Market market, BasicAgent agent) 120 | { 121 | var bestClass = market.getMostProfitableAgentClass(); 122 | 123 | //Special case to deal with very high demand-to-supply ratios 124 | //This will make them favor entering an underserved market over 125 | //Just picking the most profitable class 126 | var bestGood = market.getHottestGood(); 127 | 128 | if (bestGood != "") 129 | { 130 | var bestGoodClass = getAgentClassThatMakesMost(bestGood); 131 | if (bestGoodClass != "") 132 | { 133 | bestClass = bestGoodClass; 134 | } 135 | } 136 | 137 | var newAgent = getAgent(market.getAgentClass(bestClass)); 138 | market.replaceAgent(agent, newAgent); 139 | } 140 | 141 | 142 | /** 143 | * Get the average amount of a given good that a given agent class has 144 | * @param className 145 | * @param good 146 | * @return 147 | */ 148 | /* 149 | public function getAgentClassAverageInventory(className:String, good:String):Float 150 | { 151 | var list = _agents.filter(function(a:BasicAgent):Bool { return a.className == className; } ); 152 | var amount:Float = 0; 153 | for (agent in list) 154 | { 155 | amount += agent.queryInventory(good); 156 | } 157 | amount /= list.length; 158 | return amount; 159 | } 160 | */ 161 | 162 | /** 163 | * Find the agent class that produces the most of a given good 164 | * @param good 165 | * @return 166 | */ 167 | public String getAgentClassThatMakesMost(String good) 168 | { 169 | string res = ""; 170 | if (good == "food" ) {res = "farmer"; } 171 | else if (good == "wood") { res = "woodcutter"; } 172 | else if (good == "ore") { res = "miner"; } 173 | else if (good == "metal") {res = "refiner"; } 174 | else if (good == "tools") { res = "blacksmith"; } 175 | else if (good == "work") { res = "worker"; } 176 | return res; 177 | } 178 | 179 | /** 180 | * Find the agent class that has the most of a given good 181 | * @param good 182 | * @return 183 | */ 184 | /* 185 | public function getAgentClassWithMost(good:String):String 186 | { 187 | var amount:Float = 0; 188 | var bestAmount:Float = 0; 189 | var bestClass:String = ""; 190 | for (key in _mapAgents.keys()) 191 | { 192 | amount = getAverageInventory(key, good); 193 | if (amount > bestAmount) 194 | { 195 | bestAmount = amount; 196 | bestClass = key; 197 | } 198 | } 199 | return bestClass; 200 | } 201 | */ 202 | 203 | //private BasicAgent getAgentScript(AgentData data) 204 | //{ 205 | // data.logic = new LogicScript(data.logicName+".hs"); 206 | // return new Agent(0, data); 207 | //} 208 | 209 | private BasicAgent getAgent(AgentData data) 210 | { 211 | data.logic = getLogic(data.logicName); 212 | return new Agent(0, data); 213 | } 214 | 215 | private Logic getLogic(String str) 216 | { 217 | switch (str) 218 | { 219 | case "blacksmith": return new LogicBlacksmith(); 220 | case "farmer": return new LogicFarmer(); 221 | case "miner": return new LogicMiner(); 222 | case "refiner": return new LogicRefiner(); 223 | case "woodcutter": return new LogicWoodcutter(); 224 | case "worker": return new LogicWorker(); 225 | } 226 | return null; 227 | } 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Logic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace EconomySim 7 | { 8 | class Logic 9 | { 10 | private bool init = false; 11 | 12 | //public function new(?data:Dynamic) 13 | //{ 14 | // //no implemenation -- provide your own in a subclass 15 | //} 16 | 17 | /** 18 | * Perform this logic on the given agent 19 | * @param agent 20 | */ 21 | 22 | public virtual void perform(BasicAgent agent, Market market) 23 | { 24 | //no implemenation -- provide your own in a subclass 25 | } 26 | 27 | protected void _produce(BasicAgent agent, String commodity, double amount, double chance = 1.0) 28 | { 29 | if (chance >= 1.0 || Quick.rnd.NextDouble() < chance) 30 | { 31 | agent.produceInventory(commodity, amount); 32 | } 33 | } 34 | 35 | protected void _consume(BasicAgent agent, String commodity, double amount, double chance = 1.0) 36 | { 37 | if (chance >= 1.0 || Quick.rnd.NextDouble() < chance) 38 | { 39 | //if (commodity == "money") 40 | //{ 41 | // agent.changeInventory(comm 42 | // agent.money -= amount; 43 | //} 44 | //else 45 | //{ 46 | agent.consumeInventory(commodity, -amount); 47 | //} 48 | } 49 | } 50 | 51 | } 52 | 53 | class LogicBlacksmith : Logic 54 | { 55 | override public void perform(BasicAgent agent, Market market) 56 | { 57 | var food = agent.queryInventory("food"); 58 | var metal = agent.queryInventory("metal"); 59 | var tools = agent.queryInventory("tools"); 60 | var need_tools = tools < 4; 61 | 62 | var has_food = food >= 1; 63 | var has_metal = metal >= 1; 64 | 65 | //_consume(agent, "money", 0.5);//cost of living/business 66 | _consume(agent, "food", 1);//cost of living 67 | 68 | if (has_food && has_metal & need_tools) 69 | { 70 | //convert all metal into tools 71 | _consume(agent, "metal", metal); 72 | _produce(agent, "tools", metal); 73 | } 74 | else 75 | { 76 | //fined $2 for being idle 77 | //_consume(agent, "money", 2); 78 | if (!has_food && agent.get_inventoryFull()) 79 | { 80 | //make_room_for(agent, "food", 2); stub todo needed? 81 | } 82 | } 83 | } 84 | } 85 | 86 | class LogicFarmer : Logic 87 | { 88 | override public void perform(BasicAgent agent, Market market) 89 | { 90 | var wood = agent.queryInventory("wood"); 91 | var tools = agent.queryInventory("tools"); 92 | var food = agent.queryInventory("food"); 93 | var need_food = food < 10; 94 | var work = agent.queryInventory("work"); 95 | 96 | var has_wood = wood >= 1; 97 | var has_tools = tools >= 1; 98 | var has_work = work >= 1; 99 | 100 | //_consume(agent, "money", 0.5);//cost of living/business 101 | 102 | if (need_food) 103 | { 104 | if (has_wood && has_tools && has_work) 105 | { 106 | //produce 4 food, consume 1 wood, break tools with 10% chance 107 | _consume(agent, "wood", 1, 1); 108 | _consume(agent, "tools", 1, 0.1); 109 | _consume(agent, "work", 1, 1); 110 | _produce(agent, "food", 6, 1); 111 | } 112 | else if (has_wood && !has_tools && has_work) 113 | { 114 | //produce 2 food, consume 1 wood 115 | _consume(agent, "wood", 1, 1); 116 | _consume(agent, "work", 1, 1); 117 | _produce(agent, "food", 3, 1); 118 | } 119 | else //no wood 120 | { 121 | //produce 1 food, 122 | _produce(agent, "food", 1, 1); 123 | } 124 | } 125 | else 126 | { 127 | //fined $2 for being idle 128 | //_consume(agent, "money", 2); 129 | } 130 | } 131 | } 132 | 133 | 134 | class LogicMiner : Logic 135 | { 136 | override public void perform(BasicAgent agent, Market market) 137 | { 138 | var food = agent.queryInventory("food"); 139 | var tools = agent.queryInventory("tools"); 140 | var ore = agent.queryInventory("ore"); 141 | var need_ore = ore < 4; 142 | 143 | var has_food = food >= 1; 144 | var has_tools = tools >= 1; 145 | 146 | //_consume(agent, "money", 0.5);//cost of living/business 147 | _consume(agent, "food", 1);//cost of living 148 | 149 | if (has_food && need_ore) 150 | { 151 | if (has_tools) 152 | { 153 | //produce 4 ore, consume 1 food, break tools with 10% chance 154 | _consume(agent, "food", 1); 155 | _consume(agent, "tools", 1, 0.1); 156 | _produce(agent, "ore", 4); 157 | } 158 | else 159 | { 160 | //produce 2 ore, consume 1 food 161 | _consume(agent, "food", 1); 162 | _produce(agent, "ore", 2); 163 | } 164 | } 165 | else 166 | { 167 | //fined $2 for being idle 168 | //_consume(agent, "money", 2); 169 | if (!has_food && agent.get_inventoryFull()) 170 | { 171 | //make_room_for(agent,"food",2); 172 | } 173 | } 174 | } 175 | } 176 | 177 | class LogicRefiner : Logic 178 | { 179 | override public void perform(BasicAgent agent, Market market) 180 | { 181 | var food = agent.queryInventory("food"); 182 | var tools = agent.queryInventory("tools"); 183 | var ore = agent.queryInventory("ore"); 184 | if (ore > 4) ore = 4; 185 | var metal = agent.queryInventory("metal"); 186 | var need_metal = metal < 4; 187 | 188 | var has_food = food >= 1; 189 | var has_tools = tools >= 1; 190 | var has_ore = ore >= 1; 191 | 192 | //_consume(agent, "money", 0.5);//cost of living/business 193 | _consume(agent, "food", 1);//cost of living 194 | 195 | if (has_food && has_ore && need_metal) 196 | { 197 | if (has_tools) 198 | { 199 | //convert all ore into metal, consume 1 food, break tools with 10% chance 200 | _consume(agent, "ore", ore); 201 | _consume(agent, "food", 1); 202 | _consume(agent, "tools", 1, 0.1); 203 | _produce(agent, "metal", ore); 204 | } 205 | else 206 | { 207 | //convert up to 2 ore into metal, consume 1 food 208 | var max = agent.queryInventory("ore"); 209 | if (max > 2) { max = 2; } 210 | _consume(agent, "ore", max); 211 | _consume(agent, "food", 1); 212 | _produce(agent, "metal", max); 213 | } 214 | } 215 | else 216 | { 217 | //fined $2 for being idle 218 | //_consume(agent, "money", 2); 219 | if (!has_food && agent.get_inventoryFull()) 220 | { 221 | //make_room_for(agent, "food", 2); 222 | } 223 | } 224 | } 225 | } 226 | 227 | class LogicWoodcutter : Logic 228 | { 229 | override public void perform(BasicAgent agent, Market market) 230 | { 231 | var food = agent.queryInventory("food"); 232 | var tools = agent.queryInventory("tools"); 233 | var wood = agent.queryInventory("wood"); 234 | var need_wood = wood < 4; 235 | 236 | var has_food = food >= 1; 237 | var has_tools = tools >= 1; 238 | 239 | //_consume(agent, "money", 0.5);//cost of living/business 240 | _consume(agent, "food", 1);//cost of living 241 | 242 | if (has_food && need_wood) 243 | { 244 | if (has_tools) 245 | { 246 | //produce 2 wood, consume 1 food, break tools with 10% chance 247 | _consume(agent, "food", 1); 248 | _consume(agent, "tools", 1, 0.1); 249 | _produce(agent, "wood", 2); 250 | } 251 | else 252 | { 253 | //produce 1 wood, consume 1 food 254 | _consume(agent, "food", 1); 255 | _produce(agent, "wood", 1); 256 | } 257 | } 258 | else 259 | { 260 | //fined $2 for being idle 261 | //_consume(agent, "money", 2); 262 | if (!has_food && agent.get_inventoryFull()) 263 | { 264 | //make_room_for(agent, "food", 2); 265 | } 266 | } 267 | } 268 | } 269 | 270 | class LogicWorker : Logic 271 | { 272 | override public void perform(BasicAgent agent, Market market) 273 | { 274 | var food = agent.queryInventory("food"); 275 | var has_food = food >= 1; 276 | var work = agent.queryInventory("work"); 277 | var need_work = work < 1; 278 | 279 | _consume(agent, "food", 1); 280 | //_consume(agent, "money", 0.5);//cost of living/business 281 | 282 | if (need_work) 283 | { 284 | _produce(agent, "work", 1); 285 | } 286 | } 287 | } 288 | 289 | 290 | } 291 | -------------------------------------------------------------------------------- /EconomySim/EconomySim/Market.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Linq; 7 | 8 | namespace EconomySim 9 | { 10 | interface ISignalBankrupt 11 | { 12 | void signalBankrupt(Market m, BasicAgent agent); 13 | } 14 | 15 | class Market 16 | { 17 | public String name; 18 | 19 | /**Logs information about all economic activity in this market**/ 20 | public History history; 21 | 22 | /**Signal fired when an agent's money reaches 0 or below**/ 23 | public ISignalBankrupt signalBankrupt; 24 | 25 | 26 | /********PRIVATE*********/ 27 | 28 | private int _roundNum = 0; 29 | 30 | private List _goodTypes; //list of string ids for all the legal commodities 31 | public BindingList _agents; 32 | public TradeBook _book; 33 | private Dictionary _mapAgents; 34 | private Dictionary _mapGoods; 35 | 36 | 37 | public Market(string name, ISignalBankrupt isb) 38 | { 39 | this.name = name; 40 | 41 | history = new History(); 42 | _book = new TradeBook(); 43 | _goodTypes = new List(); 44 | _agents = new BindingList(); 45 | _mapGoods = new Dictionary(); 46 | _mapAgents = new Dictionary(); 47 | 48 | signalBankrupt = isb;//new TypedSignalBasicAgent->Void>(); 49 | } 50 | 51 | public void init(MarketData data) 52 | { 53 | fromData(data); 54 | } 55 | 56 | public int numTypesOfGood() 57 | { 58 | return _goodTypes.Count; 59 | } 60 | 61 | public int numAgents() 62 | { 63 | return _agents.Count; 64 | } 65 | 66 | public void replaceAgent(BasicAgent oldAgent, BasicAgent newAgent) 67 | { 68 | newAgent.id = oldAgent.id; 69 | _agents[oldAgent.id] = newAgent; 70 | oldAgent.destroy(); 71 | newAgent.init(this); 72 | } 73 | 74 | //@:access(bazaarbot.agent.BasicAgent) //dfs stub ???? 75 | public void simulate(int rounds) 76 | { 77 | for (int round=0; round(); 95 | foreach (var agent in _agents) 96 | { 97 | if (agent.money <= 0) del.Add(agent); 98 | } 99 | while (del.Count > 0) 100 | { 101 | signalBankrupt.signalBankrupt(this, del[0]); //signalBankrupt.dispatch(this, agent); 102 | del.RemoveAt(0); 103 | } 104 | _roundNum++; 105 | } 106 | } 107 | 108 | public void ask(Offer offer) 109 | { 110 | _book.ask(offer); 111 | } 112 | 113 | public void bid(Offer offer) 114 | { 115 | _book.bid(offer); 116 | } 117 | 118 | /** 119 | * Returns the historical mean price of the given commodity over the last X rounds 120 | * @param commodity_ string id of commodity 121 | * @param range number of rounds to look back 122 | * @return 123 | */ 124 | 125 | public double getAverageHistoricalPrice(String good, int range) 126 | { 127 | return history.prices.average(good, range); 128 | } 129 | 130 | /** 131 | * Get the good with the highest demand/supply ratio over time 132 | * @param minimum the minimum demand/supply ratio to consider an opportunity 133 | * @param range number of rounds to look back 134 | * @return 135 | */ 136 | 137 | public String getHottestGood(double minimum = 1.5, int range = 10) 138 | { 139 | string best_market = ""; 140 | double best_ratio = -99999;// Math.NEGATIVE_INFINITY; 141 | foreach (var good in _goodTypes) 142 | { 143 | var asks = history.asks.average(good, range); 144 | var bids = history.bids.average(good, range); 145 | 146 | double ratio = 0; 147 | if (asks == 0 && bids > 0) 148 | { 149 | //If there are NONE on the market we artificially create a fake supply of 1/2 a unit to avoid the 150 | //crazy bias that "infinite" demand can cause... 151 | 152 | asks = 0.5; 153 | } 154 | 155 | ratio = bids / asks; 156 | 157 | if (ratio > minimum && ratio > best_ratio) 158 | { 159 | best_ratio = ratio; 160 | best_market = good; 161 | } 162 | } 163 | return best_market; 164 | } 165 | 166 | /** 167 | * Returns the good that has the lowest average price over the given range of time 168 | * @param range how many rounds to look back 169 | * @param exclude goods to exclude 170 | * @return 171 | */ 172 | 173 | public String getCheapestGood(int range, List exclude = null) 174 | { 175 | double best_price = -9999999;// Math.POSITIVE_INFINITY; 176 | string best_good = ""; 177 | foreach (var g in _goodTypes) 178 | { 179 | if (exclude == null || !exclude.Contains(g)) 180 | { 181 | double price = history.prices.average(g, range); 182 | if (price < best_price) 183 | { 184 | best_price = price; 185 | best_good = g; 186 | } 187 | } 188 | } 189 | return best_good; 190 | } 191 | 192 | /** 193 | * Returns the good that has the highest average price over the given range of time 194 | * @param range how many rounds to look back 195 | * @param exclude goods to exclude 196 | * @return 197 | */ 198 | 199 | public String getDearestGood(int range, List exclude= null) 200 | { 201 | double best_price = 0; 202 | String best_good = ""; 203 | foreach (var g in _goodTypes) 204 | { 205 | if (exclude == null || !exclude.Contains(g)) 206 | { 207 | var price = history.prices.average(g, range); 208 | if (price > best_price) 209 | { 210 | best_price = price; 211 | best_good = g; 212 | } 213 | } 214 | } 215 | return best_good; 216 | } 217 | 218 | /** 219 | * 220 | * @param range 221 | * @return 222 | */ 223 | public String getMostProfitableAgentClass(int range= 10) 224 | { 225 | double best = -999999;// Math.NEGATIVE_INFINITY; 226 | String bestClass=""; 227 | foreach (var className in _mapAgents.Keys) 228 | { 229 | double val = history.profit.average(className, range); 230 | if (val > best) 231 | { 232 | bestClass = className; 233 | best = val; 234 | } 235 | } 236 | return bestClass; 237 | } 238 | 239 | public AgentData getAgentClass(String className) 240 | { 241 | return _mapAgents[className]; 242 | } 243 | 244 | public List getAgentClassNames() 245 | { 246 | var agentData = new List (); 247 | foreach (var key in _mapAgents.Keys) 248 | { 249 | agentData.Add(key); 250 | } 251 | return agentData; 252 | } 253 | 254 | public List getGoods() 255 | { 256 | return new List(_goodTypes); 257 | } 258 | 259 | public List getGoods_unsafe() 260 | { 261 | return _goodTypes; 262 | } 263 | 264 | public Good getGoodEntry(String str) 265 | { 266 | if (_mapGoods.ContainsKey(str)) 267 | { 268 | return _mapGoods[str].copy(); 269 | } 270 | return null; 271 | } 272 | 273 | /********REPORT**********/ 274 | public MarketReport get_marketReport(int rounds) 275 | { 276 | var mr = new MarketReport(); 277 | mr.strListGood = "Commodities\n\n"; 278 | mr.strListGoodPrices = "Price\n\n"; 279 | mr.strListGoodTrades = "Trades\n\n"; 280 | mr.strListGoodAsks = "Supply\n\n"; 281 | mr.strListGoodBids = "Demand\n\n"; 282 | 283 | mr.strListAgent = "Classes\n\n"; 284 | mr.strListAgentCount = "Count\n\n"; 285 | mr.strListAgentProfit = "Profit\n\n"; 286 | mr.strListAgentMoney = "Money\n\n"; 287 | 288 | mr.arrStrListInventory = new List(); 289 | 290 | foreach (var commodity in _goodTypes) 291 | { 292 | mr.strListGood += commodity + "\n"; 293 | 294 | var price = history.prices.average(commodity, rounds); 295 | mr.strListGoodPrices += Quick.numStr(price, 2) + "\n"; 296 | 297 | var asks = history.asks.average(commodity, rounds); 298 | mr.strListGoodAsks += (int)(asks) + "\n"; 299 | 300 | var bids = history.bids.average(commodity, rounds); 301 | mr.strListGoodBids += (int)(bids) + "\n"; 302 | 303 | var trades = history.trades.average(commodity, rounds); 304 | mr.strListGoodTrades += (int)(trades) + "\n"; 305 | 306 | mr.arrStrListInventory.Add(commodity + "\n\n"); 307 | } 308 | foreach (var key in _mapAgents.Keys) 309 | { 310 | var inventory = new List(); 311 | foreach (var str in _goodTypes) 312 | { 313 | inventory.Add(0); 314 | } 315 | mr.strListAgent += key + "\n"; 316 | var profit = history.profit.average(key, rounds); 317 | mr.strListAgentProfit += Quick.numStr(profit, 2) + "\n"; 318 | 319 | double test_profit = 0; 320 | var list = _agents; //var list = _agents.filter(function(a:BasicAgent):Bool { return a.className == key; } ); dfs stub wtf 321 | int count = 0; 322 | double money = 0; 323 | 324 | foreach (var a in list) 325 | { 326 | if (a.className==key) 327 | { 328 | count++; 329 | money += a.money; 330 | for (int lic=0; lic<_goodTypes.Count; lic++) 331 | { 332 | inventory[lic] += a.queryInventory(_goodTypes[lic]); 333 | } 334 | } 335 | } 336 | 337 | money /= count; 338 | for (int lic =0; lic<_goodTypes.Count; lic++) 339 | { 340 | inventory[lic] /= count; 341 | mr.arrStrListInventory[lic] += Quick.numStr(inventory[lic],1) + "\n"; 342 | } 343 | 344 | mr.strListAgentCount += Quick.numStr(count, 0) + "\n"; 345 | mr.strListAgentMoney += Quick.numStr(money, 0) + "\n"; 346 | } 347 | return mr; 348 | } 349 | 350 | /********PRIVATE*********/ 351 | 352 | private void fromData(MarketData data) 353 | { 354 | //Create commodity index 355 | foreach (var g in data.goods) 356 | { 357 | _goodTypes.Add(g.id); 358 | _mapGoods[g.id] = new Good(g.id, g.size); 359 | 360 | double v = 1.0; 361 | if (g.id == "metal") v = 2.0; 362 | if (g.id == "tools") v = 3.0; 363 | 364 | history.register(g.id); 365 | history.prices.add(g.id, v); //start the bidding at $1! 366 | history.asks.add(g.id, v); //start history charts with 1 fake buy/sell bid 367 | history.bids.add(g.id, v); 368 | history.trades.add(g.id, v); 369 | 370 | _book.register(g.id); 371 | } 372 | 373 | _mapAgents = new Dictionary(); 374 | 375 | foreach (var aData in data.agentTypes) 376 | { 377 | _mapAgents[aData.className] = aData; 378 | history.profit.register(aData.className); 379 | } 380 | 381 | //Make the agent list 382 | _agents = new BindingList(); 383 | 384 | var agentIndex = 0; 385 | foreach (var agent in data.agents) 386 | { 387 | agent.id = agentIndex; 388 | agent.init(this); 389 | _agents.Add(agent); 390 | agentIndex++; 391 | } 392 | 393 | } 394 | 395 | private void resolveOffers(String good= "") 396 | { 397 | var bids = _book.bids[good]; 398 | var asks = _book.asks[good]; 399 | 400 | bids = Quick.shuffle(bids); 401 | asks = Quick.shuffle(asks); 402 | 403 | //bids.Sort(Quick.sortOfferDecending); //highest buying price first 404 | asks.Sort(Quick.sortOfferAcending); //lowest selling price first 405 | 406 | int successfulTrades = 0; //# of successful trades this round 407 | double moneyTraded = 0; //amount of money traded this round 408 | double unitsTraded = 0; //amount of goods traded this round 409 | double avgPrice = 0; //avg clearing price this round 410 | double numAsks = 0; 411 | double numBids = 0; 412 | 413 | int failsafe = 0; 414 | 415 | for (int i=0; i 0 && asks.Count > 0) //while both books are non-empty 427 | { 428 | var buyer = bids[0]; 429 | var seller = asks[0]; 430 | 431 | var quantity_traded = (double)Math.Min(seller.units, buyer.units); 432 | var clearing_price = seller.unit_price; //Quick.avgf(seller.unit_price, buyer.unit_price); 433 | 434 | //if (buyer.unit_price < seller.unit_price) 435 | // break; 436 | 437 | if (quantity_traded > 0) 438 | { 439 | //transfer the goods for the agreed price 440 | seller.units -= quantity_traded; 441 | buyer.units -= quantity_traded; 442 | 443 | transferGood(good, quantity_traded, seller.agent_id, buyer.agent_id, clearing_price); 444 | transferMoney(quantity_traded * clearing_price, seller.agent_id, buyer.agent_id); 445 | 446 | //update agent price beliefs based on successful transaction 447 | var buyer_a = _agents[buyer.agent_id]; 448 | var seller_a = _agents[seller.agent_id]; 449 | buyer_a.updatePriceModel(this, "buy", good, true, clearing_price); 450 | seller_a.updatePriceModel(this, "sell", good, true, clearing_price); 451 | 452 | //log the stats 453 | moneyTraded += (quantity_traded * clearing_price); 454 | unitsTraded += quantity_traded; 455 | successfulTrades++; 456 | } 457 | 458 | if (seller.units == 0) //seller is out of offered good 459 | { 460 | asks.RemoveAt(0); //.splice(0, 1); //remove ask 461 | failsafe = 0; 462 | } 463 | if (buyer.units == 0) //buyer is out of offered good 464 | { 465 | bids.RemoveAt(0);//.splice(0, 1); //remove bid 466 | failsafe = 0; 467 | } 468 | 469 | failsafe++; 470 | 471 | if (failsafe > 1000) 472 | { 473 | Console.WriteLine("BOINK!"); 474 | } 475 | } 476 | 477 | //reject all remaining offers, 478 | //update price belief models based on unsuccessful transaction 479 | while (bids.Count > 0) 480 | { 481 | var buyer = bids[0]; 482 | var buyer_a = _agents[buyer.agent_id]; 483 | buyer_a.updatePriceModel(this,"buy",good, false); 484 | bids.RemoveAt(0);//.splice(0, 1); 485 | } 486 | while (asks.Count > 0) 487 | { 488 | var seller = asks[0]; 489 | var seller_a = _agents[seller.agent_id]; 490 | seller_a.updatePriceModel(this,"sell",good, false); 491 | asks.RemoveAt(0);// splice(0, 1); 492 | } 493 | 494 | //update history 495 | 496 | history.asks.add(good, numAsks); 497 | history.bids.add(good, numBids); 498 | history.trades.add(good, unitsTraded); 499 | 500 | if (unitsTraded > 0) 501 | { 502 | avgPrice = moneyTraded / (double)unitsTraded; 503 | history.prices.add(good, avgPrice); 504 | } 505 | else 506 | { 507 | //special case: none were traded this round, use last round's average price 508 | history.prices.add(good, history.prices.average(good, 1)); 509 | avgPrice = history.prices.average(good,1); 510 | } 511 | 512 | List ag = _agents.ToList(); 513 | ag.Sort(Quick.sortAgentAlpha); 514 | 515 | String curr_class = ""; 516 | String last_class = ""; 517 | List list = null; 518 | double avg_profit = 0; 519 | 520 | for (int i=0;i(); //make a new list 532 | last_class = curr_class; 533 | } 534 | list.Add(a.get_profit()); //push profit onto list 535 | } 536 | 537 | //add the last class too 538 | history.profit.add(last_class, Quick.listAvgf(list)); 539 | 540 | //sort by id so everything works again 541 | //_agents.Sort(Quick.sortAgentId); 542 | 543 | } 544 | 545 | private void transferGood(String good, double units, int seller_id, int buyer_id, double clearing_price) 546 | { 547 | var seller = _agents[seller_id]; 548 | var buyer = _agents[buyer_id]; 549 | seller.changeInventory(good, -units, 0); 550 | buyer.changeInventory(good, units, clearing_price); 551 | } 552 | 553 | private void transferMoney(double amount, int seller_id, int buyer_id) 554 | { 555 | var seller = _agents[seller_id]; 556 | var buyer = _agents[buyer_id]; 557 | seller.money += amount; 558 | buyer.money -= amount; 559 | } 560 | 561 | } 562 | } 563 | --------------------------------------------------------------------------------