I first misread the question and thought it was a matter of finding the midpoint between only two turtles, so I suggested this:
to setup
clear-all
resize-world -25 25 -25 25
create-turtles 2
ask turtle 0 [ setxy 0 -25 ]
ask turtle 1 [ setxy 0 23 ]
show midpoint turtle 0 turtle 1
end
to-report midpoint [ t1 t2 ]
let result (list)
ask t1 [
hatch 1 [
face t2
forward distance t2 / 2
set result list xcor ycor
die
]
]
report result
end
Provided world wrapping is turned on, running setup will print [0 24.5]
.
But Arthur pointed out that what he actually wanted was to find the midpoint for a whole set of turtles (i.e., a centroid). After a some thinking, I realized I could apply a very similar method:
- Create one temporary turtle for each one in the original set (I call them
points
);
- Make the first one of those a "
seeker
" turtle that will move around until it finds the centroid.
- Have the seeker move half-way to the first of the other points, then a third of the way to the second one, then a fourth of the way to the third one, etc., until there are no more points left.
Aside from intuition, I have no mathematical proof that this works, but when world wrapping is turned off, it does give the same result as the "mean coordinates" method, so I assume it also works with wrapping on. It also works for the [0 24.5]
case. I'd be happy to get corrected if I'm mistaken, though.
Here it is:
to setup
clear-all
ask n-of (2 + random 10) patches [ sprout 1 ]
; Show centroid with the "seeker" method
show centroid turtles
; Show centroid calculated with mean coordinates for comparison.
; If wrapping is on, it will probably be different from
; `centroid turtles`. If wrapping is off, it should be the
; same, with very small floating point variations:
show list mean [xcor] of turtles mean [ycor] of turtles
end
to-report centroid [ set-of-turtles ]
let points (list)
ask set-of-turtles [
hatch 1 [ set points lput self points ]
]
report seek-centroid first points but-first points 2
end
to-report seek-centroid [ seeker points n ]
if-else not empty? points [
let target first points
ask seeker [
face target
forward distance target / n
]
ask target [ die ]
report seek-centroid seeker but-first points (n + 1)
]
[
let result [ list xcor ycor ] of seeker
ask seeker [ die ]
report result
]
end
Note: adding ask first points [ pen-down ]
before calling report seek-centroid ...
is a fun way to get a feel for how the algorithm works.