问题
I am creating a program that creates 1,500 "scientists" (turtles), in a world where there are 1500 "disciplines".
I need to assign each turtle a "discipline" as a number between 1-500, and ensure that there are 3 turtles for each discipline.
This means that set(random) isn't appropriate. Is there a primitive I can use?
Nevermind, I think I have figured it out. Does this make sense?
to set-discipline
ask turtles [ set discipline -1 ]
let unassigned turtles
let current 1
while [any? unassigned]
[
ask n-of (min (list group-size (count unassigned))) unassigned
[ set discipline current ]
set current current + 1
set unassigned unassigned with [discipline = -1]
]
end
回答1:
Your code works, but is very... unnetlogoish. while
loops and indexes, in NetLogo, are often a sign that you're not taking full advantage of the capabilities of the language. At the very minimum, I would replace your while
with a foreach
:
ask turtles [ set discipline -1 ]
foreach n-values 500 [ 1 + ? ] [
let unassigned turtles with [ discipline = -1 ]
ask n-of (min (list group-size (count unassigned))) unassigned [
set discipline ?
]
]
You can check the result in the command center with:
observer> print remove-duplicates map [ count turtles with [ discipline = ? ] ] n-values 500 [ 1 + ? ]
[3]
But I would suggest taking it a step further.
Having disciplines just be numbers is a bit limiting. That is, of course, the sort of thing that you would do in a traditional mathematical model. But this is an ABM. And you have all of NetLogo at your disposal. You could make your disciplines... turtles! This would make your model much more flexible. Your disciplines could eventually be heterogeneous: having their own variables, by which they could differ from one another. And I think you'll find that replacing numbers with agents makes code more readable in general.
Here is a full example of what I have in mind:
breed [ scientists scientist ]
scientists-own [ my-discipline ]
breed [ disciplines discipline ]
to setup
clear-all
let nb-scientists 1500
let nb-disciplines 500
let group-size 3
create-scientists nb-scientists [
set my-discipline nobody
]
create-disciplines nb-disciplines [
let unassigned scientists with [ my-discipline = nobody ]
ask n-of (min (list group-size (count unassigned))) unassigned [
set my-discipline myself
]
]
end
You can check that it worked:
observer> setup
observer> print remove-duplicates [ count scientists with [ my-discipline = myself ] ] of disciplines
[3]
But you know what? If it was me, I would take it another step further, and make the relation between a scientist and its discipline an actual NetLogo link
. This way, you could eventually envision a scientist belonging to (gasp!) more than one discipline. Here is what it would look like:
breed [ scientists scientist ]
breed [ disciplines discipline ]
to setup
clear-all
let nb-scientists 1500
let nb-disciplines 500
let group-size 3
create-scientists nb-scientists
create-disciplines nb-disciplines [
let unassigned scientists with [ not any? my-links ]
ask n-of (min (list group-size (count unassigned))) unassigned [
create-link-with myself
]
]
end
Don't you think the code is even nicer this way? And it works:
observer> print remove-duplicates [ count my-links ] of disciplines
[3]
回答2:
What Nicolas said. But consider also this alternate approach:
to test
let disciplines reduce sentence map [(list ? ? ?)] n-values 500 [? + 1]
ask turtles [
set discipline first disciplines
set disciplines butfirst disciplines
]
end
ask
is in random order, so we don't need to shuffle the disciplines
list.
Or, if the turtles don't exist yet and you're free to create them as you go:
to test
let disciplines reduce sentence map [(list ? ? ?)] n-values 500 [? + 1]
foreach shuffle disciplines [
create-turtles 1 [ set discipline ? ]
]
end
In this one, we have to shuffle the list of disciplines, since the turtles are being created in who number order.
来源:https://stackoverflow.com/questions/27301677/assign-each-number-to-3-turtles