
Object subclass: #Meadow
  instanceVariableNames: 
    'foxes rabbits grasses date '
  classVariableNames: ''
  poolDictionaries: '' !

!Meadow class methods !

example
"create a meadow simulation for several days"
" Meadow example "
| days meadow |
meadow := Meadow initialize.
days := Prompter prompt: 'Run for how many days?' defaultExpression: '10'.
meadow runFor: days.!

initialize
"set up the meadow with 100 units of grass,
25 rabbits and a fox"
|rand meadow grass rabbit fox|
rand := Random new.
meadow := Meadow new.
grass := Prompter prompt: 'How many patches of grass?' defaultExpression: '100'.
rabbit := Prompter prompt: 'How many rabbits?' defaultExpression: '20'.
fox := Prompter prompt: 'How many foxes?' defaultExpression: '2'.

grass timesRepeat:[meadow grasses add: (Grass new
  location: (rand next:720)@(rand next:  340))].

rabbit timesRepeat:[meadow rabbits add: (Rabbit new
  location: (rand next:720)@(rand next:340);
    displayState: true; age: (rand next:5))].

fox timesRepeat:[meadow foxes add: (Fox new
    location: (rand next:720)@(rand next:340);
    displayState: true; age:(rand next: 10))].
^meadow.! !


!Meadow methods !

date
"return the value of the current date
default is 0"
date isNil ifTrue: [self date: 0].
^date!

date: anInteger
"set the value of the current date to be anInteger"
date := anInteger!

display
"clear screen & display all inhabitants"
|field|
field := Form width: Display width height: (Display height - 10).
field displayAt: 0@10 rule: Form over.
'Meadow simulation date:', date printString displayAt: 0@0.
'Number of foxes:', foxes size printString displayAt: 200@0.
'Number of rabbits:', rabbits size printString displayAt: 350@0.
self foxes do:[:each | (each displayState) ifTrue: [each displayAt: each location]].
self rabbits do:[:each | (each displayState) ifTrue: [each displayAt: each location]].
self grasses do:[:each | (each displayState) ifTrue: [each displayAt: each location]].!

foxes
"return the bag containing all foxes"
foxes isNil ifTrue: [self foxes: Bag new].
^foxes!

foxes: aBag
"set the bag containing all foxes"
foxes := aBag!

grasses
"return the bag containing all grasses"
grasses isNil ifTrue: [self grasses: Bag new].
^grasses!

grasses: aBag
"set the bag containing all grasses"
grasses := aBag.!

morning
"add 1 to date and to everyone's age"
self date: self date + 1.
self foxes do: [:each | each age: each age+1].
self rabbits do:[:each | each age: each age+1].
self grasses do:[:each | each age: each age+1].!

rabbits
"return the bag containing all rabbits"
rabbits isNil ifTrue: [self rabbits: Bag new].
^rabbits!

rabbits: aBag
"set the bag containing all rabbits"
rabbits := aBag!

runFor: nSteps
"run simulation for integer nSteps"
nSteps timesRepeat:[self runOneStep]!

runOneStep  |rand|
rand := Random new.
"run simulation one step"
"add 1 to everyone's age"
self morning.
"let grass grow"
self grasses do:[:grass | grass grow].
"let rabbits locate grass, move to it."
self rabbits do:[:rabbit | rabbit moveToPrey: (rabbit locatePrey: grasses)].
"let foxes locate rabbits, move towards them"
self foxes do:[:fox | fox moveToPrey: (fox locatePrey: rabbits)].
"let rabbits die"
self rabbits do:[:rabbit | (rabbit death)
    ifTrue:[rabbits remove: rabbit ifAbsent: nil ]].
"let foxes die"
self foxes do:[:fox | (fox death)
    ifTrue:[foxes remove: fox ifAbsent: nil ]].
"let rabbits give birth."
self rabbits do:[:rabbit | (rabbit birth)
    ifTrue:[rabbit lastBirth: rabbit age.
         rabbits add:(Rabbit new location: rabbit location)]].
"let foxes give birth"
self foxes do:[:fox | (fox birth)
    ifTrue:[ fox lastBirth: fox age.
        foxes add:(Fox new location: fox location)]].

"display final state"
self display! !
