take class class aset define aset::new: { _asg \%1.thisaset | (setq \%1.thisaset.cnt 0) (\%1) } define aset>>insert: { if == \find(|\%2|,\m(\%1.thisaset)) 0 { _asg \%1.thisaset \m(\%1.thisaset)\%2| (++ \%1.thisaset.cnt) } (\%1) } define aset>>remove: { if \find(|\%2|,\m(\%1.thisaset)) { _asg \%1.thisaset \freplace(\m(\%1.thisaset),|\%2|,|) (-- \%1.thisaset.cnt) } (\%1) } define aset>>isEmpty { (== 0 \%1.thisaset.cnt) } define aset>>includes: { (> \find(|\%2|,\m(\%1.thisaset)) 0) } define aset>>min { if = 0 \%1.thisaset.cnt return -1 local \&w[] void \fsplit(\m(\%1.thisaset),&w) array sort /numeric \&w (\&w[1]) } define aset>>max { ; if = 0 \%1.thisaset.cnt return 0 local \&w[] (let size \fsplit(\m(\%1.thisaset),&w)) array sort /numeric \&w (\&w[size]) } define aset>>inspect { show mac \%1.thisaset (\%1) } define say { echo \%1 } define randnum { ; \%1 random seed while true { if {\fsexpr(let rd \frandom(\%1))} return \m(rd) } } define aReference { ; \%1 Id return \%1.\frandom(999999)_\frandom(999999) } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; class DiscreteProbability define DiscreteProbability>>defineWeights { ; \%2 anArray } define DiscreteProbability>>next { (if (>= (let r \frandom(100)) 90) 3 (if (>= r 65) 2 1)) } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; class NormalDistribution define NormalDistribution::new: { \%1 setmean: 1.0 deviation: 0.5 } define NormalDistribution>>setmean:deviation: { ; \%2 mean ; \%3 deviation (setq \%1.ND.curTime 0) (setq \%1.ND.mean \%2) (setq \%1.ND.deviation \%3) } define NormalDistribution>>next { ; (++ \%1.ND.curTime (randnum 5)) (++ \%1.ND.curTime \frandom(5)) } define NormalDistribution>>incr { local v1 v2 s u (setq s 1) while >= s 1 { echo \m(s) *** (setq v1 (- (* 2 (randnum 1)) 1)) echo \m(v1) (setq v2 (- (* 2 (randnum 1)) 1)) echo \m(v2) (setq s (+ (* v1 v1) (* v2 v2))) echo \m(s) *** } (setq u (sqrt (/ (log (* -2.0 s)) s)))) (+ \%1.ND.mean (* \%1.ND.deviation v1 u)) } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; class Dictionary define Dictionary::new: { aset new: \%1.DictionarySet (\%1) } define Dictionary>>add:at: { ; \%1 caller ; \%2 item to be added ; \%3 slotid (if (not (\%1.DictionarySet 'includes: \%3)) (. (setq \%1.DictionarySet<\%3> 0 \%1.DictionarySet<\%3> 0) (\%1.DictionarySet 'insert: \%3) ) ) (++ \%1.DictionarySet<\%3>) (let \\\\%i \%1.DictionarySet<\%3>) _asg \%1.DictionarySet<\%3><\%i> {\%2} (\%1) } define Dictionary>>emptyAt: { (if (\%1.DictionarySet 'includes: \%2) (== \%1.DictionarySet<\%2> \%1.DictionarySet<\%2>) 1 ) } define Dictionary>>isEmpty { (\%1.DictionarySet 'isEmpty) } define Dictionary>>getNext: { ; Two iterators and manage the queue of messages (++ \%1.DictionarySet<\%2>) asg \%i \m(\%1.DictionarySet<\%2>) (if (\%1 'emptyAt: \%2) (\%1.DictionarySet 'remove: \%2)) return \%1.DictionarySet<\%2><\%i> } define Dictionary>>minTime { (\%1.DictionarySet 'min) } define Dictionary>>maxTime { (\%1.DictionarySet 'max) } define Dictionary>>includesKey: { (\%1.DictionarySet 'includes \%2) } define Dictionary>>At:Do: { local \%i (let b \%1.DictionarySet<\%2>) incr b (let e \%1.DictionarySet<\%2>) for \%i b e 1 { (\%1.DictionarySet<\%2><\%i> \%3) } } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; class Simulation define Simulation::new: { Dictionary new: \%1.eventQueue (setq \%1.currentTime 0) (\%1) } define Simulation>>add:at: { \%1.eventQueue add: {\%2} at: \%3 (\%1) } define Simulation>>add:next: { (\%1 'add: \%2 'at: (+ \%1.currentTime \%3)) (\%1) } define Simulation>>init { (setq \%1.currentTime 0) (\%1) } define Simulation>>time { (\%1.currentTime) } define Simulation>>maxTime { (\%1.eventQueue 'maxTime) } define Simulation>>proceed { (if (> (setq \%1.currentTime (\%1.eventQueue 'minTime)) 0) (\%1 'processEvent: (\%1.eventQueue 'getNext: \%1.currentTime)) -1 ) } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; class IceCreamStore inherit: Simulation define IceCreamStore::new: { \%1 Simulation::new: ; call super new: (setq \%1.profit 0 \%1.ICS.remainingChairs 10) ((NormalDistribution 'new: '\%1.ICS.arrivalDistribution) 'setMean: 3.0 'deviation: 1.0) DiscreteProbability new: \%1.ICS.scoopDistribution \%1 scheduleArrival ; schedule the first arrival } define IceCreamStore>>processEvent: { ; say {event received at \fsexpr(\%1 'time)} (\%2) \%1 scheduleArrival ; Schedule subsequent arrival } define IceCreamStore>>scheduleArrival { (Customer 'new: (let newCustomer (aReference 'Customer))) if < {\fsexpr(let atime (+ (\%1 'time) (randnum 10)))} 60 { \%1 add: {(\%1 'customerArrival: \m(newCustomer))} at: \m(atime) } } define IceCreamStore>>customerArrival: { echo {Group of size \fsexpr(let size (\%2 'groupSize)) arrives} if < \m(size) \m(\%1.ICS.remainingChairs) { (say '(Take chairs, schedules order)) (-- \%1.ICS.remainingChairs size) \%1 add: {(\%1 'customerOrder: \%2)} next: \fexec(randnum 3) } else { (say '(Find no chairs, leaves)) } (\%1) } define IceCreamStore>>customerOrder: { ; \%2 customer (let size (\%2 'groupSize) numScoops 0 i 0) for i 1 size 1 { (++ numScoops (\%1.ICS.scoopDistribution 'next)) } echo {Group of size \m(size) order \m(numScoops) scoops} echo Profits so far \fsexpr(++ \%1.profit (* numScoops 0.17)) \%1 add: {(\%1 'customerLeave: \%2)} next: \fexec(randnum 5) (\%1) } define IceCreamStore>>customerLeave: { ; \%2 customer echo {Group of size \fsexpr(let size (\%2 'groupSize)) leaves} (++ \%1.ICS.remainingChairs size) _define \%2 ; Garbage collection (\%1) } define IceCreamStore>>reportProfits { echo Total profits are \m(\%1.profit) (\%1) } define IceCreamStore>>scoopsFor: { (let i 0 number 0) for i 1 \%2 1 { (++ number (\%1.ICE.scoopDistribution 'next)) } echo group of \%2 'have' \m(number) scoops (number) } define IceCreamStore>>inspect { echo \v(macro) (\%1) } define IceCreamStore>>run { while true { if {\fsexpr(< (\%1 'proceed) 0)} break if {\fsexpr(> (\%1 'time) \%2)} break } } define IceCreamStore>>runit { while {\fsexpr(< \%2 (\%1 'time))} { \%1 proceed } } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; class Customer define Customer::new: { (setq \%1.groupSize (randnum 15)) (\%1) } define Customer>>groupSize { (\%1.groupSize) } define Customer>>numberOfScoops { (let number (randnum 5)) echo Customer has \m(number) scoop(s) (number) } define Customer>>inspect { echo \%1 \v(macro) (\%1) } echo IceCreamStore new: myStore myStore run 40 echo mystore reportProfits echo