/* Idle Theory - Economic Model Derived from ITecon6.java using JDK1.1.6 Chris Davis - 16 Dec 2008 Item.java (Idle Theory Economic Model) ========= Copied from ITecon6.java. Item.html enlarges applet to 500 x 500 pixels. Non-functioning slider control removed. New textarea for applet data. Twin rolling graph displays for different data streams, now scaleable. Editable main text area. Editable variables in the text area write into a Stringbuffer which is written to textarea, and read back what is written. When edits (doubleclicked) are noticed by textlistener, they are copied to the Stringbuffer, where edited fields are read back into variables. This hasn't been entirely debugged: sometimes textarea fields get messed up. TOOLx parameters in html call to allocate men their tools. This threw up a few bugs, principal among which was the ordering of burnMoney() calls. Seems to now be fixed. DEBUG parameter added to switch printlns on/off. productiontargets are set set as multiples of maximum sale + use thruputs over 10-day periods. Needs better initialisation? Shortages flagged as bits in int variable for display. Working OK. $ production targets set like other tools. $s in sales counted as thruputs. Textarea formatting and decimal points display modified. Editing OK It is now possible to assign the content of textarea rows using an alphabetic system. Tool purchasing broken down into smaller routines. tryToBuyTool() added. This is also called by burnSmallAmountsMoney(), which had one bug in it, - a = smallAmountMoney / moneyrequ; should be smallAmountMoney / price; - and may still have another (is amoney the right variable to reduce?). New burnMoney() routine has each man taking turns to buy a little labour. Arbitrary $ spending > $6. No damping, but produces fuzzy equality. Damped production targets instead. Modified setPurchaseTargets() to modulate tool-0 purchase targets according to how much cash available. The result is that just prices produce perfect equality with all tools as $s. Probably a bit of a fluke. New damped() method generalizes damping. $ supply oscillations depend on who makes $. 2 Jan 2009 Simple floating prices model. Prices go up if sale thruput > 0, else down. It's important to have prices not exactly the same if competition is to pull down prices. $ production targets doubled to ensure better liquidity, because some traders had $ shortages. Seemed to fix the problem. The floating price model (only tool prices are floated, not labour prices) works rather well. With no competition, prices rise to just below values. With competition they fall to just above costs. In a 7-man system with 4 tools, 3 of them made competitively (not the $), an approximate equality results (this is true of all $s, with tool-1 as $ the worst). 5 jan 2009 The 2 Jan saved code doesn't actually behave like it says it does. It was not actually the 1 jan code, but something from the next day, partly edited and not debugged. Competition doesn't actually bring prices down to costs. Instead prices keep on rising. Edits from 2-5 jan accidentally lost (but that code had the same problem anyway). 6 Jan 0.5 rather than 0.6 in labour purchase targets non-random price differentials for repeatability. 8 jan 9-man system with 3 producers of each tool. $ producer periodically hired as labour, cutting $ production. Mystery 1: Labour prices don't keep falling, but eventually stabilise. Mystery 2: If $ producer's labour price is fixed, other labour prices stay at same level. 9 Jan $ target stock levels increased if shortages, slightly decreased if not. $-producer aims public-spiritedly to keep total of $15 in trading system. 25 Jan damped price changes when price falls below costs. Current system brings tool price falls is >2 competing tool producers, and labour competition pulls down labour price, and prices stabilise at costs. With tool 1,2, or 3, there is no equality, and idleness meanders around, with shortages of some tools, usually the $. With tool 0 there is equality, not shortages, and a flatline. */ import java.awt.*; import java.awt.event.*; import java.lang.*; import java.applet.*; import java.util.*; import java.net.*; public class Item extends Applet implements ItemListener, ActionListener, MouseListener, Runnable { double elapsed_time = 0; double dt = 1.0; // actual time step double dt_requ = 8.0; // required time step double display_dt = 256.0; // display time step int cycleprices; ItemEconomy ec; int frameNumber = -1; Thread animatorThread = null; boolean frozen = true; int appletDelay = 100; boolean debug = false; ItemGraphCanvas canvas1, canvas2; TextArea t1, t2, t3; TextListener l; Button b1; List c1; int currentChoice = 0; // selected Choice index no. boolean actionChoice = false; // true to do something about it boolean floatprices = false; Label counter; Label day, avAge, variance; int tset = 0; int vcheck = 0; int ctlTime[] = new int[15]; int ctlAction[] = new int[15]; int nt = 0; double tvalue[] = new double[20]; double tcost[] = new double[20]; double tlife[] = new double[20]; double tprice[] = new double[20]; int tool[] = new int[20]; double paramprice[] = new double[20]; double justMarkup; double damp; double pmf; String textorder = "ABCDEFGHIJKLMNO"; int nmen, tools, ui; int trading; int tx; int avperiod; // averaging period (days) boolean integerise = false; // integer/fractional purchases public String getAppletInfo() { return "Idle Theory economic model - Chris Davis 2008\r\n"; } public void init() { Dimension d = getSize(); Double dbl; int i; // set up the GUI GridBagLayout gridBag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); setLayout(gridBag); c.fill = GridBagConstraints.BOTH; c.insets = new Insets( 2, 2, 2, 2 ); t2 = new TextArea("Text area 2", 1, 14 ); c.gridx = 0; c.gridy = 0; c.gridwidth = 2; c.gridheight= 1; c.weightx = 1.0; c.weighty = 0.5; t2.setSize( d.width/2, 50 ); gridBag.setConstraints(t2, c); add(t2); c1 = new List(1, false); c1.addItem("0 Trading ON/OFF"); c1.addItem("1 Set Prices = zero"); c1.addItem("2 Set random prices"); c1.addItem("3 Set prices = Values"); c1.addItem("4 Double prices"); c1.addItem("5 Halve prices"); c1.addItem("6 Set Prices = Costs"); c1.addItem("7 Set Just Prices"); c1.addItem("8 Set Unjust 1-Price"); c1.addItem("9 Set Unjust 4-Price"); c1.addItem("10 Untooled idleness+"); c1.addItem("11 Untooled idleness-"); c1.addItem("12 Untooled idleness--"); c1.addItem("13 Add new trader"); c1.addItem("14 Remove a trader"); c1.addItem("15 Float prices ON/OFF"); c1.addItem("16 Lower labour prices 5%"); c1.addItem("17 Raise labour prices 5%"); c1.addItem("18 Slow/speed applet"); c.gridx = 2; c.gridy = 0; c.gridwidth = 2; c.gridheight= 1; c.weightx = 1.0; c.weighty = 0.5; gridBag.setConstraints(c1, c); add(c1); c1.addActionListener(this); t1 = new TextArea("Text area 1", 10, 25); c.gridx = 0; c.gridy = 1; c.gridwidth = 4; c.gridheight= 1; c.weightx = 1.0; c.weighty = 0.9; t1.setSize( d.width, d.width-20 ); gridBag.setConstraints(t1, c); add(t1); t1.setEditable(true); canvas2 = new ItemGraphCanvas(); c.gridx = 2; c.gridy = 2; c.gridwidth = 2; c.gridheight= 1; c.weightx = 1.0; c.weighty = 1.0; gridBag.setConstraints(canvas2, c); add(canvas2); canvas1 = new ItemGraphCanvas(); c.gridx = 0; c.gridy = 2; c.gridwidth = 2; c.gridheight= 1; c.weightx = 1.3; c.weighty = 1.0; gridBag.setConstraints(canvas1, c); add(canvas1); canvas1.addMouseListener( this ); canvas2.addMouseListener( this ); t1.addMouseListener( this ); t2.addMouseListener( this ); c1.addMouseListener( this ); t1.addTextListener( l ); validate(); int cc = getComponentCount(); Component cpt[] = getComponents(); /* Parameters allow Choice items to be programmed events. Thus CT0 = 110 and CA0 = 4 means "double prices on day 110" And CT1 = 230 and CA1 = 7 means "set just prices on day 230" */ // get timer control parameters. // These determine when some action takes place. for ( int pn = 0; pn <15; pn++ ) { try { ctlTime[pn] = Integer.parseInt( getParameter("CT" + Integer.toString(pn) ) ); } catch( Exception e ) { ctlTime[pn] = 0; } } // get control action parameters. // These determine what action takes place at ctlTime[pn]. for ( int pn = 0; pn <15; pn++ ) { try { ctlAction[pn] = Integer.parseInt( getParameter("CA" + Integer.toString(pn) ) ); } catch( Exception e ) { ctlAction[pn] = 0; } } /* get toolset to use */ try { tset = Integer.parseInt( getParameter("SET" ) ); } catch( Exception e ) { tset = 0; } /* get number of men in economy */ try { nmen = Integer.parseInt( getParameter("NMEN" ) ); } catch( Exception e ) { nmen = 4; } /* get number of tools in use */ try { tools = Integer.parseInt( getParameter("NTOOLS" ) ); } catch( Exception e ) { tools = 0; } /* get untooled idleness */ try { ui = Integer.parseInt( getParameter("UI" ) ); } catch( Exception e ) { ui = 0; } /* $ money tool */ try { tx = Integer.parseInt( getParameter("TX" ) ); } catch( Exception e ) { tx = 0; } // get tools to be manufactured by man[1] ... man[n] for ( int pn = 0; pn <15; pn++ ) { try { tool[pn] = Integer.parseInt( getParameter("TOOL" + Integer.toString(pn) ) ); } catch( Exception e ) { tool[pn] = pn; // default is that man 1 makes tool 1, etc } } // get tool prices for ( int pn = 0; pn <15; pn++ ) { try { dbl = Double.valueOf( getParameter("P" + Integer.toString(pn) ) ); paramprice[pn] = dbl.doubleValue(); } catch( Exception e ) { paramprice[pn] = 0.0; } } /* check prices less than values */ try { vcheck = Integer.parseInt( getParameter("VCHECK" ) ); } catch( Exception e ) { vcheck = 0; // default don't check } /* float prices */ try { if ( Integer.parseInt( getParameter("FLOAT") ) == 1 ) { floatprices = true; } else { floatprices = false; } } catch( Exception e ) { floatprices = false; } /* get trade/no trade */ try { trading = Integer.parseInt( getParameter("TRADE" ) ); } catch( Exception e ) { trading = 1; } /* get averaging period */ try { avperiod = Integer.parseInt( getParameter("AVPERIOD" ) ); if ( avperiod > 1000 ) avperiod = 1000; } catch( Exception e ) { avperiod = 50; } // get damping strength. 0.0 is no damping. try { dbl = Double.valueOf( getParameter("DAMP" ) ); damp = dbl.doubleValue(); } catch( Exception e ) { damp = 1.0; } /* get integer/fractional purchases * Integer purchases mean 1, 2, or 3 knives can be bought * Fractional purchases mean 0.1 or 1.1 units of wheat can be bought */ try { cc = Integer.parseInt( getParameter("INTEGERISE" ) ); if ( cc == 1 ) { integerise = true; } else { integerise=false; } } catch( Exception e ) { integerise=false; } try { cycleprices = Integer.parseInt( getParameter("CYCLE" ) ); } catch( Exception e ) { cycleprices = 0; } try { textorder = getParameter("TEXT" ); } catch( Exception e ) { textorder = "ABCDEFGHIJKL"; } /* set price movement factor */ try { dbl = Double.valueOf( getParameter("PMF") ); pmf = dbl.doubleValue(); } catch( Exception e ) { pmf = 0.02; } /* set Just markup */ try { dbl = Double.valueOf( getParameter("JUST") ); justMarkup = dbl.doubleValue(); } catch( Exception e ) { justMarkup = 1.1; } /* debug mode on/off */ try { debug = false; if ( Integer.parseInt( getParameter("DEBUG" ) ) == 1 ) { debug = true; } } catch( Exception e ) { debug = false; } //initialize economy ec = new ItemEconomy( this ); ec.init(); } public void start() { if (animatorThread == null) { animatorThread = new Thread(this); animatorThread.start(); } } public void stop() { if ( animatorThread != null ) { animatorThread.stop(); animatorThread = null; } } public void destroy() { } public void actionPerformed( ActionEvent ae ) { // start/stop button if ( ae.getSource() == b1 ) { frozen = !frozen; if ( frozen ) { b1.setLabel("Start"); } else { b1.setLabel("Stop"); } } // choice list if ( ae.getSource() == c1 ) { currentChoice = c1.getSelectedIndex(); actionChoice = true; // if frozen ( perhaps only just init'd ) perform choice action // immediately, else do in main loop engine. if ( frozen == true ) { actionChoice = ItemChoiceOptions.doChoiceAction( currentChoice, ec ); } } } public void itemStateChanged( ItemEvent ie ) { } public void mouseClicked( MouseEvent me) { } public void mouseEntered( MouseEvent me) { int x, y; frozen = true; x = me.getX(); y = me.getY(); } public void mouseExited( MouseEvent me) { frozen = false; } public void mousePressed( MouseEvent me) { } public void mouseReleased( MouseEvent me) { } public void run() { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); //This is the animation loop. while (Thread.currentThread() == animatorThread) { try { if ( !frozen ) { //Advance the animation frame. frameNumber++; // work out species idleness frozen = ec.engine(); // rolling graphs canvas2.repaint(); canvas1.repaint(); animatorThread.sleep( appletDelay ); } else { animatorThread.sleep(500); } } catch ( InterruptedException e ) { stop(); } } } } /****** Toolset **********************************************************/ /* These tools only save time in basic self-maintenence work * * Use table shows labour time saved by using tool X in making tool Y * Labour is tool 0. **/ class ItemToolset { /* Use fraction table: Daily value of using tool-t = Vt / Lt Daily fraction of tool-t used = 1 / Lt u[g][0][1] = Untooled amount of tool-0 (labour) used in making 1 unit of tool/good g. u[g][t][1] = amount or fraction of tool t used in making one unit of good g. u[g][t][2] = amount of labour time (tool-0) saved by using tool t in making one unit of good g. (also daily value) If amount_used[tool] * price[tool] < labour_time_saved * price[labour] a tool is worth using. u[g][t][3] = u[g][t][1] with tools not worth using omitted. */ int man = 0; int FV = 2; // fractional value array index int F = 1; // fraction array index int QT = 6; double toolValue[] = new double[QT]; double toolCost[] = new double[QT]; double toolLifetime[] = new double[QT]; int tsize = 10; double u[][][] = new double[tsize][tsize][6]; // tool 0 1 2 3 4 5 good double Q[][][][] = { { // Toolset 0 { // fraction of tool used in making 1 good { 1.0, 0.01, 0.04, 0.04, 0.10, 0.05 }, // 0 { 2.0, 0, 0.0, 0.0, 0.00, 0.00 }, // 1 { 1.0, 0, 0.0, 0.0, 0.00, 0.00 }, // 2 { 1.0, 0, 0.0, 0.0, 0.00, 0.00 }, // 3 { 1.0, 0, 0.0, 0.0, 0.00, 0.00 }, // 4 { 0.5, 0, 0.0, 0.0, 0.00, 0.00 } // 5 }, { // labour saving using tool to make 1 good { 0, 0.1, 0.16, 0.16, 0.20, 0.12 }, // 0 { 0, 0, 0.0, 0.0, 0.00, 0.00 }, // 1 { 0, 0, 0.0, 0.0, 0.00, 0.00 }, // 2 { 0, 0, 0.0, 0.0, 0.00, 0.00 }, // 3 { 0, 0, 0.0, 0.0, 0.00, 0.00 }, // 4 { 0, 0, 0.0, 0.0, 0.00, 0.00 } // 5 } }, { // Toolset 1 { // fraction of tool used in making 1 good { 1.0,0.001, 0.04, 0.01, 0.05, .001 }, // 0 { 2.0, 0, 0.0, 0.0, 0.00, 0.00 }, // 1 { 0.1, 0, 0.0, 0.0, 0.00, 0.00 }, // 2 { .01, 0, 0.0, 0.0, 0.00, 0.00 }, // 3 { 1.0, 0, 0.0, 0.0, 0.00, 0.00 }, // 4 { .0001, 0, 0.0, 0.0, 0.00, 0.00 } // 5 }, { // labour saving using tool to make 1 good { 0, 0.2, 0.25, 0.02, 0.2, 0.00 }, // 0 { 0, 0, 0.0, 0.0, 0.00, 0.00 }, // 1 { 0, 0, 0.0, 0.0, 0.00, 0.00 }, // 2 { 0, 0, 0.0, 0.0, 0.00, 0.00 }, // 3 { 0, 0, 0.0, 0.0, 0.00, 0.00 }, // 4 { 0, 0, 0.0, 0.0, 0.00, 0.00 } // 5 } } }; public ItemToolset() { int g, t; // data stored in program for ( g=0; g 0, tool has labour cost, so is made. for ( int g=1; g 0 ) count++; } return( count ); } public void displayTable() { int g, t; System.out.println( "G/T 0 1 2 3 4 5 fraction" ); for ( g=0; g 0 ) { u[good][tool][FV] = v/l; } else { u[good][tool][FV] = 0; } } public void setToolFraction( int good, int tool, double a ) { u[good][tool][F] = a; } public void setToolFractionL( int good, int tool, double l ) { if ( l > 0 ) { u[good][tool][F] = 1.0/l; } else { u[good][tool][F] = 0; } } public void setToolUntooledCost( int good, double a ) { u[good][man][F] = a; } } /****** Man - member of trading system ************************************/ class ItemMan { Item thisApplet; ItemEconomy economy; ItemToolset ts; int man = 0; boolean debug = false; static int maxHealth = 3; boolean alive; // life status double fatstock; // health (store of days of life) int id; // identity number double untooledIdleness; // untooled idleness (fraction) int avperiod; // averaging period int avindex; // current index into average array float avI[] = new float[1000];// average idleness array (%) double avIdleness; // idleness over average period (%) double purse; // purse reflects $ stock double purseThreshold; // purse level at which spending starts double avPurse; // purse over average period (10 days?) double predictedIncome; double predictedIdleness; double IOUissue; // IOUs issued double IOUlimit; // IOU issue limit (credit limit) boolean trading; // trading /not trading boolean integerise; // integer/fractional purchases boolean creditworthy; // true if can issue IOUs boolean discriminates; // true if buys when price < value int Tx; // $ unit (Tool for eXchange) int shoptool; // product name/number double shopMaxPrice; // shoptool price if P = V double shopMinPrice; // shoptool price if P = C double shopPrice; double toolPrice[] = new double[20]; // tool prices boolean shopSelling[] = new boolean[20]; // flags for goods on sale double purchaseTarget[] = new double[20]; // purchase targets double productionTarget[] = new double[20]; // production targets double stockTarget[] = new double[20]; // product stock-for-sale targets double o_stock[] = new double[20]; // tools-in-use stock (number) double i_stock[] = new double[20]; // tools just produced (number) double p_stock[] = new double[20]; // tools just bought (number) double useThruput[] = new double[20]; // use thruput in production double saleThruput[] = new double[20]; // sale thruput double avProductionCost[] = new double[20]; // tool average $ production costs double avPurchasePrice[] = new double[20]; // tool average $ purchase prices int numGoodsOwned; // number of different goods owned + used. int numToolsMissing; // number of tools missing (counted at end of day) int shortage; // shortage in production (counted during production) double allToolSales; // $ income from tool sales double allToolPurchases; // $ expenses from tool purchases double allLabourSales; // $ labour sales double allLabourPurchases; // $ labour purchases double idealIncome; // ideal $ income - $ expenses double tempLabour; // temporary labour store int vcheck; // = 1 to check price and value double s[] = new double[20]; // utility arrays double r[] = new double[20]; // .. .. double damper[][] = new double[4][20]; // dampers double maxThruput[] = new double[20]; // 10-day maximum sale thruput int index; double priceMovementFactor; double lastIdleness = 0.0; boolean z = false; int nextMan = 1; double verySmallAmount = 0.0001; /* default constructor */ public ItemMan() { } /* Man constructor */ public ItemMan( int id, int tool, int tx, double lprice, double tprice, ItemEconomy e ) { super(); economy = e; ts = economy.ts; this.id = id; this.alive = true; this.fatstock = maxHealth; setUntooledIdleness( economy.ui ); this.vcheck = economy.vcheck; this.discriminates = false; this.trading = economy.trading; this.Tx = tx; this.shoptool = tool; this.o_stock[man] = 1.0; this.p_stock[man] = 0.0; this.stockTarget[man] = 1.0; this.purchaseTarget[man] = 3.0; this.toolPrice[man] = lprice; this.avPurchasePrice[man] = economy.meanPrice[man]; this.allToolPurchases = 0.0; this.allToolSales = 0.0; this.allLabourPurchases = 0.0; this.allLabourSales = 0.0; clearDampers(); // price movement factor is made slightly different for each man // so as to ensure prices are slightly different differentiatePMF( economy.thisApplet.pmf ); for ( int n=1; n<20; n++ ) { this.saleThruput[n] = 0.0; this.stockTarget[n] = 1.0; this.o_stock[n] = 0.0; this.p_stock[n] = 0.0; this.toolPrice[n] = 1.0; this.avPurchasePrice[n] = economy.meanPrice[n]; this.purchaseTarget[n] = 1.0; this.shopSelling[n] = false; if ( n == tool ) { this.stockTarget[n] = 3.0; this.toolPrice[n] = tprice; this.shopSelling[n] = true; this.productionTarget[n] = 3.0; this.purchaseTarget[n] = 0.0; this.o_stock[n] = 3.0; this.useThruput[n] = 0.0; if ( n == Tx ) { this.stockTarget[n] = 3.0; this.toolPrice[n] = 1.0; this.shopSelling[n] = false; this.purchaseTarget[n] = 0.0; this.o_stock[n] = 3.0; // force early $ production } } if ( n == Tx ) this.o_stock[Tx] = 2.0; if ( n == man ) this.shopSelling[man] = true; maxThruput[n] = 0.0; } setPurse( Tx ); setPurseThreshold( 1.0 ); // set a low purse threshold this.numGoodsOwned = this.countNumGoodsOwned(); this.avindex = 0; this.avperiod = economy.avperiod; this.debug = economy.debug; index = this.id; nextMan = this.id; // where to start windowshopping } /* Make all tools */ public void makeAllTools() { if ( this.alive ) { this.makeTool(man); // make tool 0 this.makeTool(shoptool); // make shoptool N } } /* Make tools. Tool-0 is labour. Tool1 - N are physical tools. */ public void makeTool( int good ) { double a, f, flowest, ptarget, productionCost, unitProductionCost; boolean inproduction = true; if ( this.o_stock[man] <= 0.0 ) inproduction = false; // no labour available if ( this.productionTarget[good] <= 0.0 ) inproduction = false; // if ( good == Tx ) System.out.println( "$ production target " + productionTarget[Tx] ); while ( inproduction ) { ptarget = productionTarget[good]; // build up s[] table of tools stocked // build up r[] table of tools required to make 1 good for ( int t=0; t<=economy.ntools; t++ ) { if ( o_stock[t] > 0.0 ) { s[t] = o_stock[t]; } else { s[t] = 0.0; } if ( t == man ) { r[man] = ts.getUntooledCost(good); } else { if ( s[t] > 0.0 ) { r[t] = ts.getToolFraction(good, t); r[man] -= ts.getToolFractionalValue(good, t); } else { r[t] = 0.0; // if useful tool missing, flag shortage if ( ts.getToolFraction(good, t) > 0 ) flagShortage(t); } } } // find lowest f = (s[t] / (ptarget * r[t])) and f > 0. flowest = 1.0; for ( int t=0; t<=economy.ntools; t++ ) { f = s[t] / (ptarget * r[t]); if ( f > 1.0 ) f = 1.0; if ( f < flowest ) { if ( f > 0.0 ) flowest = f; } } // use all tools to produce (flowest x ptarget) amount of good // and work out $ cost of production productionCost = 0; for ( int t=0; t<=economy.ntools; t++ ) { a = flowest * ptarget * r[t]; o_stock[t] -= a; useThruput[t] += a; if ( o_stock[t] < verySmallAmount ) o_stock[t] = 0.0; productionCost += a * avPurchasePrice[t]; } unitProductionCost = productionCost / ( flowest * ptarget ); avProductionCost[good] = unitProductionCost; // average is current cost for now // get new average production $ cost and add to stock of good i_stock[good] += flowest * ptarget; a = flowest * ptarget; if ( debug ) System.out.println( this.id + " makes " + (float)a + " of tool " + good + " using " + (float)(a * r[0]) + " labour" ); // reduce stock target productionTarget[good] -= flowest * ptarget; // continue production if target not met and labour available if ( productionTarget[good] > verySmallAmount ) { if ( o_stock[man] <= 0.0 ) inproduction = false; } else { inproduction = false; } } } public void buyAllTools() { if ( this.alive ) { buySmallAmountsOfAllTools(); } } /* If short of tools, buy more. No value check. Buy using Tx. */ public void buySmallAmountsOfAllTools() { double a, f, use, bestprice, smallAmount, purse; int n, tool; boolean buying = false; for ( tool=economy.ntools; tool>=man; tool-- ) { f = 1.0 / (double)economy.nmen; // divide purchases if possible smallAmount = f * this.purchaseTarget[tool]; // set small amount to buy if ( smallAmount > verySmallAmount ) buying = true; while ( buying ) { // loop around buying purse = this.o_stock[Tx]; // The attempt to buy some small amount of a tool is cash limited // by the purse, if necessary, which it probably isn't. a = tryToBuyTool( tool, smallAmount, purse, 0 ); this.purchaseTarget[tool] -= a; // reduce target if ( a == 0.0 ) buying = false; if ( this.purchaseTarget[tool] < verySmallAmount ) buying = false; } } } /* Try to buy a small amount of some tool */ double tryToBuyTool( int tool, double amount, double cashLimit, int returntype ) { int seller; double a, as, unitprice; a = amount; // small a[mount] to buy unitprice = 0.0; seller = windowShop( tool, this.id ); // find seller n of best unitpriced tool if ( seller > 0 ) { // if there's a seller... as = economy.m[seller].o_stock[tool]; // amount of tool for sale unitprice = economy.m[seller].toolPrice[tool]; // tool unitprice if ( as > verySmallAmount ) { if ( as < a ) { // if seller doesn't have amount... a = as; // ...reduce amount } if ( (a * unitprice) > cashLimit ) { // if not enough money... a = cashLimit / unitprice; // reduce amount to buy } a = makeTransaction( seller, tool, a, unitprice, Tx ); // do transaction } else { a = 0.0; } // don't buy very small amounts } else { a = 0.0; } // if no seller, nothing bought if ( returntype == 0 ) { return( a ); // return amount bought } else { return( a * unitprice ); // return money spent } } /* go windowshopping for the trader offering best value for money */ int windowShop( int t, int exclude ) { int n, t1, t2, bestSeller = 0; // bestseller 0 is no seller double valueForMoney = 0.0; double bestValueForMoney = 0.0; double bestPrice; n = nextMan; for ( int m=1; m <= economy.nmen; m++ ) { if ( economy.m[n].trading ) { if ( n != exclude ) { t1 = economy.m[n].shoptool; t2 = man; if ( (t == t1) || ( t == t2) ) { // if trader n sells the required tool if ( economy.m[n].o_stock[t] >= verySmallAmount ) { valueForMoney = 1.0 / economy.m[n].toolPrice[t]; if ( valueForMoney > bestValueForMoney ) { bestValueForMoney = valueForMoney; bestSeller = n; bestPrice = economy.m[n].toolPrice[t]; if ( economy.vcheck > 0 ) { if ( priceExceedsValue( t, bestPrice ) ) { bestSeller = 0; // System.out.println( "Tool " + t + " overpriced" ); } } } } } } n++; if ( n > economy.nmen ) n = 1; } } // include this line to move where windowshopping starts next nextMan++; if ( nextMan > economy.nmen ) nextMan = 1; return( bestSeller ); } /* Perform transaction, exchanging tool and money. Return amount bought */ double makeTransaction( int seller, int tool, double a, double price, int moneyunit ) { int s = seller; double currentStock, currentPrice; double spend = a * price; // money spend amount if ( a > verySmallAmount ) { // if not trivial amount currentStock = this.o_stock[tool]; currentPrice = this.avPurchasePrice[tool]; // buyer takes money out of purse/stock this.o_stock[moneyunit] -= spend; // pay for a[mount] tools // buyer hands over money to seller if ( moneyunit == man ) { economy.m[s].o_stock[moneyunit] += spend; // labour payment for use today } else { economy.m[s].i_stock[moneyunit] += spend; // tool payment for use tomorrow } this.saleThruput[moneyunit] += spend; // $ is being 'sold' too! // seller takes goods off shelf economy.m[s].o_stock[tool] -= a; economy.m[s].saleThruput[tool] += a; // buyer receives goods if ( economy.iflag ) { this.p_stock[tool] += a; // receive a[mount] tools in input buffer } else { this.o_stock[tool] += a; // receive a[mount] tools for use now } // set new average purchase price of this tool this.avPurchasePrice[tool] = getAveragePrice( currentStock, currentPrice, a, price ); // note income and expenditure noteExpenses( this.id, seller, tool, spend ); if ( debug ) System.out.println( "Man " + this.id + " buys " + (float)a + " of tool " + tool + " from man " + s + " at $" + (float)price + "/unit s" + (float)o_stock[tool] + " t" + (float)purchaseTarget[tool] ); } else { a = 0.0; } return( a ); // return amount bought } /* Calculate a new average $ price of tool after more stock added */ double getAveragePrice( double stock, double price, double addedStock, double addedPrice ) { double averagePrice; averagePrice = ( stock * price + addedStock * addedPrice ) / ( stock + addedStock ); return( averagePrice ); } /* Transfer input stocks to output stocks for next day. For the most part, newly produced or bought goods go into input buffer i_stock[] for use the next day (except in the case of labour, which won't keep until tomorrow. So at the start of each day, input stocks are transferred to output stocks, o_stock[], for use or sale. */ public void transferIOstocks() { for ( int tool=0; tool<=economy.ntools; tool++ ) { if ( tool == man ) { // transfer input man/labour stock produced to fat/energy store. this.fatstock += this.i_stock[man]; this.i_stock[man] = 0.0; // transfer maximum of 1 day's labour from fat/energy store // to output stock for use next day. if ( this.fatstock > 1.0 ) { this.setIdleness( 1.0 + this.untooledIdleness ); this.fatstock -= 1.0; } else { this.setIdleness( this.fatstock + this.untooledIdleness ); this.fatstock = 0.0; } } else { this.o_stock[tool] += this.i_stock[tool]; this.i_stock[tool] = 0.0; } } } /*************************************************************************** CONTROL METHODS ****************************************************************************/ /* set individual production targets to reach target stock levels */ void setProductionTargets() { double a; for ( int t=0; t<=economy.ntools; t++ ) { if ( t == 0 ) { // Production work by individuals in making tool 0 (man) // produces stored future days of life, in the form of // stored body fat, which powers life for some period of time. // This 'stored time' is then released at the rate of one day // of idle time per day, which is available for use in performing // production work, or for sale to do work for others, or for leisure. // When the store runs out, the individual dies. this.productionTarget[man] = maxHealth - this.fatstock; } else { // All tools apart from labour (like knives and baskets) are // stored in piles which are available for use or for sale, and // which do not (in the present model) rot or corrode, and which // only vanish when they are used or consumed in production. if ( shoptool == t ) { a = stockTarget[t] - o_stock[t]; if ( a < 0.0 ) { a = 0.0; } a = damped( a, t, 0 ); // damped amount this.productionTarget[t] = a; } } } } /* set target stock levels as multiple of thruput. */ /* to be called after sales, before production? */ void setProductionStockTargets() { double totalThruput, a; for ( int t=0; t<=economy.ntools; t++ ) { if ( t == 0 ) { // if labour price below cost, do something if ( economy.vcheck > 0 ) { if ( t != Tx ) { if ( toolPrice[t] < avProductionCost[t] ) { a = avProductionCost[t]; setDamper( toolPrice[t], t, 3 ); toolPrice[t] = damped( a, t, 3 ); // damped amount // System.out.println( "Tool price " + t + " too low" ); } } } } else if ( t == Tx ) { // it seems that if there are enough $s in a system // shortages are minimal. if ( shoptool == Tx ) { // aim for a good level of money in whole economy if ( economy.findTotalMoney() < 15.0 ) { a = 1.05 * stockTarget[t]; } else { a = 0.98 * stockTarget[t]; } a = damped( a, t, 1 ); // damped amount stockTarget[t] = a; // stockTarget[t] = 3.0; OLD METHOD } } else { if ( this.shoptool == t ) { // get the maximum sale+use thruput over 10 day period. // set target as multiple of this thruput. totalThruput = saleThruput[t] + useThruput[t]; if ( economy.clock10 == 0 ) { a = 4.0 * maxThruput[t] + 0.01; a = damped( a, t, 1 ); // damped amount stockTarget[t] = a; maxThruput[t] = 0.0; } else { if ( totalThruput > maxThruput[t] ) { maxThruput[t] = totalThruput; } } // if price below cost, do something. if ( economy.vcheck > 0 ) { if ( t != Tx ) { if ( toolPrice[t] < avProductionCost[t] ) { a = avProductionCost[t]; setDamper( toolPrice[t], t, 3 ); toolPrice[t] = damped( a, t, 3 ); // damped amount // System.out.println( "Tool price " + t + " too low" ); // stockTarget[t] = useThruput[t]; } } } } } } } /* Set individual purchase targets */ public void setPurchaseTargets() { double netIncome; double a = 0.0; for ( int t=0; t<=economy.ntools; t++ ) { if ( t == man ) { // Some fraction of labour use thruput is bought, // on the grounds that high labour usage implies a need to buy labour. // This demand for labour is modulated by available $s, such that // low $s must reduce demand, and high $s increase it. double f = economy.getSumPrices() * 0.5; // in earlier version a = 1.0 if ( o_stock[Tx] < f ) { // .. a = 0.50 * ( o_stock[Tx] * 2.0 / f ); // .. } else { // .. a = 1.0; // .. } // .. // see also burnMoney()... a = damped( a, t, 2 ); // damped target this.purchaseTarget[man] = 0.50 * this.useThruput[man] * a; if ( o_stock[Tx] < 0.5 )this.purchaseTarget[man] = 0.0; } else if ( t == Tx ) { this.purchaseTarget[t] = 0.0; // don't buy $s } else if ( t == this.shoptool ) { this.purchaseTarget[t] = 0.0; // don't buy own tool } else { if ( this.o_stock[t] < stockTarget[t] ) { // if stocks low... a = stockTarget[t] - this.o_stock[t]; // set a[mount] to buy a = damped( a, t, 2 ); // damped target if ( economy.integerise ) { a = Math.rint(a) + 1.0; // integer value purchases } } else { a = 0.0; a = damped( a, t, 2 ); // damped target } this.purchaseTarget[t] = a; // buy other tools } } } /* float tool prices up or down to increase idleness */ void floatPrices() { double mf, newprice, f; // if tool sales > 0, raise prices. // if tool sales = 0, and not sold out, lower prices // if tool sales = 0, and sold out, raise prices // float tool price if ( shoptool != Tx ) { mf = Math.abs( priceMovementFactor ); f = mf; if ( saleThruput[ shoptool ] <= 0.0 ) { // if ( o_stock[ shoptool ] > 0.0 ) { f = -mf; // } } toolPrice[ shoptool] = toolPrice[ shoptool ] + toolPrice[ shoptool ] * f; // if ( toolPrice[ shoptool ] > shopMaxPrice ) toolPrice[ shoptool ] = 0.9 * shopMaxPrice; } // float labour price if ( Tx != 0 ) { mf = Math.abs( priceMovementFactor ); f = mf; if ( saleThruput[ man ] <= 0.0 ) { // if ( o_stock[ man ] > 0.0 ) { f = -mf; // } } // if no money, reduce labour price if ( o_stock[Tx] <= verySmallAmount ) { f = -mf; // System.out.println( "NO CASH !!" ); } toolPrice[ man ] = toolPrice[ man ] + toolPrice[ man ] * f; } } void priceFloorCheck() { if ( this.toolPrice[shoptool] < ( economy.justMarkup * avProductionCost[shoptool] ) ) { // this.toolPrice[shoptool] = economy.justMarkup * avProductionCost[shoptool]; // System.out.println( "Man " + this.id + "PRICE RAISED" ); } } /* if tool price > tool value, return true */ boolean priceExceedsValue( int t, double p ) { boolean check = true; if ( economy.vcheck > 0 ) { if ( t != man ) { double v = ts.toolValue[t]; // tool labour-saving value v = v * this.toolPrice[man]; // ...times price of labour if ( p < v ) check = false; } else { check = false; // allow any labour price } } else { check = false; // not checked } return( check ); } /* if tool price < tool cost, return true */ boolean priceBelowCost( int t, double p ) { boolean check = true; double v = ts.toolCost[t]; // tool labour cost of production v = v * this.toolPrice[man]; // ...times price of labour if ( p >= v ) check = false; return( check ); } /* return damped number. damp = 0 for no damping. */ double damped( double a, int tool, int type ) { if ( a < 0.0 ) a = 0.0; a = ( a + economy.damp * damper[type][tool] ) / ( 1.0 + economy.damp ); damper[type][tool] = a; return( a ); } void setDamper( double a, int tool, int type ) { damper[type][tool] = a; } /*************************************************************************** UTILITY METHODS ****************************************************************************/ /* Note expenditures on tool and labour purchases, and income from tool and labour sales */ void noteExpenses( int buyer, int seller, int tool, double moneyExchanged ) { if ( tool != man ) { if ( buyer != seller ) { economy.m[buyer].allToolPurchases += moneyExchanged; economy.m[seller].allToolSales += moneyExchanged; } } else { if ( buyer != seller ) { economy.m[buyer].allLabourPurchases += moneyExchanged; economy.m[seller].allLabourSales += moneyExchanged; } } } /* clear tool income and expenses */ void clearExpenses() { this.allToolPurchases = 0.0; this.allToolSales = 0.0; this.allLabourPurchases = 0.0; this.allLabourSales = 0.0; } /* store tool shortages as flag bits set in shortage integer variable */ void flagShortage( int tool ) { shortage = shortage | (int)Math.pow( 2.00, (double)(tool-1) ); } /* return number list of tools short. OK for up to 9 tools. */ /* doesn't include tool 0? */ int findShortages() { int mask = 1; int list = 0; for ( int t=1; t<=8; t++ ) { // assumes no more than 8 tools if ( ( shortage & mask ) > 0 ) { list = t + list * 10; } mask = 2 * mask; } return( list ); } /* count shortages, and return number of shortages */ int countShortages() { int mask = 1; int count = 0; for ( int t=1; t<=8; t++ ) { // assumes no more than 8 tools if ( ( shortage & mask ) > 0 ) { count++; } mask = 2 * mask; } return( count ); } /* make each price movement factor unique */ double differentiatePMF( double pmf ) { priceMovementFactor = pmf + verySmallAmount * (double)this.id; return( priceMovementFactor ); } /* find shop price corresponding to tool value */ double findShopMaxPrice() { double toolvalue = ts.toolValue[ shoptool ]; shopMaxPrice = toolvalue * this.toolPrice[man]; return( shopMaxPrice ); } /* find shop price corresponding to tool cost */ double findShopMinPrice() { double toolcost = ts.toolCost[ shoptool ]; //labour cost of production shopMinPrice = toolcost * this.toolPrice[man]; return( shopMinPrice ); } /* set purse to stock of whatever is being used as $ unit */ double setPurse( int tx ) { this.purse = this.o_stock[tx]; return( this.purse ); } /* get purse contents */ double getPurse( int tx ) { return( this.o_stock[tx] ); } /* get spending money ( money in excess of purse threshold ) */ double getSpendingMoney( int tx ) { double a = 0.0; if ( this.purse > this.purseThreshold ) { a = this.purse - this.purseThreshold; } return( a ); } /* set purse threshold */ void setPurseThreshold( double amt ) { this.purseThreshold = amt; } /* get idleness from today's stock of tool-0 */ double getIdleness() { return( this.o_stock[man] ); } /* add idle time to today's stock of tool-0 */ double addIdleness( double a) { this.o_stock[man] += a; return( this.o_stock[man] ); } /* set today's stock of tool-0 */ double setIdleness( double a) { this.o_stock[man] = a; return( this.o_stock[man] ); } double getShopStock() { return( this.o_stock[ this.shoptool ] ); } void setShopStock( double a ) { this.o_stock[ this.shoptool ] = a; } /* count tools owned and used */ int countNumGoodsOwned() { this.numGoodsOwned = 0; for ( int t=1; t<=economy.ntools; t++ ) { if ( this.o_stock[t] > 0.0 ) this.numGoodsOwned++; } return( this.numGoodsOwned ); } void clearNumToolsMissing() { this.numToolsMissing = 0; } int countNumToolsMissing() { this.numToolsMissing = 0; for ( int t=1; t<=economy.ntools; t++ ) { if ( this.o_stock[t] <= 0.0 ) this.numToolsMissing++; } return( this.numToolsMissing ); } void clearShortage() { this.shortage = 0; } void clearThruputs() { for ( int t=0; t<=economy.ntools; t++ ) { this.useThruput[t] = 0.0; this.saleThruput[t] = 0.0; } } void setTradingStatus( boolean status ) { this.trading = status; } void clearDampers() { for ( int r=0; r<3; r++ ) { for ( int n=0; n<20; n++ ) { this.damper[r][n] = 0.0; } } } /* find the $ income from selling to everyone minus expenses from buying from everyone */ double findidealIncome() { int seller; double rate; double expenses, income = 0.0; // income from selling own tool at same rate to all other men. rate = 1.0 / ts.toolLifetime[ this.shoptool ]; income = (economy.nmen - 1) * rate * this.toolPrice[ this.shoptool ]; // expenditure buying all other tools except labour or own tool expenses = 0.0; for ( int t=1; t<=economy.ntools; t++ ) { if ( t != this.shoptool ) { seller = economy.findToolSeller( t ); if ( seller > 0 ) { rate = 1.0 / ts.toolLifetime[ t ]; expenses += economy.m[seller].toolPrice[t] * rate; } } } this.idealIncome = income - expenses; return( this.idealIncome ); } /* If idleness < 0, reduce health, otherwise increment to maxHealth. If fatstock falls to zero, set alive = false */ void setHealth() { if ( this.getIdleness() < 0 ) { if ( this.fatstock <= 0 ) { if ( this.alive) this.setDead(); } } else { if ( this.fatstock > maxHealth ) this.fatstock = maxHealth; } } /* set fractional untooled idleness */ void setUntooledIdleness( double ui ) { this.untooledIdleness = ( ui + 0.0005 ) / 100.0; } /* set dead */ void setDead() { this.alive = false; this.trading = false; this.setIdleness( -1.0 ); // ? for ( int n = 0; n < this.avperiod; n++ ) this.setavI(); System.out.println( "man " + this.id + " dies on day " + economy.day ); } /* enter current idleness into average-period idleness array */ void setavI() { this.avI[avindex] = (float)(this.getIdleness() * 100.0); avindex++; if ( avindex >= avperiod ) avindex = 0; } /* return average-period idleness */ double getavI() { float isum = 0; for ( int i = 0; i < this.avperiod; i++ ) { isum += this.avI[ i ]; } return ( (double)isum / ((double)this.avperiod * 100.0 ) ); } // change prices, except $ price of $ void changePrice( double factor ) { int t = this.shoptool; if ( Tx != man ) this.toolPrice[man] = this.toolPrice[man] * factor; if ( Tx != t ) this.toolPrice[t] = this.toolPrice[t] * factor; } } /****** Economy class variables, constructors and methods*************/ class ItemEconomy { Item thisApplet; boolean debug = false; public ItemToolset ts; public int tset; // selected toolset public static final int NMAX = 20; // max number of men public double meanIdleness; // predicted mean idleness public ItemTextFormatter scrtext; // main table public ItemTextFormatter scrtext2; // applet info public boolean trading; // trading/not-trading flag public double justMarkup; // just price markup public ItemMan m[] = new ItemMan[NMAX]; // array of men public int nmen = 4; // number of men public int ntools = 5; // number of tools public int day = 1; // day counter public int redLetterDay; // flag some event public double totprice; // total price of all tools public int index = 1; // re-indexer public int avperiod; // averaging period public int nextAvDay = avperiod; public int ctlPointer = 0; // choice event control public double ui; // % untooled idleness public int vcheck; // check prices against values public boolean integerise; // integer/fractional purchases boolean floatprices; // float prices public int Tx; // $ unit (Tool for eXchange) double lprice, tprice; double meanPrice[] = new double[20]; double sumPrice; int nshortages; // number of shortages experienced double damp; // damping weight. 0 = none. int nextman; int TxManufacturer = 0; int clock5 = 0; // 5-day clock int clock10 = 0; // 10-day clock boolean iflag = false; // flag for bought goods to go to i_stocks String textorder = new String(); // Constructor allows access to Applet public ItemEconomy( Item a ) { super(); thisApplet = a; tset = thisApplet.tset; ts = new ItemToolset( thisApplet.tset ); } public void init() { int tool, n, i; day = 1; redLetterDay = -1; /* set toolset to use */ tset = thisApplet.tset; /* set % untooled idleness */ ui = (double)thisApplet.ui; vcheck = thisApplet.vcheck; floatprices = thisApplet.floatprices; debug = thisApplet.debug; /* set number of men in economy */ this.nmen = thisApplet.nmen; if ( this.nmen > NMAX ) this.nmen = NMAX; /* set tool used as $ */ Tx = thisApplet.tx; /* get number of tools in toolset */ this.ntools = thisApplet.tools; /* integer/fractional purchases */ integerise = thisApplet.integerise; /* set trading/ not trading */ trading = true; if ( thisApplet.trading == 0 ) trading = false; /* set just price markup to be used, if required */ justMarkup = thisApplet.justMarkup; /* set averaging period */ avperiod = thisApplet.avperiod; if ( avperiod > 1000 ) avperiod = 1000; if ( avperiod < 1 ) avperiod = 1; /* get damping weight */ damp = thisApplet.damp; /* define each man's shop tool, price, and stock */ lprice = thisApplet.paramprice[0]; meanPrice[0] = lprice; for ( n = 1; n <= 5; n++ ) { meanPrice[n] = thisApplet.paramprice[n]; } for ( n = 1; n <= 10; n++ ) { tool = thisApplet.tool[n]; if ( tool == Tx ) TxManufacturer = n; tprice = thisApplet.paramprice[tool]; m[n] = new ItemMan( n, tool, Tx, lprice, tprice, this); } nextman = 1; /* set up TextAreaa */ scrtext = new ItemTextFormatter( this ); scrtext.setDisplayOrder( thisApplet.textorder ); scrtext2 = new ItemTextFormatter( this ); scrtext2.setMode( 1 ); scrtext.setTextDisplay( thisApplet.t1 ); scrtext.setTextDisplay( thisApplet.t2 ); /// label and scale canvas thisApplet.canvas1.setYscale( 2 ); meanIdleness = predictMeanIdleness(); ts.displayTable(); predictThings(); // findIterativelyCostPrices( ntools, 1, 1.1 ); } /* The engine works out who does what during each 'day' of the economy. */ public boolean engine() { int i, n; boolean allDead = true; while ( thisApplet.ctlTime[ctlPointer] == day ) { thisApplet.actionChoice = ItemChoiceOptions.doChoiceAction( thisApplet.ctlAction[ctlPointer], this ); ctlPointer++; } /* action any selected Choices */ if ( thisApplet.actionChoice ) thisApplet.actionChoice = ItemChoiceOptions.doChoiceAction( thisApplet.currentChoice, this ); // System.out.println(); // System.out.println("day" + day); /* daily preliminaries */ incrementClocks(); countTotalShortages(); for ( n=1; n <= nmen; n++ ) { if ( m[n].alive ) { allDead = false; if ( floatprices ) m[n].floatPrices(); // float prices up or down m[n].transferIOstocks(); // transfer i/p stocks to o/p m[n].clearExpenses(); // reset expense totals m[n].findidealIncome(); // find ideal expenses m[n].setTradingStatus( trading ); // set trading status m[n].clearShortage(); // clear flagged shortages m[n].clearNumToolsMissing(); m[n].setHealth(); // set health status m[n].setProductionStockTargets(); // adjust production targets m[n].setProductionTargets(); // set day production targets m[n].setPurchaseTargets(); // set day purchase targets m[n].clearThruputs(); // clear use and sale thruputs m[n].findShopMaxPrice(); // max shoptool price m[n].findShopMinPrice(); // min shoptool price if ( vcheck > 0 )m[n].priceFloorCheck(); // check P < C, raise prices if so } } findMeanPrices(); /* action any selected Choices */ if ( thisApplet.actionChoice ) thisApplet.actionChoice = ItemChoiceOptions.doChoiceAction( thisApplet.currentChoice, this ); /* have each man buy all tools */ for ( n=1; n <= nmen; n++ ) { m[n].buyAllTools(); } /* have each man make all necessary tools */ for ( n=1; n <= nmen; n++ ) { m[n].makeAllTools(); } /* have each man burn excess money buying labour */ burnMoney(); /* re-indexing is done to stop man 1 always being first in line */ index += 1; if (index > nmen) index = 1; // change index findAverages(); /* set purse contents to $s remaining at end of day */ setPurses(); displayResults(); day++; redLetterDay = -1; return( allDead ); } /* clocks 'chime' every few days */ void incrementClocks() { if( clock10++ > 9 ) clock10 = 0; // 10 day clock if( clock5++ > 9 ) clock5 = 0; // 5 day clock } /* spend excess $s on buying labour (and thereby increasing own idleness) Small amounts of labour are bought to spread the buying. Labour is held in i_stock until all purchases complete. */ void burnMoney() { int s, n; int man = m[1].man; double p, f, a, as, moneyrequ, amountspent, amoney, smallAmountMoney; double verySmallAmount = m[1].verySmallAmount; boolean buying = false; boolean someoneBuying = true; double thruput; iflag = true; // bought labour to go into i_stock[man] while ( someoneBuying ) { someoneBuying = false; for ( n=1; n<=nmen; n++ ) { sumPrice = getSumPrices(); // in earlier version sumPrice = 6.0 amountspent = 0.0; amoney = 0.0; // money to spend thruput = m[n].useThruput[Tx] + m[n].saleThruput[Tx]; if ( m[n].o_stock[Tx] > sumPrice) { amoney = m[n].o_stock[Tx] - sumPrice; if ( amoney < 0 ) amoney = 0.0; if ( amoney > 0 ) buying = true; } f = 1.0 / (double)nmen; // divide purchases if possible smallAmountMoney = f * amoney; // set small amount to buy if ( amoney > 0.0 ) { // Excess cash is spent buying labour to directly increase idleness. // So the attempt is not to buy some amount of labour, but to spend money, // and so a stupidly large amount of labour is passed to tryToBuyTool() so // as to force the cash limit into operation. amountspent = m[n].tryToBuyTool( man, 1000.0, smallAmountMoney, 1 ); amoney -= amountspent; // is it amoney that should be reduced? if ( amoney < verySmallAmount ) buying = false; if ( amountspent < verySmallAmount ) buying = false; } else buying = false; // if anyone is buying, flag someone buying as true. if ( buying ) someoneBuying = true; } } // transfer bought labour to output stocks for ( n=1; n<=nmen; n++ ) { m[n].o_stock[man] += m[n].p_stock[man]; m[n].p_stock[man] = 0.0; } iflag = false; // bought goods to be put in o_stock[] } int findToolSeller( int tool ) { int seller = 0; for ( int n=1; n<=nmen; n++ ) { if ( m[n].shoptool == tool ) seller = n; } return( seller ); } /* takes an index value and re-indexes it so if 6 men in system, indexes 345678 returns 345612 */ int reindex( int n ) { int i; i = n; if ( n > nmen ) i -= nmen; if ( n < 1 ) i = nmen; return( i ); } /* find the total amount of money in the system */ double findTotalMoney() { double totalMoney = 0.0; for ( int n=1; n<=nmen; n++ ) { totalMoney += m[n].o_stock[Tx]; totalMoney += m[n].i_stock[Tx]; totalMoney += m[n].p_stock[Tx]; // $s just bought? } return ( totalMoney ); } int countTotalShortages() { nshortages = 0; for ( int n=1; n<=nmen; n++ ) { nshortages += m[n].countShortages(); } return ( nshortages ); } /* find mean or average prices of tools on sale */ void findMeanPrices() { double num, pmean; for ( int g=0; g<=ntools; g++ ) { pmean = 0.0; num = 0.0; for ( int n = 1; n<= nmen; n++ ) { if ( g == 0 ) { pmean += m[n].toolPrice[0]; num++; } else { if ( g == m[n].shoptool ) { pmean += m[n].toolPrice[g]; num++; } } } meanPrice[g] = pmean / num; } } double getSumPrices() { int t; double sum = 0.0; for( int n=1; n<=nmen; n++ ) { t= m[n].shoptool; sum += m[n].toolPrice[t]; } return( sum ); } double findMeanMoney() { double totMoney = 0.0; for ( int n = 1; n<= nmen; n++ ) { totMoney += m[n].o_stock[Tx]; } return( totMoney / (double)nmen ); } public void findAverages() { totprice = 0.0; for ( int n = 1; n<= nmen; n++ ) { totprice += m[n].shopPrice; m[n].setavI(); m[n].avIdleness = m[n].getavI() * 100.0 ; } } public void setPurses() { for ( int n = 1; n<= nmen; n++ ) { m[n].setPurse( Tx ); } } /* mean idleness = sum (V-C) / L of all available tools */ public double predictMeanIdleness() { double idleness; idleness = ui / 100.0; /* assume all have same untooled idleness */ for ( int n = 1; n <= ntools; n++ ) { idleness += ( ts.toolValue[n] - ts.toolCost[n] ) / ts.toolLifetime[n]; } return( idleness ); } // multiply all tool prices by sinusoidally varying factor f void sineWavePrices( double amplitude ) { double f = 1.0 + amplitude * Math.sin( Math.PI * (double)day / 360.0 ); for ( int n=1; n <= nmen; n++ ) { if ( n != Tx ) m[n].changePrice( f ); } } void showCurrentIdleness() { for ( int n=1; n<=nmen; n++ ) { System.out.print( "i" + n + "=" + m[n].o_stock[0] + " " ); } System.out.println(); } /* output some results */ public void displayResults() { String s; scrtext.setTextDisplay( thisApplet.t1 ); scrtext.setSwitchTextDisplay( thisApplet.t1 ); scrtext.textDisplay( thisApplet.t1 ); scrtext2.setTextDisplay( thisApplet.t2 ); scrtext2.textDisplay( thisApplet.t2 ); int maxn = 4; if ( nmen < maxn ) maxn = nmen; for ( int n = 1; n <= maxn; n++ ) { thisApplet.canvas2.nexty[n] = m[n].avIdleness; thisApplet.canvas2.setStreamLabel( n, "i" + Integer.toString(n) ); } for ( int t=0; t<=ntools; t++ ) { thisApplet.canvas1.nexty[t] = meanPrice[t]; s = "p" + Integer.toString(t); thisApplet.canvas1.setStreamLabel(t, s); } double totpurse = 0; for ( int n=1; n <= nmen; n++ ) { totpurse += m[n].purse; }; thisApplet.canvas2.nexty[0] = (totpurse+0.5); thisApplet.canvas2.streamLabel[0] = "$"; thisApplet.canvas2.day = day; thisApplet.canvas2.redLetterDay = redLetterDay; thisApplet.canvas1.day = day; thisApplet.canvas1.redLetterDay = redLetterDay; if ( day == nextAvDay ) { nextAvDay += avperiod; } } void predictThings() { int n, t, g; double v, c, l, p, vtot; vtot = 0.0; g = 0; for ( n=0; n<=nmen; n++ ) { // System.out.println( "P" + n + "= " + (float)ts.PT[n] ); } for ( n=1; n<=nmen; n++ ) { t = m[n].shoptool; v = ts.getToolValue(g, t); c = ts.getUntooledCost( t ); l = ts.getToolLifetime(g, t ); p = m[n].toolPrice[t]; vtot += (v / l); } } } /*********** do Choice actions *******************************************/ class ItemChoiceOptions { public static boolean doChoiceAction( int choice, ItemEconomy economy ) { int i, n, a, b, t; double v, r; boolean doagain = false; boolean newprice = false; int Tx = economy.Tx; if ( choice == 0 ) { // toggle trading/not trading economy.trading = !economy.trading; for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].trading = !economy.m[n].trading; } } else if ( choice == 1 ) { // set zero prices for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; economy.m[n].toolPrice[i] = 0.0; economy.m[n].toolPrice[Tx] = 1.0; } newprice = true; } else if ( choice == 2) { // C < random price < P for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; v = Math.random(); economy.m[n].toolPrice[i] = v; economy.m[n].toolPrice[Tx] = 1.0; } newprice = true; } else if ( choice == 3 ) { // set prices = ABS values // start off by setting all prices to tool-0 $ values for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; economy.m[n].toolPrice[i] = Math.abs( economy.ts.toolValue[i] ); // economy.m[n].toolPrice[0] = 1.0; } // multiply all prices by resulting inverse of price of $ if ( Tx == 0 ) { r = 1.0; } else { r = 1.0 / economy.m[ economy.TxManufacturer ].toolPrice[Tx]; } for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; economy.m[n].toolPrice[i] = r * economy.m[n].toolPrice[i]; // economy.m[n].toolPrice[0] = r * economy.m[n].toolPrice[0]; } newprice = true; } else if ( choice == 4 ) { // double prices for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; economy.m[n].toolPrice[i] *= 2.0; economy.m[n].toolPrice[Tx] = 1.0; } } else if ( choice == 5 ) { // halve prices for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; economy.m[n].toolPrice[i] /= 2.0; economy.m[n].toolPrice[Tx] = 1.0; } newprice = true; } else if ( choice == 6 ) { // set Prices = Costs // start off by setting prices to labour costs for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; economy.m[n].toolPrice[i] = Math.abs( economy.ts.toolCost[i] ); economy.m[n].toolPrice[0] = 1.0; // economy.m[n].toolPrice[0] = economy.m[n].avProductionCost[0]; } // multiply all prices by resulting inverse of price of $ if ( Tx == 0 ) { r = 1.0; } else { r = 1.0 / economy.m[ economy.TxManufacturer ].toolPrice[Tx]; } for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; economy.m[n].toolPrice[i] = r * economy.m[n].toolPrice[i]; // economy.m[n].toolPrice[0] = r * economy.m[n].toolPrice[0]; } newprice = true; } else if ( choice == 7 ) { // set Just Prices /* Just Prices to produce equal idleness. prices are related such that Pa = Ca + La.( Pb - Cb ) / Lb where a and b are any two tools, and P is price , C cost, and L lifetime. */ // First find just prices using tool-0 // Labour price[1] = justMarkup * Cost[1] b = economy.m[1].shoptool; economy.m[1].toolPrice[b] = economy.ts.toolCost[b] * economy.justMarkup; System.out.print( (float)economy.m[1].toolPrice[b] + " " ); for ( int iter = 0; iter < 3; iter++ ) { for ( n = 1; n <= economy.nmen; n++ ) { i = n + 1; if ( i > economy.nmen ) i = 1; economy.m[n].toolPrice[0] = 1.0; economy.m[i].toolPrice[0] = 1.0; a = economy.m[n].shoptool; b = economy.m[i].shoptool; economy.m[i].toolPrice[b] = economy.ts.toolCost[b] + economy.ts.toolLifetime[b] * ( economy.m[n].toolPrice[a] - economy.ts.toolCost[a] ) / economy.ts.toolLifetime[a]; } } // Set just $-prices by multiplying all labour just prices by factor // that sets $-price of $ to 1.0. if ( Tx == 0 ) { r = 1.0; } else { t = Tx; r = 1.0 / economy.m[ economy.TxManufacturer ].toolPrice[t]; } for ( n = 1; n <= economy.nmen; n++ ) { a = economy.m[n].shoptool; economy.m[n].toolPrice[0] = r * economy.m[n].toolPrice[0]; economy.m[n].toolPrice[a] = r * economy.m[n].toolPrice[a]; } newprice = true; } else if ( choice == 8 ) { // set unjust price for man 1 for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].toolPrice[0] = 1.0; i = economy.m[n].shoptool; if ( n == 1 ) { economy.m[n].toolPrice[i] = economy.ts.toolCost[i] + economy.ts.toolLifetime[i] * economy.meanIdleness; } else { economy.m[n].toolPrice[i] = economy.ts.toolCost[i]; } } // if Tx not 0, multiply all prices by factor that sets $ price of $ to 1. if ( Tx != 0 ) { t = Tx; r = 1.0 / economy.m[ economy.TxManufacturer ].toolPrice[t]; for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].toolPrice[0] *= r; economy.m[n].toolPrice[n] *= r; } } newprice = true; } else if ( choice == 9 ) { // set unjust price for man 4 for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].toolPrice[0] = 1.0; i = economy.m[n].shoptool; if ( n == 4 ) { economy.m[n].toolPrice[i] = economy.ts.toolCost[i] + economy.ts.toolLifetime[i] * economy.meanIdleness; } else { economy.m[n].toolPrice[i] = economy.ts.toolCost[i]; } } // if Tx not 0, multiply all prices by factor that sets $ price of $ to 1. if ( Tx != 0 ) { t = Tx; r = 1.0 / economy.m[ economy.TxManufacturer ].toolPrice[t]; for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].toolPrice[0] *= r; economy.m[n].toolPrice[n] *= r; } } newprice = true; } else if ( choice == 10) { // increase untooled idleness economy.ui += 5; for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].untooledIdleness += 0.05; if ( economy.m[n].untooledIdleness > 1.0 ) economy.m[n].untooledIdleness = 1.0; } } else if ( choice == 11) { // decrease untooled idleness economy.ui -= 5; for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].setUntooledIdleness( economy.ui ); } } else if ( choice == 12) { // falling untooled idleness economy.ui -= 0.1; for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].untooledIdleness -= 0.001; doagain = true; // this will be cancelled by any other selection!!! } } else if ( choice == 13) { // add new trader if ( economy.nmen < 20 ) { economy.nmen += 1; economy.m[economy.nmen].shoptool = economy.nmen; economy.ntools += 1; // economy.thisApplet.canvas2.addStream(); } } else if ( choice == 14) { // remove last trader if ( economy.nmen > 1 ) { economy.nmen -= 1; economy.ntools -= 1; economy.thisApplet.canvas2.removeStream(); } } else if ( choice == 15) { // float/unfloat tool prices economy.floatprices = !economy.floatprices; if ( economy.floatprices ) { for ( n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; } } economy.vcheck = 1; // enable price value/cost checking } else if ( choice == 16) { // lower all labour prices 5% for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].toolPrice[0] = economy.m[n].toolPrice[0] * 0.975; } } else if ( choice == 17) { // raise all labour prices 5% for ( n = 1; n <= economy.nmen; n++ ) { economy.m[n].toolPrice[0] = economy.m[n].toolPrice[0] / 0.975; } } else if ( choice == 18) { // slow/speed applet n = economy.thisApplet.appletDelay; if ( n <= 100 ) { n = 10000; } else { n = 100; } economy.thisApplet.appletDelay = n; } if ( !doagain ) economy.redLetterDay = choice; return( doagain ); } /* find total price of all goods, and set this as credit limit */ public static void setCreditLimits( ItemEconomy economy) { double totprice = 0; int i; for ( int n = 1; n <= economy.nmen; n++ ) { i = economy.m[n].shoptool; totprice += economy.m[n].toolPrice[i]; } for ( int n = 1; n <= economy.nmen; n++ ) { if ( economy.m[n].IOUlimit > 0 ) { economy.m[n].IOUlimit = totprice + 0.1; } } } } /*********** text area formatter *****************************************/ class ItemTextFormatter { public ItemEconomy economy; int mode; int maxfields = 12; public StringBuffer b; int editOffset; String textorder = "ABCDEFGH"; int rowlen; int rows = 16; // no. of rows of data to display public int indent[] = new int[ItemEconomy.NMAX]; public final String title[] = { // make sure these are 8 chars + \t "Man \t", "Status \t", "%Av.I \t", "Purse \t", // A,B,C,D "Short \t", "P0 \t", "Pmax \t", "Pt \t", // E,F,G,H "Pmin \t", "Tstock \t", "Target \t", "ttool \t", // I,J,K,L "tvalue \t", "tcost \t", "tlife \t", "Uthruput\t", // M,N,O,P "Sthruput\t", "Use 0 \t", "T$ in \t", "T$ out \t", // Q,R,S,T "L$ in \t", "L$ out \t", "Ideal$ \t", " \t", // U,V,W,X " \t", " \t", "Tool \t", "Value \t", // Y,Z,a,b "Cost \t", "Lifetime\t", "Price \t", "1/L \t", // c,d,e,f "N-1/L \t", "$N-1/L \t", "$/L \t", "sum-1$/L\t", // g,h,i,j "P0min \t", " \t", " \t", " \t", // k,l,m,n " \t", " \t", " \t", " \t", // o,p,q,r " \t", " \t", " \t", " \t", // s,t,u,v " \t", " \t", " \t", " \t" // w,x,y,z }; /* constructor creates Stringbuffer */ public ItemTextFormatter( ItemEconomy e ) { int n; String s; economy = e; mode = 0; // display table of men and their associated variables /* make up a row with blank fields for each man */ b = new StringBuffer(0); for ( n = 0; n <= maxfields; n++ ) { indent[n] = 9 * n; // distance to indent b.append(" "); } b.append("\n"); s = b.toString(); rowlen = b.length(); /* add blank rows for each label */ for ( n = 1; n < rows; n++ ) { b.append( s ); } } public void setDisplayOrder( String s ) { textorder = s; } public void setMode( int m ) { mode = m; } public void textDisplay( TextArea t ) { t.setText( b.toString() ); } /* make double into 8-char string with leading tab */ public String makeString( double v ) { int decimal, i, digits; boolean leadingzero, debug; char ch; StringBuffer s = new StringBuffer(); v = v + .000005; leadingzero = true; digits = 0; if ( v < 0.0 ) { s.append('-'); digits++; v = Math.abs(v); } // set number of decimal places by d >.0001 for ( double d = 100000; d > .001; d = d * 0.1 ) { decimal = (int)( v / d ); if ( (decimal != 0) || ( d == 1 ) ) leadingzero = false; v = v - (double)decimal * d; // because v % d didn't work as expected. if ( !leadingzero ) { ch = (char)( 48 + decimal ); digits++; s.append( ch ); if ( d == 1.0 ) s.append('.'); } if ( digits > 5 ) break; } while ( s.length() < 8 ) { s.append(' '); } s.append("\t"); return( s.toString() ); } /* make int into 8-char string with trailing tab */ public String makeString( int v ) { int decimal, i, digits; boolean leadingzero; char ch; StringBuffer s = new StringBuffer(); leadingzero = true; digits = 0; if ( v < 0 ) { s.append('-'); digits++; v = Math.abs(v); } for ( int d = 100000; d > 0; d = d/10 ) { decimal = v / d ; if ( decimal != 0 ) leadingzero = false; v = v % d; if ( !leadingzero || (d == 1) ) { ch = (char)( 48 + decimal ); s.append( ch ); digits++; } if ( digits > 5 ) break; } while ( s.length() < 8 ) { s.append(' '); } // fill out to 8 chars s.append("\t"); return( s.toString() ); } /* put double into StringBuffer field */ public double setField( int man, int field, double v ) { Double dbl; String s; int len, bpos; char ch; double value; s = makeString( v ); len = s.length(); bpos = (field * rowlen) + indent[man]; if ( editOffset == 0 ) { overwriteString( bpos, s ); // no editing has been done value = v; } else { if ( ( bpos ) != editOffset ) { overwriteString( bpos, s ); // editing not done here value = v; } else { s = ""; // edited field retrieved here bpos = editOffset; for ( int i = 0; i < len; i++ ) { s = s + b.charAt( bpos++ ); } try { dbl = Double.valueOf( s ); //...and converted to double value = dbl.doubleValue(); } catch( Exception e ) { value = v; } System.out.print( " edited double = " + s + " " ); } } return( value ); } /* put integer into StringBuffer field */ public int setField( int man, int field, int v ) { String s; int len, bpos; char ch; int value; s = makeString( v ); len = s.length(); bpos = (field * rowlen) + indent[man]; if ( editOffset == 0 ) { overwriteString( bpos, s ); // no editing has been done value = v; } else { if ( ( bpos ) != editOffset ) { overwriteString( bpos, s ); // editing not done here value = v; } else { s = ""; // edited field retrieved here bpos = editOffset; for ( int i = 0; i < len; i++ ) { s = s + b.charAt( bpos++ ); } try { value = Integer.parseInt( s ); // ...and converted to int } catch( Exception e ) { value = v; } System.out.print( " edited integer = " + s + " " ); } } return( value ); } /* put 6-char string into StringBuffer field */ public String setField( int man, int field, String v ) { String s, value; int len, bpos; char ch; bpos = (field * rowlen) + indent[man]; len = v.length(); if ( editOffset == 0 ) { overwriteString( bpos, v ); // no editing has been done value = v; } else { if ( ( bpos ) != editOffset ) { overwriteString( bpos, v ); // editing not done here value = v; } else { s = ""; // edited field retrieved here bpos = editOffset; for ( int i = 0; i < len; i++ ) { s = s + b.charAt( bpos++ ); } value = s; System.out.print( " edited string = " + s + " " ); } } return( value ); } /* overwrite string at Stringbuffer offset position */ public String overwriteString( int offset, String s ) { int len, bpos; char ch; len = s.length(); bpos = offset; for ( int i = 0; i < len; i++ ) { ch = s.charAt(i); b.setCharAt(bpos++, ch); } return( s ); } // check if main textarea has been edited, and if it has been // copy the edit into Stringbuffer b, and return offset into b. int checkTextEdited( TextArea t ) { String s; s = t.getSelectedText(); editOffset = t.getSelectionStart(); if ( editOffset > 0 ) { overwriteString( editOffset, s ); System.out.println( s + " at offset " + editOffset ); } return( editOffset ); } /* put data into top StringBuffer fields */ public void setTextDisplay( TextArea ta ) { String stx = "$s -" + Integer.toString( economy.Tx ) + "-\t"; int row; row = 0; setField( 0, row, "Day \t" ); setField( 1, row, economy.day ); setField( 2, row, "Nmen \t" ); setField( 3, row++, economy.nmen ); setField( 0, row, stx ); setField( 1, row, economy.findTotalMoney() ); setField( 2, row, "UI% \t" ); setField( 3, row++, economy.ui ); setField( 0, row, "%Ipred \t" ); setField( 1, row++, 100.0 * economy.predictMeanIdleness() ); } /* put all data into StringBuffer fields of main textarea */ public void setSwitchTextDisplay( TextArea ta ) { int row, col, charindex, item, s, t= 0; int alphabet = 26; char A = 'A'; char a = 'a'; int uppercase = (int)A; int lowercase = (int)a; double b; String salive = "Alive \t"; String sdead = "Dead \t"; checkTextEdited( ta ); for ( col=0; col<=maxfields; col++) { if ( col <= economy.nmen ) { if ( col > 0 ) t = economy.m[col].shoptool; for ( row=0; row<=15; row++ ) { if ( row < textorder.length() ) { item = -1; charindex = (int)textorder.charAt(row); if ( charindex >= uppercase ) { if ( charindex >= lowercase ) { item = charindex - lowercase + alphabet; } else { item = charindex - uppercase; } } } else { item = -1; } if ( col == 0 ) { if ( item >= 0 ) { setField( 0, row, title[item] ); } } else switch( item ) { case -1: break; case 0: setField( col, row, col ); break; case 1: // setField( col, row, economy.m[col].fatstock ); if ( economy.m[col].alive ) { setField( col, row, "Alive \t" ); } else { setField( col, row, "Dead \t" ); } break; case 2: setField( col, row, economy.m[col].avIdleness ); break; case 3: economy.m[col].o_stock[economy.Tx] = setField( col, row, economy.m[col].o_stock[economy.Tx] ); break; case 4: setField( col, row, economy.m[col].findShortages() ); break; case 5: economy.m[col].toolPrice[0] = setField( col, row, economy.m[col].toolPrice[0] ); break; case 6: economy.m[col].shopMaxPrice = setField( col, row, economy.m[col].shopMaxPrice ); break; case 7: economy.m[col].toolPrice[t] = setField( col, row, economy.m[col].toolPrice[t] ); break; case 8: economy.m[col].shopMinPrice = setField( col, row, economy.m[col].shopMinPrice ); break; case 9: economy.m[col].setShopStock ( setField( col, row, economy.m[col].getShopStock() ) ); break; case 10: economy.m[col].stockTarget[t] = setField( col, row, economy.m[col].stockTarget[t] ); break; case 11: economy.m[col].shoptool = setField( col, row, t ); break; case 12: setField( col, row, economy.ts.getToolValue( 0, t ) ); break; case 13: setField( col, row, economy.ts.getUntooledCost( t ) ); break; case 14: setField( col, row, economy.ts.getToolLifetime( 0, t ) ); break; case 15: setField( col, row, economy.m[col].useThruput[ economy.m[col].shoptool ] ); break; case 16: setField( col, row, economy.m[col].saleThruput[ economy.m[col].shoptool ] ); break; case 17: setField( col, row, economy.m[col].useThruput[0] ); break; case 18: setField( col, row, economy.m[col].allToolSales ); break; case 19: setField( col, row, economy.m[col].allToolPurchases ); break; case 20: setField( col, row, economy.m[col].allLabourSales ); break; case 21: setField( col, row, economy.m[col].allLabourPurchases ); break; case 22: setField( col, row, economy.m[col].idealIncome ); break; case 26: setField( col, row, t ); break; case 27: setField( col, row, economy.ts.toolValue[ t ] ); break; case 28: setField( col, row, economy.ts.toolCost[ t ] ); break; case 29: setField( col, row, economy.ts.toolLifetime[ t ] ); break; case 30: s = economy.findToolSeller(t); setField( col, row, economy.m[s].toolPrice[t] ); break; case 31: setField( col, row, 1.0 /economy.ts.toolLifetime[ t ] ); break; case 32: setField( col, row, (double)(economy.nmen-1) / economy.ts.toolLifetime[ t ] ); break; case 33: s = economy.findToolSeller(t); setField( col, row, ( (double)(economy.nmen-1) * economy.m[s].toolPrice[ t ] ) / economy.ts.toolLifetime[ t ] ); break; case 34: s = economy.findToolSeller(t); setField( col, row, ( economy.m[s].toolPrice[t] ) / economy.ts.toolLifetime[ t ] ); break; case 35: b = 0.0; for ( int tool=1; tool<=economy.ntools; tool++ ) { s = economy.findToolSeller( tool ); if ( s != col ) { b += economy.m[s].toolPrice[tool] / economy.ts.toolLifetime[ tool ]; } } setField( col, row, b ); break; case 36: setField( col, row, economy.m[col].avProductionCost[0] ); break; default: break; } } } } } int setField( int n ) { System.out.print( n ); return( 0 ); } } /*********** moving graph canvas *****************************************/ class ItemGraphCanvas extends Canvas { Dimension fielddimension; Image fieldImage; Graphics fieldGraphics; int day; int nstreams = 6; double lasty[] = new double[nstreams]; double nexty[] = new double[nstreams]; String streamLabel[] = new String[nstreams]; int graph_height = 100; int graphymax = 100; boolean started; Font font; FontMetrics fm; int redLetterDay; String ylabel = new String(); // Constructor allows access to Field objects by this class public ItemGraphCanvas() { super(); for ( int n = 0; n < nstreams; n++ ) { lasty[n] = -100.0; nexty[n] = -100.0; streamLabel[n] = " "; } ylabel = "100"; day = 0; started = false; redLetterDay = -1; font = new Font( "Helvetica", Font.PLAIN, 12 ); } public void addStream() { nstreams++; } public void removeStream() { nstreams--; } public void setStreamLabel( int stream, String s ) { streamLabel[stream] = s; } public void setYscale( int ymax ) { graphymax = ymax; ylabel = Integer.toString( ymax ); } public void stop() { fieldGraphics = null; fieldImage = null; } public void redraw() { repaint(); } // update calls paint(), otherwise clears the screen. public void update(Graphics g) { paint(g); } public void paint(Graphics g) { int n; Dimension d = getSize(); int sideband = 25; int lowband = 15; //Create the offscreen graphics context, if no good one exists. if ( (fieldGraphics == null) ) { fieldImage = createImage(d.width, graph_height + lowband); fieldGraphics = fieldImage.getGraphics(); fieldGraphics.setColor(Color.black); fieldGraphics.fillRect(0, 0, d.width, graph_height + lowband); fieldGraphics.setFont( font ); g.drawImage(fieldImage, 0, 0, this); } fm = fieldGraphics.getFontMetrics( font ); if ( started ) { /* move image 1 pixel leftward */ fieldGraphics.setPaintMode(); fieldGraphics.copyArea(1,0, d.width-sideband, graph_height+lowband-1, -1, 0 ); /* rub out unmoved vertical line */ fieldGraphics.setColor(Color.black); fieldGraphics.fillRect(d.width-sideband-1, 0, d.width-1, graph_height+lowband); /* add righthand text */ fieldGraphics.setColor(Color.lightGray); fieldGraphics.drawString( ylabel, d.width-sideband+1, 10 ); fieldGraphics.drawString( "0", d.width-sideband/3-1, graph_height-1 ); /* draw horizontal gridlines */ for ( n = graph_height/4; n <= graph_height; n = n + graph_height/4 ) { fieldGraphics.setColor(Color.darkGray); fieldGraphics.drawLine( d.width-sideband-2, n, d.width-sideband-1, n ); } /* draw vertical gridlines and day numbers */ String s; if ( (day % 100) == 0 ) { fieldGraphics.setColor(Color.darkGray); fieldGraphics.drawLine( d.width-sideband-1, 0, d.width-sideband-1, graph_height ); s = Integer.toString(day); fieldGraphics.setColor(Color.lightGray); fieldGraphics.drawString( s, d.width-sideband-fm.stringWidth(s)-1, graph_height+lowband-1 ); } /* draw red vertical line to show event */ if ( redLetterDay >= 0 ) { fieldGraphics.setColor(Color.red); fieldGraphics.drawLine( d.width-sideband-1, 0, d.width-sideband-1, graph_height ); s = Integer.toString(redLetterDay); fieldGraphics.drawString( s, d.width-sideband-fm.stringWidth(s)-3, fm.getAscent() + 1 ); } /* draw graph lines and labels at right edge of graph */ for ( n = nstreams-1; n >= 0; n-- ) { fieldGraphics.setColor(Color.orange); if ( n==0 ) fieldGraphics.setColor(Color.white); if ( n==1 ) fieldGraphics.setColor(Color.red); if ( n==2 ) fieldGraphics.setColor(Color.green); if ( n==3 ) fieldGraphics.setColor(Color.blue); if ( n==4 ) fieldGraphics.setColor(Color.yellow); if ( n==5 ) fieldGraphics.setColor(Color.lightGray); fieldGraphics.drawLine( d.width-sideband-2, rescale(lasty[n]), d.width-sideband-1, rescale( nexty[n] ) ); fieldGraphics.drawString( streamLabel[n], d.width-sideband+2, rescale( nexty[n] ) ); } //Paint the image onto the screen. g.drawImage(fieldImage, 0, 0, this); } else { started = true; fieldGraphics.setColor(Color.black); fieldGraphics.fillRect(0, 0, d.width, graph_height); } for ( n = 0; n < nstreams; n++ ) lasty[n] = nexty[n]; } // rescale y value int rescale( double yvalue ) { int rsv; double gph = (double)graph_height; double yv = (double)yvalue; double gymax = (double)graphymax; double yl = gph - yv * ( gph / gymax ); rsv = (int)yl; return( rsv ); } }