Skip to content

Commit

Permalink
Merge pull request #710 from olekscode/500-occupants-should-be-occupa…
Browse files Browse the repository at this point in the history
…ntsAt-

500 occupants should be occupants at
  • Loading branch information
olekscode committed Aug 10, 2023
2 parents 69d5e53 + 9afe84a commit 40850d8
Show file tree
Hide file tree
Showing 19 changed files with 369 additions and 168 deletions.
4 changes: 2 additions & 2 deletions repository/Cormas-Core/CMAbstractModel.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -2711,7 +2711,7 @@ CMAbstractModel >> pickCellWithoutAny: aClass [
Example2: self pickCellWithoutAny: #Building"
^ self
pickCellConstrainedBy: [ :cell | (cell occupantsAt: aClass) isEmpty ]
pickCellConstrainedBy: [ :cell | (cell occupantsOfClass: aClass) isEmpty ]
]
{ #category : #'accessing - entities' }
Expand Down Expand Up @@ -2768,7 +2768,7 @@ CMAbstractModel >> pickUnoccupiedCell [
"Purpose: return a random cell not occuppied of the grid
Return Value: a cell"
^ self pickCellConstrainedBy: [ :cell | cell noOccupant ]
^ self pickCellConstrainedBy: [ :cell | cell hasNoOccupants ]
]
{ #category : #printing }
Expand Down
18 changes: 9 additions & 9 deletions repository/Cormas-Core/CMArcEntity.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -225,12 +225,12 @@ CMArcEntity >> initFrom: initNode to: endNode [
CMArcEntity >> initFromCell: startCell toCell: endCell [

| previousNodes initNode endNode |
previousNodes := startCell occupants: self nodeType name.
previousNodes := startCell occupantsOfClassNamed: self nodeType name.
previousNodes isEmpty
ifTrue: [initNode := self newNode "initNode isMovedTo: startCell"]
ifFalse: [initNode := previousNodes first].
self startNode: initNode.
previousNodes := endCell occupants: self nodeType name.
previousNodes := endCell occupantsOfClassNamed: self nodeType name.
previousNodes isEmpty
ifTrue: [endNode := self newNode "endNode isMovedTo: endCell"]
ifFalse: [endNode := previousNodes first].
Expand Down Expand Up @@ -282,8 +282,8 @@ CMArcEntity >> isMovedFrom: startCell to: endCell [
self moveStartNodeTo: startCell.
patch := startCell.
self moveStopNodeTo: endCell.
(startCell occupants: self class name) add: self.
(endCell occupants: self class name) add: self.
(startCell occupantsOfClassNamed: self class name) add: self.
(endCell occupantsOfClassNamed: self class name) add: self.
alreadySituated_start
ifTrue: [ self halt.
self flag:#TODO.
Expand All @@ -310,7 +310,7 @@ CMArcEntity >> isMovedTo: startCell [
alreadySituated_start := self isSituated. "Log the movement"
startCell spaceModel logMovementOf: self from: patch to: startCell.
self moveStartNodeTo: startCell.
(startCell occupants: self class name) add: self.
(startCell occupantsOfClassNamed: self class name) add: self.
stopNode patch ifNil: [ ^ nil ].
alreadySituated_start
ifTrue: [ "self halt."
Expand Down Expand Up @@ -371,13 +371,13 @@ CMArcEntity >> leaveWhileMoving: isBeingMoved [
patch := nil.
startNode isNil
ifFalse: [ startNode patch isNil
ifFalse: [ (startNode patch occupants: self class name)
ifFalse: [ (startNode patch occupantsOfClassNamed: self class name)
remove: self
ifAbsent: [ ] ].
startNode removeArc: self ].
stopNode isNil
ifFalse: [ stopNode patch isNil
ifFalse: [ (stopNode patch occupants: self class name)
ifFalse: [ (stopNode patch occupantsOfClassNamed: self class name)
remove: self
ifAbsent: [ ] ].
stopNode removeArc: self ].
Expand Down Expand Up @@ -435,7 +435,7 @@ CMArcEntity >> newIncomingArcFromCell: initCell [
"creates and add a new instance of Arc from initCell until my startNode. If there is no node on initCell, it creates it, otherwise it uses the current node already located on initCell"

| nodes initNode |
nodes := initCell occupants: self nodeType name.
nodes := initCell occupantsOfClassNamed: self nodeType name.
nodes isEmpty
ifTrue:
[initNode := self newNode.
Expand Down Expand Up @@ -468,7 +468,7 @@ CMArcEntity >> newOutgoingArcToCell: endCell [
"creates and add a new instance of Arc from my stopNode to another cell by creating a new instance of stopNode on endCell if there is none or using the current node if already located on endCell"

| endNode endNodes |
endNodes := endCell occupants: self nodeType name.
endNodes := endCell occupantsOfClassNamed: self nodeType name.
endNodes isEmpty
ifTrue:
[endNode := self newNode.
Expand Down
2 changes: 1 addition & 1 deletion repository/Cormas-Core/CMLocatedObject.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Example: self isMovedTo: self patch neighbourN"
alreadySituated := self isSituated.
self leaveWhileMoving: true.
self patch: aSpatialEntity.
(self patch occupants: self class name) add: self.
(self patch occupantsOfClassNamed: self class name) add: self.
alreadySituated
ifFalse:
[ "the agent is arriving on the grid for the first time, the SpaceInterfaces should be aware"
Expand Down
2 changes: 1 addition & 1 deletion repository/Cormas-Core/CMNodeEntity.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ CMNodeEntity >> checkToReplaceNode [
| sameNodes |
self replaceNodeWhileMoving ifFalse: [^nil].
patch ifNil: [^nil].
sameNodes := (self patch occupants: self class) copy.
sameNodes := (self patch occupantsOfClassNamed: self class) copy.
sameNodes
remove: self
ifAbsent: [nil].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ Class {
{ #category : #'environment - sensing - space' }
CMNonSquaredSpaceNeighbourhood >> nearestEmptyCellFor: aCMAgentLocation [

^ aCMAgentLocation nearestCellVerifying: [:p | p noOccupant]
^ aCMAgentLocation nearestCellVerifying: [:p | p hasNoOccupants]
]
143 changes: 55 additions & 88 deletions repository/Cormas-Core/CMSpatialEntity.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ CMSpatialEntity class >> theOccupants_default [
^Dictionary new
]

{ #category : #adding }
CMSpatialEntity >> addOccupant: anObject [

(self theOccupants at: anObject class name
ifAbsentPut: [ OrderedCollection new ]) add: anObject
]

{ #category : #'environment - sensing - space' }
CMSpatialEntity >> allLayersTo: radius [
"returns a collection (collResult) of layers :
Expand Down Expand Up @@ -156,7 +163,7 @@ Return value: <Collection(AgentLocation & ObjectLocation)>"
^ collec
]

{ #category : #'star testing' }
{ #category : #testing }
CMSpatialEntity >> belongsToAggregate: aSpatialEntity [
"Purpose: tests if the receiver belongs to a higher level spatial entity, even if theCSE is nil.
This method is valid whatever the aggregate level and even if theCSE is nil. It will return 'true' if the receiver is a component of a component of aSpatialEntity
Expand Down Expand Up @@ -306,15 +313,39 @@ Return value: <Collection(SpatialElementEntity)>"
^self spaceModel elementaryEntities
]

{ #category : #'star testing' }
CMSpatialEntity >> hasOccupantType: locatedEntityName [
{ #category : #testing }
CMSpatialEntity >> hasNoOccupants [

^ self hasOccupants not
]

{ #category : #testing }
CMSpatialEntity >> hasNoOccupantsExcept: anObject [

self theOccupants ifNil: [ ^ true ].

^ self theOccupants allSatisfy: [ :list |
(list copyWithout: anObject) isEmpty ].
]

{ #category : #testing }
CMSpatialEntity >> hasOccupants [

self theOccupants ifNil: [ ^ false ].

^ self theOccupants values anySatisfy: [ :list |
list isNotEmpty ].
]

{ #category : #testing }
CMSpatialEntity >> hasOccupantsOfClass: aClass [

"Purpose: test if there is an occupant of a given type.
Argument: locatedEntityName = <Symbol | AgentLocation | ObjectLocation>
Return value: <Boolean>
Example: self hasOccupantType: #Tree"

^ (self occupantsAt: locatedEntityName) isNotEmpty
^ (self occupantsOfClass: aClass) isNotEmpty
]

{ #category : #accessing }
Expand Down Expand Up @@ -369,7 +400,7 @@ CMSpatialEntity >> interestingDetails [
}
]

{ #category : #'star testing' }
{ #category : #testing }
CMSpatialEntity >> isComponentOf: aSpatialEntity [
"Purpose: tests if the receiver belongs to the components of a given compound spatial entity
It will return 'false' if the receiver is a component of a component of aSpatialEntity (cf. belongsToAggregate:)
Expand Down Expand Up @@ -530,7 +561,7 @@ Argument: range = <Integer>
Return value: <Collection(SpatialEntity)>"

^self
nearestNeighborsVerifying: [:n | n noOccupant]
nearestNeighborsVerifying: [ :n | n hasNoOccupants ]
withinRadius: range
]

Expand Down Expand Up @@ -666,15 +697,13 @@ Example: self nearestNeighborsWithMaxOf: #water withinRadius: 5"
]

{ #category : #'environment - sensing - space' }
CMSpatialEntity >> nearestNeighborsWithoutAny: locatedEntityName withinRadius: range [
CMSpatialEntity >> nearestNeighborsWithoutAny: aClass withinRadius: range [
"Purpose: returns the nearest spatial entities within a given radius and without any occupant of a given type.
Arguments: range = <Integer>
locatedEntityName = <Symbol | Class>
Return value: <Collection(SpatialEntity)>
Example: self nearestNeighborsWithoutAny: #Tree withinRadius: 5 "

^self
nearestNeighborsVerifying: [:p | p noOccupantType: locatedEntityName]
nearestNeighborsVerifying: [:p | (p hasOccupantsOfClass: aClass) not ]
withinRadius: range
]

Expand Down Expand Up @@ -729,90 +758,30 @@ CMSpatialEntity >> neighboursMaxOf: aMagnitudeName [
amongObjects: self neighbourhood
]

{ #category : #'star testing' }
CMSpatialEntity >> noOccupant [

"Purpose: tests if there is no occupant of any kind.
Return value: <Boolean>"

| test |
test := true.
self theOccupants notNil ifTrue: [
self theOccupants valuesDo: [ :list |
list isEmpty ifFalse: [ test := false ] ] ].
^ test
]

{ #category : #'star testing' }
CMSpatialEntity >> noOccupantBut: anAgent [

"Purpose: tests if there is no occupant of any kind, excepted anAgent.
Useful from an agent perspective, to test if there are other agents on the cell: self patch noOccupantBut: self.
Return value: <Boolean>"

| test |
test := true.
self theOccupants notNil ifTrue: [
self theOccupants valuesDo: [ :list |
list isEmpty ifFalse: [
(list includes: anAgent) ifFalse: [ test := false ] ] ] ].
^ test
]
{ #category : #'environment - sensing - agents' }
CMSpatialEntity >> occupantsOfClass: aClass [

{ #category : #'star testing' }
CMSpatialEntity >> noOccupantType: locatedEntityName [
"Purpose: tests if there is no occupant of given type.
Argument: locatedEntityName = <Symbol | AgentLocation | ObjectLocation>
Return value: <Boolean>
Example: self noOccupantType: #Tree"
"Purpose: returns all the entities of a given type located there
Note that the instances of subclasses ARE CONSIDERED by this method
Return value: <Collection(AgentLocation & ObjectLocation)>"

aClass ifNil: [ ^ OrderedCollection new ].

^(self occupantsAt: locatedEntityName) isEmpty
^ aClass withAllSubclasses flatCollect: [ :eachClass |
self theOccupants
at: eachClass name
ifAbsent: [ OrderedCollection new ] ].
]

{ #category : #'environment - sensing - agents' }
CMSpatialEntity >> occupants: aClassOrClassName [
CMSpatialEntity >> occupantsOfClassNamed: aClassName [

"Purpose: returns all the entities of a given class name located there
Argument: aClassOrClassName = <ByteSymbol> or a Cormas Entity Class
Note that the instances of subclasses are NOT considered by this method, contrarily to #occupantsAt: and #occupantsType:
Return value: <Collection(AgentLocation & ObjectLocation)>"

| aClassName |
aClassName := aClassOrClassName isSymbol
ifTrue: [ aClassOrClassName ]
ifFalse: [ aClassOrClassName name ].
^ self theOccupants
at: aClassName
ifAbsentPut: [ OrderedCollection new ]
]

{ #category : #'environment - sensing - agents' }
CMSpatialEntity >> occupantsAt: locatedEntityName [
"Purpose: returns all the entities of a given type located there
Argument: locatedEntityName = <ByteSymbol | AgentLocation | ObjectLocation>
Note that the instances of subclasses ARE CONSIDERED by this method, contrarily to #occupants:
Return value: <Collection(AgentLocation & ObjectLocation)>"

| aClass |
aClass := locatedEntityName isLiteral
ifTrue: [ Smalltalk at: locatedEntityName asSymbol ifAbsent: [ nil ] ]
ifFalse: [ locatedEntityName ].
^ self occupantsType: aClass
]

{ #category : #'environment - sensing - agents' }
CMSpatialEntity >> occupantsType: aClass [
"Purpose: returns all the entities of a given type located there
Argument: locatedEntityName = <AgentLocation | ObjectLocation>
Note that the instances of subclasses ARE CONSIDERED by this method, contrarily to #occupants:
Return value: <Collection(AgentLocation & ObjectLocation)>"

| instances |
instances := OrderedCollection new.
aClass ifNil: [^instances].
aClass withAllSubclasses
do: [:class | instances addAll: (self occupants: class name)].
^instances
aClass := self class environment at: aClassName asSymbol.
^ self occupantsOfClass: aClass
]

{ #category : #accessing }
Expand Down Expand Up @@ -911,16 +880,14 @@ Example: self recursiveNeighbourhood: 5 verifying: [:c | c isClosed not] "
]

{ #category : #'environment - sensing - space' }
CMSpatialEntity >> recursiveNeighbourhood: range withoutAny: locatedEntityName [
CMSpatialEntity >> recursiveNeighbourhood: range withoutAny: aClass [
"Purpose: returns the spatial entities within a given radius and without any occupant of a given type.
Arguments: range = <Integer>
locatedEntityName = <Symbol | Class>
Return value: <Collection(SpatialEntity)>
Example: self recursiveNeighbourhood: 5 withoutAny: #Tree"

^self
recursiveNeighbourhood: range
verifying: [:p | p noOccupantType: locatedEntityName]
verifying: [:p | (p hasOccupantsOfClass: aClass) not ]
]

{ #category : #'initialize-release' }
Expand Down
14 changes: 7 additions & 7 deletions repository/Cormas-Core/CMSpatialEntityElement.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ CMSpatialEntityElement >> coordinates [
"Purpose: Returns the coordinates x and y as a Point instance.
Example: self coordinates dist: (self neighbourNE coordinates)"

spaceModel ifNil: [ ^ nil ].

^ Point
x: self columnNumber
y: self rowNumber
Expand Down Expand Up @@ -581,24 +583,23 @@ Example: self nearestCellWithMaxOf: #sugar"
]

{ #category : #'environment - sensing - space' }
CMSpatialEntityElement >> nearestCellWithoutAny: locatedEntityName [
CMSpatialEntityElement >> nearestCellWithoutAny: aClass [
"Purpose: returns the nearest cell without any occupant of a given type.
If none: returns nil; if more than one at the minimum radius: random selection
Valid only for regular grids (square or hexagonal cells). For polygonal cells, use the generic but slower method #nearestCellVerifying: in super class SpatialEntity
Argument: locatedEntityName = <Symbol | Class>
Return value: <SpatialEntityElement | nil>
Example: self nearestCellWithoutAny: #Tree"

| locations |
^(self spaceModel gridCellShape = #squared
or: [self spaceModel gridCellShape = #hexagonal])
ifTrue:
[locations := self nearestCellsWithoutAny: locatedEntityName.
[locations := self nearestCellsWithoutAny: aClass.
locations isEmpty
ifFalse: [Cormas selectRandomlyFrom: locations]
ifTrue: [nil]]
ifFalse:
[super nearestCellVerifying: [:p | p noOccupantType: locatedEntityName]]
[super nearestCellVerifying: [ :p | (p hasOccupantsOfClass: aClass) not ]]
]

{ #category : #'environment - sensing - space' }
Expand Down Expand Up @@ -644,15 +645,14 @@ Example: self nearestNeighborsWithMaxOf: #water"
]

{ #category : #'environment - sensing - space' }
CMSpatialEntityElement >> nearestCellsWithoutAny: locatedEntityName [
CMSpatialEntityElement >> nearestCellsWithoutAny: aClass [
"Purpose: returns the nearest cells without any occupant of a given type.
Valid only for regular grids (square or hexagonal cells).
Argument: locatedEntityName = <Symbol | Class>
Return value: <Collection(SpatialEntityElement)>
Example: self nearestCellsWithoutAny: #Predator"

^self
nearestNeighborsVerifying: [:p | p noOccupantType: locatedEntityName]
nearestNeighborsVerifying: [:p | (p hasOccupantsOfClass: aClass) not ]
withinRadius: (self spaceModel line max: self spaceModel column)
]

Expand Down
Loading

0 comments on commit 40850d8

Please sign in to comment.