"Market balancing price model"

"smalltalk version 1.9"

"6/1/95"

"copyright 1995, Richard E. Hawkins"
"all rights reserved"




Object subclass: #Agent
       instanceVariableNames: 'cash doneForDay inventory id '
       classVariableNames: 'lastID hour date nHours World nCostToShop'
       poolDictionaries: ''
       category: nil !

Agent comment: 'I am the root agent class for AL models!'!

!Agent class methodsFor: 'instance creation'!

    classInit: modelSpecs

	"how boring"
	!    

new

    |r|

    r := super new.
    r init.

    ^r

	!

newID
    "this returns a new, unique, id number"

    lastID := lastID + 1.

    ^lastID	


	! !


!Agent  methodsFor: 'instance initialization'!

init
    

    id := (Agent newID ).
    cash := 0.
    inventory := 0    
	"   'Whee!  ive been inited' printNl"

	! !


!Agent  methodsFor: 'methods for variable acces'!

tellID
    ^id
	!

tellInv
    ^inventory
	!

tellCash
    ^cash

	!

    setCash: newCash
	cash := newCash.
	!

perish
    inventory := 0
	!

    addCash: howMuch
	cash := cash + howMuch
	    !

newDay
    self perish .
    doneForDay = false




	! !



"the person will be the dominant agent type"




Agent  subclass: #Person
       instanceVariableNames: ''
       classVariableNames: 'lastID nDailyCash initYet '
       poolDictionaries:''
       category: nil !




Person  comment: 'I am a person, and I live in Hawkinsville.'!

!Person   class methodsFor: 'instance creation'!



new

    |r|

    (initYet = nil) 
	ifTrue: 
	    [    nDailyCash := 20000.
		 initYet := true].
    r := super new.
    r init.
    ^r
	

	! !

!Person methodsFor: 'instance initialization'!

init
    
    

    ^ super init
	! !







"!Person methodsFor: 'methods for daily initialization'!"


"nothing here, really"


"! !"


" *** end of class Person *** "


Person  subclass: #Merchant
	instanceVariableNames: 'myPrices myTransactions mySales myLostTransactions myLostSales gHrTolerance gHrCh0 gHrCh1 gHrCh2'
	classVariableNames: 'nDailyInventory  lastID hChanges dChanges'
	poolDictionaries: ''
	category: nil !


Merchant comment: 'I am a Merchant, and I live in Hawkinsville.'!

!Merchant class methodsFor: 'instance creation'!

    classInit: modelSpecs
	lastID :=0.
	nDailyInventory := (modelSpecs tellDailyInventory) 
	    !

new

    |r|

    r := super new.
    r init.
    ^r
	

	! !



!Merchant methodsFor: 'instance initialization'!

    init: modelSpecs

	super init.

	"an array to keep track of prices by hour"
	myPrices := (Array new: 5)   "nHours"
	    ! !




!Merchant methodsFor: 'methods for daily initialization'!


newDay
    
    | temp | 
    super NewDay. "get general agent newday stuff"
    
    inventory = nDailyInventory.
    
    "put the adjusted closing price into a temporary spot"
    temp :=  myPrices at: (nHours+1).
    
    "flush the data "

    [:array | array atAllPut: 0 ] 

	myPrices myTransactions mySales myLostTransactions myLostSale


	! !





"!Merchant methodsFor: 'methods for variable access2'!"
!Merchant methodsFor: 'methods for general behavior'!



tellPrice

    ^myPrices at: hour

!
 
endHour

    self setPrice.
	super endHour
!

endOfDay

    "end of day merchant behavior"

"compile the days information"

"this will compile the data for each log"
"additionally, it will compile to the master log, whose"
"identity is known to the class"
    [:dayLog | dayLog sumUp ] 
	myPrices myTransactions mySales myLostTransactions myLostSale.

	self setPrice.
	super endOfDay
!

setPrice
    (hour = 'endOfDay')
	ifTrue: [self setPriceDay]
	ifFalse: [self setPriceHour].

!

setPriceHour

|dev aDev sDev change|

    dev := (self myDev).
    aDev := (dev abs).
    (dev = 0)
	ifTrue: [sDev := 0]
	ifFalse: [sDev := dev/aDev].
    (aDev > gHrTolerance) ifTrue:
	["stuff is selling at the wrong speed; change price"
	 change := sDev * (gHrCh0 + gHrCh1*aDev + gHrCh2*aDev*aDev).
	 hChanges inc.	 ]
			 ifFalse: [change := 0].
    myPrices setNextHour: change.
!

gHrTolerance gHrCh0 gHrCh1 gHrCh2     

!

setPriceHour
|dev change|

dev := (self myDev)

d

!
myDev
"write this!!! ***"



	! !











" *** end of class Merchant *** "






"The world is of course populated with Consumers"


Person  subclass: #Consumer
	instanceVariableNames: 'trysLeft'
	classVariableNames: 'nDailyCash  lastID sinboy nTotMerchants yestPrice'
	poolDictionaries: ''
	category: nil !





Consumer  comment: 'I am a Consumer, and I live in Hawkinsville.'!

!Consumer class methodsFor: 'instance creation'!

    classInit: modelSpecs
	lastID :=0.
	nDailyCash := (modelSpecs tellDailyCash) 
	    !
new

    |r|

    r := super new.
    r init.
    ^r
	

	! !

!Consumer methodsFor: 'instance initialization'!

init
    
    

    ^ super init
	! !


!Consumer methodsFor: 'general behavior'!
    "seller howMuch price"
smile

!
at: key  put: value
    | index assoc |
    "index := self findKeyIndex: key."
    
     
     
!



buyStuff:  howMany at: price from: myMerch

    "make sure he can afford it"
    |iGot  quant|

    

    (cash < (price * howMany) )
	ifTrue: [ quant  := (cash / price) ]
	ifFalse: [ quant := howMany copy].

    iGot := ( myMerch sell: quant).
    
    inventory := inventory + iGot.
    
    cash := cash - (myMerch getPaid: (iGot * price)).
    ^ iGot

		    
		    
	!


newDay
    
    super newDay.
    cash := nDailyCash.
    "give us this day. . ."
    World rShopSchedule: (self) 
	"schedule me to shop at a random time"

	!



shop

    "it is definitely time to shop"
    "note that the c++ version called him daily and he checked to see if"
    "  it was time to shop"
    "and for that matter, this section could be probably halved in lenght;"
    " this is essentially the c++ code"


    | myMerch price demand yestPrDemand |    

    myMerch := ( World randMerch ).
    
    price :=  (myMerch tellPrice ).
    demand := (self myDemand: myMerch price) - inventory.
    (demand < 0) ifTrue: [demand := 0].
    
    "is it worth buying here?"
    yestPrDemand = self demand: yestPrice.

    ( (price > (yestPrice + nCostToShop/yestPrDemand)) &
	  (hour < nHours) & (trysLeft > 0) & (demand > 0) )
	ifTrue: "this guy is too expensive, try next hour"
	    [ self abortShop ]
	ifFalse: [self buyStuff:  demand at: price from: myMerch ].

    (inventory < demand)
	ifTrue: [doneForDay := true]



	!

    myDemand:  price
	"the consumer's demand at the given price"
	"perhaps this can inherit a code segment from modelSpecs"
	
	| dem |

    (date < 10)
	ifTrue: [dem := 200 - price]
	ifFalse: [dem := 200 - price + 25 * sinboy].

    ^ dem
	!



abortShop
    cash := cash - nCostToShop.
    trysLeft := trysLeft - 1.
    World shopReSchedule: self.
    ^ True
	

! !


"the DayLog class is to keep track of & total hourly transactions"

Array  subclass: #DayLog

	instanceVariableNames: 'carryOver total'
	classVariableNames: ''
	poolDictionaries: ''
	category: nil !



DayLog  comment: 'DayLogs are extended arrays with also  endOfDay & total elements'

!DayLog class methodsFor: 'instance creation'!


new

    |r|

    r := super new.
    r init.
    ^r
	

	! !

!DayLog methodsFor: 'instance initialization'!

init
    ^ super init
	! !

!DayLog methodsFor: 'general behavior'!

endOfDay

 "   [:array | array atAllPut: 0 ] 

	myPrices myTransactions mySales myLostTransactions myLostSale
"
"sum the elements into Total"
! !