Reputation: 61
I have a model with 5000+ farmers and several factories. Sometimes a new factory is built, at which point I want the factory to do the following:
Create a list with all farmers and then sort that list according to distance of farmer to the factory (from low to high).
I have tried doing this with a table,
ask factory 1 [ask farmers [set distance-to-factory distance myself]]
ask factory 1 [set a table:group-agents farmers [distance-to-factory]]
but then the resulting agentsets are not ordered from low to high or vice versa. Moreover, I want the factory to be able afterwards to ask single agents from the ordered table (or list) to do something:
After ordering the farmers by their distance-to-factory, I want the factory to be able to ask farmers from that list to deliver their goods (i.e. the closest farmer is asked first, but when it has no goods, the second closest farmer is asked and so on).
Your help is much appreciated!
Upvotes: 2
Views: 543
Reputation: 17678
You need to create an agent variable for the factory that stores the list of farmers in distance order. Here is a full example, run it and inspect a factory to convince yourself that it works.
breed [factories factory]
breed [farmers farmer]
factories-own [my-farmers]
to setup
clear-all
create-farmers 100
[ setxy random-xcor random-ycor
set color yellow
set shape "circle"
set size 0.5
]
create-factories 3
[ setxy random-xcor random-ycor
set color red
set shape "house"
set size 2
initialise-factory
]
reset-ticks
end
to initialise-factory
set my-farmers sort-on [distance myself] farmers
end
Look at the initialise-factory procedure. The sort-on
primitive operating on an agentset
returns a list
. And the [distance myself] of ...
is calculating the distance back to the factory (because the factory is doing the asking and is therefore myself
). So the list is sorted by distance
to the factory.
Once you have created the list, you use list procedures (eg the item
primitive) to do the asking specific farmers.
Upvotes: 4
Reputation: 61
There are indeed multiple factories and the distance-to-factory is to the most recently created factory, but the my-farmers list that each factory has doesn't change.
I already used the profiler extension on a previous version of the model and that one was very slow because of every factory asking each farmer every time (once a year) if they had goods:
let closest-farmer (min-one-of farmers with [status = 0] [distance myself])
That is why I thought of every factory creating a list of farmers from closest to furthest, so that factories can run through that list. Below you find a more elaborate piece of code, I hope this helps you to get a better image.
breed [factories factory]
breed [farmers farmer]
globals [
count-down
total-capacity-factories
price-goods
]
farmers-own [
area
goods-per-area
goods
distance-to-factory
status
]
factories-own [
my-farmers
goods-delivered
capacity
revenues-this-year
total-revenues
]
to setup
clear-all
create-farmers 1000 [
setxy random-xcor random-ycor
set area one-of [10 50 100]
set goods-per-area one-of [5 10 15]
set color yellow
set shape "circle"
set size 0.5
]
create-factories 20 [
setxy random-xcor random-ycor
set color red
set shape "house"
set size 2
initialise-factory
]
set market-demand-goods 250000
set total-capacity-factories sum [capacity] of factories
set count-down 11
reset-ticks
end
to go
if count-down = 11 [
change-market-demand
ask farmers [
set status 0
set goods 0
]
]
if count-down = 10 [
ask farmers [
sow-seeds
]
]
if count-down = 5 [
if market-demand-goods - [capacity] of one-of factories > total-capacity-factories [
build-factory
]
]
if count-down = 2 [
ask farmers [
harvest-goods
]
ask factories [
receive-harvested-goods
sell-goods
]
]
set count-down count-down - 1
if count-down = 0 [
set count-down 11
]
end
to initialise-factory
set capacity 10000
ask farmers [
set distance-to-factory distance myself
]
set my-farmers (sort-on [distance-to-factory] farmers)
end
to change-market-demand
let chance random 100
if chance < 33 [
set market-demand-goods market-demand-goods - 50000
]
if chance >= 33 and chance < 66 [
set market-demand-goods market-demand-goods + 10000
]
if chance >= 66 [
set market-demand-goods market-demand-goods + 50000
]
let chance2 random 100
if chance2 < 50 [
set price-goods price-goods + 1
]
if chance2 >= 50 [
set price-goods price-goods - 1
]
end
to sow-seeds
set color brown
end
to build-factory
loop [
if total-capacity-factories >= market-demand-goods [stop]
create-factory 1 [
setxy random-xcor random-ycor
set color red
set shape "house"
set size 2
initialise-factory
set total-capacity-factories (total-capacity-factories + [capacity] of myself
]
end
to harvest-goods
set goods area * goods-per-area
end
to receive-harvested-goods
let i 0
loop [
if goods-delivered >= capacity [stop]
let closest-farmer-with-goods (item i my-farmers)
ifelse [status] of closest-farmer-with-goods = 0 [
set goods-delivered + [goods] of closest-farmer-with-goods
ask closest-farmer-with-goods [
set status "goods-delivered"
]
]
[set i i + 1]
]
end
to sell-goods
set revenues-this-year goods-delivered * price-goods
set total-revenues total-revenues + revenues-this-year
end
Upvotes: 1
Reputation: 61
@JenB, thanks for the help! I also found out that it can be done as follows:
hatch factory 1 [
ask farmers [set distance-to-factory distance myself]
set my-farmers (sort-on [distance-to-factory] farmers)
]
Then I designed the following code for asking from the my-farmers list:
let i 0
loop [
if goods-delivered > capacity [stop]
let closest-farmer-with-goods (item i my-farmers)
ifelse [status] of closest-farmer-with-goods = 0 [ (; aka goods are not delivered yet to another factory)
set goods-delivered + [goods] of closest-farmer-with-goods
]
[set i i + 1] ; *else*
]
But this makes the model quite slow. Do you know how to make this simpler?
Upvotes: 0