| 08-17-2006, 12:57 AM | #1 |
Is there a function (or could someone make one) that takes a location and returns the nearest unit to that location Thanks |
| 08-17-2006, 01:04 AM | #2 |
Try wc3jass.com. Probably something there. |
| 08-17-2006, 02:56 AM | #3 |
It is easy to make one anyways JASS:// x,y : point // tries : max dist checked would be 2^(tries+8) // filter : (can use null, simply a filter man.) // function getclosest unit takes real x, real y, boolexpr filter, integer tries returns unit local unit p local unit c=null local real min local group g=CreateGroup() local real d=128. local real e local real f loop exitwhen (tries==0) or (c!=null) call GroupEnumUnitsInRange(g,x,y,d,filter) loop set p=FirstOfGroup(g) exitwhen p==null set e=x-GetUnitX(p) set f=y-GetUnitY(p) set e=e*e+ f*f if (c==null) or (min>e) then set c=p set min=e endif call GroupRemoveUnit(g,p) endloop set d=d*2. set tries=tries-1 endloop call DestroyGroup(g) set g=null if (c!=null) then set tries=H2I(c) set c=null return tries endif return null endfunction |
| 08-17-2006, 03:59 AM | #4 |
as written, max distance checked is 2^(tries+6), not +8 Easy to refactor as a max distance condition. Top of the loop: If distance > maxdistance, set distance = maxdistance. Bottom of the loop: exitwhen distance >= maxdistance. Use integers instead of reals for dist/maxdist though or add a tolerance to the comparison. |
| 08-17-2006, 04:34 AM | #5 | |
typo , I didn't want to add an if then else to the loop, it is not needed to actually have the max dist value there anyways, cause that argument is mostly to limit the number of tries, not really for distances. Quote:
Why? |
| 08-17-2006, 04:55 AM | #6 |
Thanks a lot vex, you should propably include this in the next version of your caster system since I have been using it for many spells Pipedream, There is no need to convert the integers to real just to make a max distance condition, the function is fine the way it is. |
| 08-17-2006, 05:34 AM | #7 |
Giving the user a number of "tries" is leaking abstraction like a sieve. Distance is a useful alternative, but often you don't want to deal with figuring out the map size, so two versions would be wanted in a good library. There are two reasons to use integers instead of reals. In Vex's version you've got real subtraction between a quantity that came from the map grid(Unit x/y) and a quantity that did not (x,y arguments). So you're going to run into the real subtraction bugs if your x,y is for example something random. In the max distance version, which I understand is not the function you're looking for, you need to compare two reals for equality. This is bad news, you have to make it with a tolerance. It's much easier to use integers instead. You only need to use an integer for distance/maxdistance, you can leave the coordinates as reals, although it would be better to use integers for all since that will also take care of the subtraction difficulty. Unfortunately it will only work for maps up to 256x256. So to write an absolutely safe function you need to use x,y integers for the first iteration and reals for the rest! Quite a mess. --- For the non distance version, you would do well to encode the map size into the function. Perhaps scale up until r is half of one of the map widths, then enum through all units. This will net you a cleaner interface at the cost of complexity. |
| 08-17-2006, 12:49 PM | #8 |
could you please explain me the real substraction bug?, tolerance would be needed if comparing == with reals, but this function does not do that. Also if you would really want a max distance argument: JASS:// x,y : point // tries : max dist checked would be 2^(tries+8) // filter : (can use null, simply a filter man.) // function getclosest unit takes real x, real y, boolexpr filter, real max returns unit local unit p local unit c=null local real min local group g=CreateGroup() local real d=max/8. local real e local real f set max=max+1. loop exitwhen (d>=max) or (c!=null) call GroupEnumUnitsInRange(g,x,y,d,filter) loop set p=FirstOfGroup(g) exitwhen p==null set e=x-GetUnitX(p) set f=y-GetUnitY(p) set e=e*e+ f*f if (c==null) or (min>e) then set c=p set min=e endif call GroupRemoveUnit(g,p) endloop set d=d*2. set tries=tries-1 endloop call DestroyGroup(g) set g=null if (c!=null) then set tries=H2I(c) set c=null return tries endif return null endfunction |
| 08-17-2006, 02:10 PM | #9 |
real subtraction bug: subtracting two very close real numbers ( a few bits of mantissa off ) becomes the closest garbage you can get to infinity. So, in your first iteration if you have a point that happens to be very very close to but not exactly the position of the unit, something undefined will happen. Likely ways this could happen is evolving a diff eq or computing something that should be the same two different ways. No real comparison in your version: Indeed, that's why I say "max distance version". --- exitwhenning before reaching max and doing a final exactly max distance iteration outside the loop would run the same number of bytecodes and work non-surprisingly. |
| 08-17-2006, 04:55 PM | #10 |
I was going to try to reproduce it but I guess you can give me code that makes it happen? |
| 08-17-2006, 04:57 PM | #11 |
I think 0.0-0.0 makes it happen. |
| 08-17-2006, 09:38 PM | #12 |
| 08-17-2006, 11:18 PM | #13 |
all right, darn darn bug. First of all I've been using real substraction for ages by now, specially when calculating distances, and never ran into issues, this bug seems to happen when just one bit differs, so I guess it could only happen if both reals are from different sources. Dilema * If I leave things with no change, there will be a chance for this to come and ruin everything. * If I decide to fix this I would have to use (a*1024.-b*1024.)/1024. which is kind of lame. * If I choose for code without real product/division I would need the duh functions: JASS:function Duh takes real d returns real if (d>1.) or (d<1.) or (d==1.) then return d endif return 0. endfunction then use Duh(a-b), but if I do so I would add a function call to every single situation that actually needs speed... * I could replace everything with integers, but every single native already returns everything in real so we would have to use valueable time in conversions. |
| 08-17-2006, 11:45 PM | #14 | |
Quote:
I don't see what use "Duh" would be. I haven't seen it produce Inf/Nan, always something big but not Inf/Nan by a few bits. |
| 08-18-2006, 03:03 AM | #15 |
Actually, the produced thing has the weird property of not being equal to 1. nor lower than 1 nor greater than 1.0 so that way if I find that crazy real I can recognize it, so it is mostly like an exception handling that returns 0. if it finds the underflow. |
