following my previous post, I would like to ask the reason why a variable is being initialised when I try to update its value. I am trying to find a way to fix this issue.
What I am wishing to do is updating the variable's original value by adding a small random quantity q = random-float 0.1, only when I add this-item to the neighbours' lists.
My expected output would be:
(object 16) with original attribute 0.147 neigh: 0 (object 16)
with updated attribute 0.167 with random-float 0.02
i.e. without initialising the original value:
(object 16) with original attribute 0.147 neigh: 0 (object 16)
with updated attribute 0.02 with random-float 0.02
The latter is my current output, and this is wrong.
I do not know how to fix this issue within my code. I am still trying to understand what is going wrong, but I have not found yet a way to fix it, so I hope you can help me to understand more.
My code is the following:
if breed = breed1 [
set selected people
hatch-items 1 [
hide-turtle
set chosen selected
set attribute1 random-float 1
set attribute2 attribute1
set this-item self
print (word " attribute1 " attribute1 " attribute2 " attribute2)
ask myself [
set my-list fput this-item my-list
] ;; close ask myself
] ;; close hatch
; ADD NEW ITEM TO NEIGHBOURS' LISTS ;
print (word " Before updating value, attribute1 " attribute1 " attribute2 " attribute2)
ask link-neighbors with [breed = breed1] [
let q random-float 0.1
set attribute1 (attribute1 + q)
print (word " After updating value, attribute1 " attribute1 " attribute2 " attribute2 " q " q)
] ;; close ask link-neighbors
] ;; close if
I put some print function to see the outputs:
the first print returns me attribute1 0.85 and attribute2 0.85
print (word " attribute1 " attribute1 " attribute2 " attribute2)
the second output returns me attribute1 0 and attribute2 0
print (word " Before updating value, attribute1 " attribute1 " attribute2 " attribute2)
the third output returns me attribute1 0 attribute2 0 and q 0.08
print (word " After updating value, attribute1 " attribute1 " attribute2 " attribute2 " q " q)
What is happening is that attribute1 is initialised within the ask link-neighbors, so I am adding the quantity q to 0, and not to the original value of attribute, defined in the hatch.
Could you please help me to update it, without initialising the value?
Many thanks
Nothing is being initialized. Your problem is that you have two different scopes.
The variable "attribute1" that you set within the hatch block belongs to the hatched agent. The variables of the same name "attribute1" in your "ask link-neighbors" block belong to the link-neighbors.
So your ask link-neighbors statement
set attribute1 (attribute1 + q)
is asking each link-neighbor to set its own "attribute1" to its own attribute1 plus q. What you want instead is to ask each link neighbor to set its own attribute1 to the recently-hatched agent's variable "attribute1" plus q.
If we had dot notation, which we don't, you'd want something like
set neigbhor.attribute1 ( hatched_agent.attribute1 + q )
Since your ask link-neighbor code is outside the scope of the hatched agent, there's no way to use something like "self" or "myself" to point to the right variable of that name.
One way around this problem would be to define a new global variable, maybe call it "passed-ball"
globals [ passed-ball ]
Then inside the hatch block you could
set passed-ball attribute1
And then in your ask link-neighbors block of code, you could say
set attribute1 (passed-ball + q)
Alternatively,instead of making this passed-ball totally global, which violates the guidelines of using as few global variables as possible, you could use another method to persist the value you want between the hatch block and the ask link-neighbors block: "passed-ball" could be an variable owned by the agent that is the one referred to at the very top of the code you posted, about which you are asking whether breed = breed1.
I think that both the hatch code and the ask-link-neighbors code could see and implicitly refer to a variable called "passed ball" that was owned by this high-level agent. Just don't name it "attribute1" yet again or there would then be three different "attribute1" meanings floating around and it would be even more likely that you or some later person modifying the code would make some error and refer implicitly to the wrong one.
Related
I am trying to write a procedure where a turtle of a certain breed asks turtles of the same breed, within a certain distance, the value of a certain variable. The asking turtle will then capture the values add them to it's own, map + them and then reduce + to a single number. Here's the code
ask Teams
[ if AsgnE = "E 1"
[
ask Teams with [ distance myself < 25]
[
; assuming that there are no more then 2 teams within distance
let Val1 []
let Val2 []
let Val3 []
set Val1 Value
set Val2 Value
set Val3 [Value] of self
let Val4 (map + Val1 Val2 Val3)
set Val4 (reduce + Val4)
set Storys1 [Stories] of Epic 0
if Storys1 > 0 [ set TotValue1 Val4 ]
]
]
]
The values of each Team continuously update as long as the go button is pressed. The issue is that the resulting number never matches the aggregate of all the values. As the number updates they never match the totals of the separate Teams. Sometimes the number drops to a lower number (I'm assuming it's representing a single teams value) before jumping back to a higher number.
Any idea on how to fix this?
Thanks
Rudy
My guess is that it's a synchronicity problem. The ask will iterate (in random order) through all the turtles. Let's say it starts with turtle 1 - so turtle 1 updates its value to be the sum of its old value and all the values of the nearby turtles. Then the ask moves on to turtle 2, and turtle 2 happens to be nearby to turtle 1. That means turtle 2 adds all the numbers again, with turtle 1 having its adjusted value. With just these two turtles, the value for turtle 2 gets added in twice because turtle 1 also has it hidden in its new value.
If this is not the behaviour you want, the easiest thing to do is to have an extra variable called something like next-value. Calculate next-value for each turtle as the appropriate sum. Then, in a new ask, get each turtle to set value next-value to update them all at the same time.
Also, your map and reduce seems unnecessarily complicated. If what you are trying to achieve is to add the value of a variable over a bunch of turtles, then you can simply do a sum of the variable after constructing the relevant turtle agentset. But it may be that you simplified for the purposes of the question, in which case just ignore this!
UPDATE ---- added complete model example
turtles-own
[ team
myval
nextval
]
to setup
clear-all
create-turtles 20
[ setxy random-xcor random-ycor
set team one-of ["A" "B"]
set myval 1
]
reset-ticks
end
to go
ask turtles
[ let myteam turtles with [team = [team] of myself]
set nextval sum [myval] of myteam
]
type "total before: " print sum [myval] of turtles
ask turtles
[ set myval nextval
]
type "total after: " print sum [myval] of turtles
end
I have a list made up by two turtles (for simplicity, houses and landlords).
Thanks to some suggestions that were provided me here, I selected the house with maximum price from the list, but unfortunately the landlord is not the owner of that house, but only the turtle selected one tick before.
I understood that something is going wrong with the definition of this turtle.
What I wrote, after the suggestions, is:
let selected_house max-one-of turtle-set my-list [price]
let selected_landlord [my-landlord] of selected_house
print (word "Landlord" [selected_landlord] of selected_house)
let new_list (list selected_house selected_landlord)
print (word "Landlord " selected_landlord "of house: " selected_house " by price: " [price] of selected_house)
but if, let's say, I have:
List:
"Landlord 2 is the owner of house 4 by price 400000"
"Landlord 5 is the owner of house 1 by price 100000"
"Landlord 4 is the owner of house 3 by price 300000"
and then I use selected_house/landlord to select the owner of the house with highest price, I should get (house 4, landlord 2); however, I am getting (house 4, landlord 5), i.e. the landlord selected one tick before.
I defined the landlord and house as follows (I have similar exercises, but on different topics):
if breed = landlords [
hatch-houses n_house [
set price precision (random-float 1) 3
set this-house self
set this-landlord myself
ask myself [
set my-list fput (list this-house this-landlord) my-list
]
]
where this-house and this-landlord are globals and my-list is landlords' own.
Could you please help me to understand and fix the issue with this part of code?
I thought that, as I am creating the list with the first element = house and the second element = landlord, it could be possible add some condition to make the selection as easy as possible (for example, once selecting the first item, i.e. house with highest price, set the second item of each element in the list as landlord of a house).
I'm not sure why this-house and this-landlord are globals, and I think (without the full code to go on) that this may be your problem. If I understand your model, each landlord has a set of houses, and you want to be able to find the most expensive house and the landlord that owns it. If each house keeps track of its landlord and price, and each landlord keeps track of their houses, then that should allow you to link any house to its landlord, or to look at all the houses that a landlord owns.
The following model perhaps will give you one idea of how to proceed. It creates landlords, each of which then creates houses with a random price. It then finds the most expensive house and its landlord. Then for each landlord, it finds that landlord's most expensive house. The landlord could keep a list of houses with [house landlord], but the second item would be the same for all the landlord's houses.
breed [landlords landlord]
breed [houses house]
landlords-own [my-houses my-house-list]
houses-own [price my-landlord]
to test
clear-all
create-landlords 10
ask landlords [
hatch-houses 5 [
set price precision (random-float 1) 3
set my-landlord myself
]
set my-houses houses with [my-landlord = myself]
]
let most-expensive max-one-of houses [price]
show (word "The mostexpensive house is house " most-expensive " owned by " [my-landlord] of most-expensive " with price =" [price] of most-expensive)
ask landlords [
let my-most-expensive max-one-of my-houses [price]
show (word "landlord " self "'s most expensive house is house " most-expensive " with price =" [price] of my-most-expensive)
]
end
On the other hand, you could keep a list of all houses across all landlords as a global, and if you run list-houses after test, you will get such a list, which you can then sort by price, landlord, or whatever.
globals [house-list]
to list-houses
set house-list []
ask houses [
set house-list fput (list self my-landlord price) house-list
]
show house-list
let sorted-by-price sort-by [[a b] -> item 2 a > item 2 b] house-list
let most-expensive first sorted-by-price
show (word "the most expensive house is house " item 0 most-expensive " with owner " item 1 most-expensive " and price " item 2 most-expensive)
end
I currently have one agentset(breed1) hatching another agentset(breed2). What I would like is to edit the breed2 (attribute1 and attribute2), then add the edited item (called item in the hatch) to the lists of the breed1's neighbours.
EDITED:
Working on the code after Wade Schuette's answer, I wrote the following
breed [people person]
breed [items item_1]
people-own
[
my-list
attribute1
attribute2
]
items-own
[
selected
attribute1
attribute2
]
to setup
clear-all
;; make turtles to test
create-people 1 [ set my-list [1 2 3 ] ]
create-people 1 [ set my-list [ ] ]
create-people 1 [ set my-list [22 33 ] ]
create-people 1 [ set my-list ["a" "b" "c"] ]
create-people 1 [ set my-list [3 4 5 ] ]
;; make a network
ask people [ create-links-with other people ]
reset-ticks
end
to go
let picked nobody
let neighbours nobody
ask one-of people
[
set attribute1 random-float 1
set attribute2 random-float 1
hatch-items 1 [
set selected picked
let this-item self
ask myself[
print (word "turtle " self " has item " this-item " with attribute1 " attribute1 "and attribute2 " attribute2)
set my-list lput this-item my-list
show my-list
]
ask link-neighbors [ print (word "Person " who " has this my-list " my-list)
set attribute1 (attribute1 + random-float 1)
set attribute2 (attribute2 + 3)
set my-list lput this-item my-list
print (word "added item " this-item " with attribute1 " attribute1 " with attribute2 " attribute2)
show my-list
]
]
]
tick
end
As you can see, my difficulties are in considering the turtle's neighbours and in updating the information (attribute1 and 2) of the item that I want to add in their lists.
You only need to make two changes to get your code to work.
Move the close-bracket ( ] ) for the hatch statements up BEFORE you try to ask for link-neighbors. Right now, you're asking for link-neighbors for the hatched agent, not the one that called it, so it finds none and fails silently.
If you do that, you get an error about this-item being undefined. That's because you declared it inside hatch code, so it goes away when hatch code closes. To fix that, declare this-item just before you call the hatch code ( let this-item "") works fine, but be sure to use LET not SET.
Then later, when updating linked neighbors, you only need to SET it, because you've already declared it.
I think with those changes it will work. Here's what I got to work. I put it many debugging xprint statements and set global verbose? to true to activate them, as I mentioned earlier. Doing all these print statements revealed the problem where link-neighbors suddenly appeared to disappear -- that's how I located the bug.
Set global verbose? to false in setup to deactivate them and get clean output.
globals [
verbose? ;; to turn on debugging statements
]
breed [people person]
breed [items item_1]
people-own
[
my-list
attribute1
attribute2
]
items-own
[
selected
attribute1
attribute2
]
to setup
clear-all
set verbose? true ;; true means printa lot of stuff
;; make turtles to test
create-people 1 [ set my-list [1 2 3 ] ]
create-people 1 [ set my-list [ ] ]
create-people 1 [ set my-list [22 33 ] ]
create-people 1 [ set my-list ["a" "b" "c"] ]
create-people 1 [ set my-list [3 4 5 ] ]
;; make a network
ask people [ create-links-with other people ]
;; ADDED next 2 lines
xprint (word "Created this many links in setup: " count links)
ask person 0 [
let fastcount count link-neighbors
xprint ( word "In setup, person " who " has this many links " fastcount )
]
reset-ticks
end
to go
let picked nobody
let neighbours nobody
ask one-of people with [ who = 0 ]
[
let fastcount count link-neighbors
xprint ( word "Entering ask-person, person " who " has this many links " fastcount )
set attribute1 random-float 1
set attribute2 random-float 1
xprint ( word "Before hatch-items, we have this...")
xprint (word "turtle " self " has no item hatched, "
" with attribute1 " precision attribute1 2 " and attribute2 " precision attribute2 2)
let this-item 0 ;; this was down inside hatch-items, so it evaporated when
;; finishing hatch-items, causing a problem
;; DECLARE it up here, then SET it inside hatch-items
hatch-items 1 [
set selected picked
set this-item self ;; this was down here inside hatch-items, move it up 4 lines
xprint ( word "confirming this-item value is: " this-item )
ask myself[
xprint ( word "inside hatch-items , inside ask-myself, we have this...")
xprint (word "turtle " self " has item " this-item
" with attribute1 " precision attribute1 2 " and attribute2 " precision attribute2 2)
set my-list lput this-item my-list
xprint ( word "hatched item now has my-list = " my-list )
] ;; end of ask myself
];;; <====== you want to close context of hatch-items up here, not down below
;;; so that ask link-neighbors will work
;; ADDED THIS NEXT LINES FOR DEBUGGING
xprint "we are done with ask myself, but still inside hatch-items"
set fastcount count link-neighbors
xprint ( word "After ask myself, but still inside hatch-items, person " who " has this many links " fastcount )
xprint ( " the code posted in the revised question failed here")
xprint ( " PERSON should be person 0 , link count should be 4 ")
xprint ( " SO ASK LINK-NEIGHBORS WIll fail !!!")
xprint " asking link-neighbors to update their lists now"
ask link-neighbors [ print (word "Person " who " has this my-list " my-list)
set attribute1 (attribute1 + random-float 1)
set attribute2 (attribute2 + 3)
set my-list lput this-item my-list
xprint (word "added item " this-item " with attribute1 " attribute1 " with attribute2 " attribute2)
show my-list
]
;;] ;; closes context of hatch-items, try closing hatch-items before asking link-neighbors
]
tick
end
to xprint [ stuff ]
if verbose? [ print stuff ]
end
Minor typo: one of your methods uses in-link-neighbors and one uses link-neighbors. Unless you want to exclude outbound links, I think you want link-neighbors.
Basically, one design question you are asking is whether it's better to find the set of the caller's link-neighbors before hatching and save that in an attribute, or to find them locally at the time of hatching and forget the list after hatching. I haven't tried your code, but I think both methods would work. If the set of links is static, you could find it once, store it, and not bother finding it again every time you hatch a new agent, and save some time. If the set of links is dynamic, you need to look it up every time anyway, so there is no point in saving it in an attribute.
You ask how to validate the code. I have no idea what either of your suggestions mean so I'll answer the general case. These are probably steps that you could do, and should do, before posting here, to fix all that you can fix by yourself.
Rule #1: Start simple, and get that much working before adding complexity.
Your code already violates Rule #1. You set two attributes when you could be testing with only one. What if the second attribute code causes an error that confuses your checking that the overall logic is working. For that matter, start testing with zero attributes. Comment out that code and add it back in gradually, checking again at each step.
Rule #2: Take small steps.
Confirm that the code works with only one agent before adding more agents. Make one pass of the "go" step and stop to test. Get that much perfect before moving on to a second step. Etc.
We can all dream of the day when NetLogo has a real debugger that lets you step through the code one statement at a time, or set break-points. But it doesn't. By the time the go step is over and a "stop" takes effect, you've lost context. Local variables have evaporated and can't be checked. The "stack" of nested calls is lost.
The only way I know of to see the dynamic details in context is to either set new global variables, which is messy, or make heavy use of embedded "print" statements.
You could also insert an error statement to cause a run-time error, examine the calling stack, and have a chance to take a breath and look at the output at that point.
error " here is the calling stack, halting execution entirely here."
Or, you can use a user-message statement to cause the code to pause to let you know that something has changed, or that a condition that never should occur (!) has now occurred. This gives you the nice options of "halt" or continuing to run as if nothing happened.
if x > 5 [ user-message " Alert -- X is over 5!! " ]
Other reviewers, chime in here and share other ways to do this!
The most useful print statements I've found label several variables of interest and identify where they are executed so you can tell them apart in the output. Example for looking at 3 variables x,y, and z:
print ( word "In step 3, x = " x " y = " y " z = " z )"
It would be great if there was a way to toggle visibility of these statements in the editor, but there isn't. You can at least toggle whether the statement runs or is skipped by adding a global variable, say "verbose?" and changing the print statements to take advantage of it. ( see below )
Then you can turn on or turn off printing all of these statements at once, as opposed to commenting them out, or worse, deleting them. In general, don't delete them, because someday you will need to modify and re-validate the code, and you'll need these back again to confirm that the modifications are doing what you want them to do and didn't break something new. Good "print" statements are worth their weight in gold and worth effort to get in place.
Here's a nice way to have selective printing. Declare a new command called "xprint" that only prints when the global variable "verbose?" is true. You can set it once in setup, or modify in go mid-stream, or set verbose? true or false in the Command Center you step through code.
Then you can use "xprint" instead of "print" where you want to be able to toggle printing or no printing.
xprint ( word "In step 3, x = " x " y = " y " z = " z )"
That really lowers the cost of having lots of print statements in your code, so it really simplifies the process of verifying code and re-verifying it later.
;; This shows how to use a global variable to turn on or off print statements,
;; which you might want to use while developing and testing code
globals [
verbose? ;; true means print lots of things, false means don't print them
]
to setup
clear-all
set verbose? true ;; or false, whatever. You can also use the Command Center
;; to set this true or false in the middle of a run
reset-ticks
end
to go
let x random 10 ;; just for illustrating how this works
xprint (word "At tick " ticks " x = " x )
tick
end
to xprint [ stuff ]
if verbose? [ print stuff ]
end
You said in a comment to the first answer:
The code works, but I have not been able to print all the neighbours
of the selected turtle and see if the item was added or not to their
lists. .... However, my difficulties are in
considering and defining the neighbours of the turtle (myself).
Can you explain what difficulties you are having? Can we pick an easier example to work with? Is the problem you are having with what agent is meant by the word "myself" and "self" depending on how deeply you are nested in ask-whoever calls?
Here's some easier code to start from. Can you create the problem with this code?
By the way, if you are an ask loop within another ask loop, the keyword "myself" will be defined and you can use
print (word "At point 3, self = " self ", and myself = " myself)
to see who is who. I don't know how to test whether "myself" exists, since if it doesn't this throws an error -- testing = nobody doesn't work and is-agent? doesn't work if myself doesn't exist. Anyone? How can you tell if myself exists?
Anyway it doesn't matter. Here's a workaround. Just wait until after the hatch section is completed when you are back in the first agent's context, and you can use
ask link-neighbors [ print (word "turtle " who " has this my-list " my-list) ]
and it should work!
turtles-own
[
my-list
]
to setup
clear-all
;; make turtles to test
create-turtles 1 [ set my-list [1 2 3 ] ]
create-turtles 1 [ set my-list [ ] ]
create-turtles 1 [ set my-list [22 33 ] ]
create-turtles 1 [ set my-list ["a" "b" "c"] ]
create-turtles 1 [ set my-list [3 4 5 ] ]
;; make a network
ask turtles [ create-links-with other turtles ]
reset-ticks
end
to go
ask one-of turtles
[
ask link-neighbors [ print (word "turtle " who " has this my-list " my-list) ]
]
tick
end
I am working on a model where turtles can exchange objects, like a virus, disease or just a ball.
After selected randomly one turtle, this turtle created an object as follows
create-object 1[ hide-turtle set new_object self set chosen? false]
set selected one-of breed1
ask selected [
set attribute random-float 1
set my-list fput attribute my-list
]
to put into a list shared between the turtle and its neighbourhood.
Now, what I would like is to consider another option for the same turtle, i.e. to choose one of the (old) items collected in its list based on the items' attribute: the higher the value, the more likely it is to be chosen.
ask one-of breed1
let selected-objects objects with [not chosen?]
let choice rnd:weighted-one-of selected-objects [attribute]
ask choice [set chosen? true]
set my-list fput choice my-list
]
where
globals [
chosen?
new_object ; in alternative to (list attribute in my-list)
]
breed[breed1 breed_1]
breed[objects object]
breed1-own [
my-list
my-list?
attribute
choice
]
My doubts are:
how can I keep this object in 'memory'/in list with its attribute?
I would need to keep in memory as the turtles (breed1) can exchange/spread the object/virus through time, but potentially this object can change its attribute's value.
would it be better to add to the list the object and/or its attribute?
if I wanted to change its value, after selected, how could I do?
Thank you for your time
OK, so you asked
(1) how can I keep this object in 'memory'/in list with its attribute?
I would need to keep in memory as the turtles (breed1) can
exchange/spread the object/virus through time, but potentially this
object can change its attribute's value.
Once you create them, the objects will persist until you kill them. This means that the attribute that each object owns will also persist without any effort on your part.
Looking at your code, you could keep track of which object is chosen by setting the global variable "new_object" to be the who number of the object you chose. .
The object with the given who number can have its attribute changed by anyone, anytime and all the other agents will be able to see that new value.
You also ask:
(2) would it be better to add to the list the object and/or its
attribute?
I would answer, don't put either the object or the attribute of the object on the my-list. Put the who number on the my-list. From the who number you can find the object with that who number, and from the object you can find the attribute.
OK, so if you do that, can you sort the list by attribute? Yes, you can do that with some clever code. The key line is the one sorting the list by the attribute of the objects which have their who numbers in the list my-list.
let temp2-list sort-on [ attribute ] objects with [ member? who [my-list] of myself ]
I think the answer to your third question should be clear now.
if I wanted to change its value, after selected, how could I do?
Here's working code that should help explain this answer. Setup generates one
agent and 6 objects and makes up a random my-list and a corresponding list of
attributes. Go generates sorted lists of objects and attributes. The object
in the list with the highest attribute is identified.
Note that objects-own [attribute]. You didn't mention that.
The example code is heavily documented in-line.
globals [
chosen_object_who
acting_breed1_who
]
breed[breed1 breed_1]
breed[objects object]
objects-own
[ attribute ]
breed1-own [
my-list ;; list of who numbers of objects, initialize to [] or it may fail
attr-list ;; list of attributes of the my-list objects, in the same order
attribute-of-chosen-object
who-of-chosen-object
my-list? ;; unknown
]
to setup
clear-all
print "creating 5 objects"
create-objects 5 [ set attribute random 100
print (word "created object " who " with attribute " attribute )
]
create-breed1 1 [
set my-list []
set attr-list []
set my-list? false
set attribute-of-chosen-object -1
set who-of-chosen-object -1
]
ask one-of breed1 [
set acting_breed1_who who
;; add six random object to my-list then remove duplicates
repeat 6 [
set my-list fput [who] of one-of objects my-list
]
set my-list remove-duplicates my-list
;; create the list of corresponding attributes
set attr-list map [i -> [attribute] of object i ] my-list
print (word "at end of setup, here's the my-list: " my-list )
print (word "here's the corresponding attr-list : " attr-list )
print ""
]
reset-ticks
end
to go
ask one-of breed1 [ ;; there is only one for this example
;; here's the magic command line
let temp2-list sort-on [ attribute ] objects with [ member? who [my-list] of myself ]
;; print (word "temp2-list: " temp2-list)
;; yields a list like [(object 3) (object 1) (object 4) (object 2) (object 0)]
;; it looks like an agent set but it's actually a list of objects in my-list,
;; but sorted into order by ascending attributes.
;; generate the new my-list, in the new order
set my-list map [i -> [who] of i ] temp2-list
set attr-list map [i -> [attribute] of i ] temp2-list
print "=========== after sort ====================="
print (word "sorted my-list now is " my-list)
print (word "matching attr-list is " attr-list )
print ""
;; You can select the best choice as the last item in the list, giving you the
;; who number of the object which has the highest attribute value
let best-choice 999
if-else length my-list > 0
[ set best-choice last my-list ]
[ error " my-list is empty! "]
;; saved as a global
set chosen_object_who best-choice
;; also save variables in the breed1 we are looking at now
set attribute-of-chosen-object last attr-list
set who-of-chosen-object last my-list
print (word "Assuming we want the object with the highest attribute")
print ""
print (word " The best choice object-who is " best-choice )
print (word " the attribute of that choice is " last attr-list )
print " "
print " all set to do something with the chosen object "
print " the choice is known both locally and globally "
inspect self
]
tick
end
Is there any alternative to read-from-string that works in NetLogoWeb? I need to a string from an input field. The string contains some number of integers and should be converted to a list. Within NetLogo, I use this code:
to-report get-demand
report reverse sort read-from-string ( word "[" the-field-name "]")
end
However, it seems that read-from-string is not implemented yet in NetLogoWeb. Any way around?
Many thanks and best wishes,
Michal
P.S. Many thanks for developping NetLogoWeb. I really missed NetLogo plugins.
Unfortunately, we haven't yet added support for read-from-string to NetLogo Web. It probably won't be there in the near future, either.
Is the code supplied here the real code that's giving you problems? I assume that it isn't, but, if it is, you can just do this for the same effect:
to-report get-demand
report reverse sort (list the-field-name)
end
(That is, if the-field-name is what it sounds like, which would be a string containing only the name of some "field".)
I assume that your real case is more complex. I might be able to offer a better workaround if I saw the true code. Are you sure that you can't solve your problem with tasks?
I'd suggest:
to-report string-to-numbers [s]
if empty? s [ report [] ]
if first s = " " [ report string-to-numbers butfirst s ]
let pos position " " s
ifelse not is-number? pos
[ report (list string-to-number s) ]
[ report fput string-to-number substring s 0 pos
string-to-numbers substring s (pos + 1) length s ]
end
to-report string-to-number [s]
report reduce [10 * ?1 + ?2]
map [position ? "0123456789"]
explode s
end
to-report explode [s]
report map [item ? s] n-values (length s) [?]
end
Sample run:
observer> show string-to-numbers "12 345 67"
observer: [12 345 67]
I verified that this works in both desktop NetLogo and NetLogo Web.
Based on the previous answer (that the command will not be implemented soon), it seems the only solution is to implement a simple parser, i.e. something like this (works for integers separated by spaces):
to-report string-to-list [ s ]
let l []
let ss ""
let n 0
let mode "out"
repeat length s [
set ss first s
set s but-first s
if ( ( ss = " ") and ( mode = "in" ) ) [
set mode "out"
set l lput n l
set n 0
]
if ( member? ss "0123456789") [
set mode "in"
set n ( n * 10 ) + ( position ss "0123456789" )
]
]
if ( mode = "in" ) [ set l lput n l ]
report l
end
The reporter gets a string s and returns a list of integers.
Or is there any simpler way to implement it?
Just to have an up-to-date answer here, as of October 2017, NetLogo Web does support read-from-string. A case like read-from-string (word "[" the-field-name "]") should work just as in desktop and report the list value.